mirror of
https://codeberg.org/armin/chromaflock.git
synced 2026-09-01 04:10:47 +02:00
159 lines
5 KiB
C++
159 lines
5 KiB
C++
#pragma once
|
|
#include <cmath>
|
|
#include <algorithm>
|
|
|
|
enum class Waveform {
|
|
Sine = 0,
|
|
Saw,
|
|
Square,
|
|
Triangle,
|
|
Noise,
|
|
Pulse25,
|
|
Pulse12,
|
|
ReverseSaw,
|
|
FullRectSine,
|
|
HalfRectSine,
|
|
Stair4,
|
|
Stair8,
|
|
SoftSine,
|
|
Sinc,
|
|
ExpPulse,
|
|
DoubleSine,
|
|
SuperSaw,
|
|
NumWaveforms
|
|
};
|
|
|
|
class Oscillator {
|
|
public:
|
|
void prepare(double sampleRate) {
|
|
this->sampleRate = sampleRate;
|
|
phase = 0.0;
|
|
phaseIncrement = 0.0;
|
|
for (int i = 0; i < numSuperSaws; ++i)
|
|
superSawPhase[i] = i * (1.0f / static_cast<float>(numSuperSaws));
|
|
}
|
|
|
|
void setFrequency(float freq) {
|
|
frequency = freq;
|
|
if (sampleRate > 0.0)
|
|
phaseIncrement = frequency / static_cast<float>(sampleRate);
|
|
}
|
|
|
|
void setWaveform(Waveform wf) { waveform = wf; }
|
|
void setLevel(float l) { level = std::clamp(l, 0.0f, 1.0f); }
|
|
void setPan(float p) { pan = std::clamp(p, -1.0f, 1.0f); }
|
|
void setSemitone(float s) { semitoneOffset = s; }
|
|
void setFineTune(float f) { fineTune = f; }
|
|
void setPhase(float p) { phase = p; }
|
|
|
|
float getFrequency() const { return frequency; }
|
|
|
|
void process(float* leftOut, float* rightOut) {
|
|
float output = 0.0f;
|
|
|
|
switch (waveform) {
|
|
case Waveform::Sine:
|
|
output = std::sin(phase * 2.0f * pi);
|
|
break;
|
|
case Waveform::Saw:
|
|
output = 2.0f * (phase - 0.5f);
|
|
break;
|
|
case Waveform::Square:
|
|
output = (phase < 0.5f) ? 1.0f : -1.0f;
|
|
break;
|
|
case Waveform::Triangle:
|
|
output = 4.0f * std::abs(phase - 0.5f) - 1.0f;
|
|
break;
|
|
case Waveform::Noise:
|
|
output = random.nextFloat() * 2.0f - 1.0f;
|
|
break;
|
|
case Waveform::Pulse25:
|
|
output = (phase < 0.25f) ? 1.0f : -1.0f;
|
|
break;
|
|
case Waveform::Pulse12:
|
|
output = (phase < 0.12f) ? 1.0f : -1.0f;
|
|
break;
|
|
case Waveform::ReverseSaw:
|
|
output = 2.0f * phase - 1.0f;
|
|
break;
|
|
case Waveform::FullRectSine:
|
|
output = std::fabs(std::sin(phase * 2.0f * pi));
|
|
break;
|
|
case Waveform::HalfRectSine:
|
|
output = std::max(0.0f, std::sin(phase * 2.0f * pi));
|
|
break;
|
|
case Waveform::Stair4: {
|
|
float s = std::floor(phase * 4.0f);
|
|
output = -1.0f + 2.0f * ((s + 0.5f) / 4.0f);
|
|
break;
|
|
}
|
|
case Waveform::Stair8: {
|
|
float s = std::floor(phase * 8.0f);
|
|
output = -1.0f + 2.0f * ((s + 0.5f) / 8.0f);
|
|
break;
|
|
}
|
|
case Waveform::SoftSine:
|
|
output = std::tanh(3.0f * std::sin(phase * 2.0f * pi)) / std::tanh(3.0f);
|
|
break;
|
|
case Waveform::Sinc: {
|
|
float x = phase * 2.0f * pi * 6.0f;
|
|
output = (x != 0.0f) ? std::sin(x) / x : 1.0f;
|
|
break;
|
|
}
|
|
case Waveform::ExpPulse:
|
|
output = (phase < 0.5f)
|
|
? std::exp(-phase * 10.0f)
|
|
: -std::exp(-(phase - 0.5f) * 10.0f);
|
|
break;
|
|
case Waveform::DoubleSine:
|
|
output = 0.5f * std::sin(phase * 2.0f * pi)
|
|
+ 0.5f * std::sin(phase * 4.0f * pi);
|
|
break;
|
|
case Waveform::SuperSaw: {
|
|
static constexpr int numSaws = 7;
|
|
static constexpr float detunes[numSaws] = {
|
|
-12.0f, -8.0f, -4.0f, 0.0f, 4.0f, 8.0f, 12.0f
|
|
};
|
|
output = 0.0f;
|
|
for (int i = 0; i < numSaws; ++i) {
|
|
superSawPhase[i] += phaseIncrement * std::pow(2.0f, detunes[i] / 1200.0f);
|
|
if (superSawPhase[i] >= 1.0f) superSawPhase[i] -= 1.0f;
|
|
output += 2.0f * (superSawPhase[i] - 0.5f);
|
|
}
|
|
output /= static_cast<float>(numSaws);
|
|
break;
|
|
}
|
|
default:
|
|
output = 0.0f;
|
|
break;
|
|
}
|
|
|
|
phase += phaseIncrement;
|
|
if (phase >= 1.0f) phase -= 1.0f;
|
|
|
|
output *= level;
|
|
|
|
float leftGain = std::sqrt((1.0f - pan) * 0.5f);
|
|
float rightGain = std::sqrt((1.0f + pan) * 0.5f);
|
|
|
|
*leftOut += output * leftGain;
|
|
*rightOut += output * rightGain;
|
|
}
|
|
|
|
float getCurrentPhase() const { return phase; }
|
|
|
|
private:
|
|
static constexpr int numSuperSaws = 7;
|
|
static constexpr float pi = 3.14159265358979323846f;
|
|
float frequency = 440.0f;
|
|
float phase = 0.0f;
|
|
float phaseIncrement = 0.0f;
|
|
float superSawPhase[numSuperSaws] = { 0.0f };
|
|
float level = 0.7f;
|
|
float pan = 0.0f;
|
|
float semitoneOffset = 0.0f;
|
|
float fineTune = 0.0f;
|
|
double sampleRate = 44100.0;
|
|
Waveform waveform = Waveform::Saw;
|
|
juce::Random random;
|
|
};
|