chromaflock/Source/DSP/Oscillator.h
2026-07-15 23:46:38 +02:00

140 lines
4.1 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,
NumWaveforms
};
class Oscillator {
public:
void prepare(double sampleRate) {
this->sampleRate = sampleRate;
phase = 0.0;
phaseIncrement = 0.0;
}
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;
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 float pi = 3.14159265358979323846f;
float frequency = 440.0f;
float phase = 0.0f;
float phaseIncrement = 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;
};