feat: improve oscillator initialization values and LFO sync implementation with bar tracking

This commit is contained in:
Liam Kerr 2026-08-12 01:27:00 +01:00
parent d8c1c90f15
commit 062d1e074c
3 changed files with 32 additions and 28 deletions

View file

@ -4,13 +4,17 @@
Oscillator::Oscillator(float initFreq) Oscillator::Oscillator(float initFreq)
: freq_(initFreq), gain_(100.0f), waveShape_(kWaveShapeSine), : freq_(initFreq), gain_(100.0f), waveShape_(kWaveShapeSine),
sampleRate_(48000.f), phase_(0.0f), inc_(0.0f) { sampleRate_(48000.f), phase_(0.0f), inc_(0.0f)
{
recalc_(); recalc_();
}; };
void Oscillator::process(float *out, uint32_t frames) { void Oscillator::process(float *out, uint32_t frames)
for (uint32_t i = 0; i < frames; ++i) { {
switch (waveShape_) { for (uint32_t i = 0; i < frames; ++i)
{
switch (waveShape_)
{
default: default:
case kWaveShapeSine: case kWaveShapeSine:
out[i] = std::sinf(phase_ * 2.0f * M_PI) * gain_; out[i] = std::sinf(phase_ * 2.0f * M_PI) * gain_;
@ -26,17 +30,21 @@ void Oscillator::reset() { phase_ = 0; }
void Oscillator::recalc_() { inc_ = freq_ / sampleRate_; } void Oscillator::recalc_() { inc_ = freq_ / sampleRate_; }
void Oscillator::setFrequency(float newFreq) { void Oscillator::setFrequency(float newFreq)
{
freq_ = std::fmax(newFreq, 0.0f); freq_ = std::fmax(newFreq, 0.0f);
recalc_();
} }
float Oscillator::getFrequency() const { return freq_; }; float Oscillator::getFrequency() const { return freq_; };
void Oscillator::setGain(float newGain) { void Oscillator::setGain(float newGain)
{
gain_ = newGain > 0 ? newGain : 1.0f; gain_ = newGain > 0 ? newGain : 1.0f;
} }
float Oscillator::getGain() const { return gain_; }; float Oscillator::getGain() const { return gain_; };
void Oscillator::setSampleRate(float newSampleRate) { void Oscillator::setSampleRate(float newSampleRate)
{
sampleRate_ = newSampleRate > 0 ? newSampleRate : 48000.0f; sampleRate_ = newSampleRate > 0 ? newSampleRate : 48000.0f;
recalc_(); recalc_();
} }

View file

@ -15,6 +15,7 @@
#define DISTRHO_PLUGIN_WANT_PROGRAMS 0 #define DISTRHO_PLUGIN_WANT_PROGRAMS 0
#define DISTRHO_PLUGIN_WANT_STATE 0 #define DISTRHO_PLUGIN_WANT_STATE 0
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1
#define DISTRHO_PLUGIN_HAS_UI 0 #define DISTRHO_PLUGIN_HAS_UI 0
#define DISTRHO_PLUGIN_IS_SYNTH 0 #define DISTRHO_PLUGIN_IS_SYNTH 0

View file

@ -22,8 +22,8 @@ public:
}; };
SquidgeFilter() SquidgeFilter()
: Plugin(kParameterCount, 0, 0), filter_(1000.0f, 0.707f, 48000.0f), : Plugin(kParameterCount, 0, 0), filter_(440.0f, 2.0f, 48000.0f),
lfo_(4.0f) { lfo_(20.0f), lfoSync_(0.0f) {
filter_.setType(Filter::kLowPass); filter_.setType(Filter::kLowPass);
} }
@ -43,16 +43,16 @@ protected:
parameter.name = "Frequency"; parameter.name = "Frequency";
parameter.symbol = "frequency"; parameter.symbol = "frequency";
parameter.ranges.min = 20.0f; parameter.ranges.min = 20.0f;
parameter.ranges.def = 1000.0f; parameter.ranges.def = 440.0f;
parameter.ranges.max = 20000.0f; parameter.ranges.max = 10000.0f;
parameter.hints = kParameterIsAutomatable | kParameterIsLogarithmic; parameter.hints = kParameterIsAutomatable | kParameterIsLogarithmic;
break; break;
case kParamResonance: case kParamResonance:
parameter.name = "Resonance"; parameter.name = "Resonance";
parameter.symbol = "resonance"; parameter.symbol = "resonance";
parameter.ranges.min = 0.1f; parameter.ranges.min = 0.9f;
parameter.ranges.def = 0.707f; parameter.ranges.def = 2.0f;
parameter.ranges.max = 20.0f; parameter.ranges.max = 20.0f;
parameter.hints = kParameterIsAutomatable; parameter.hints = kParameterIsAutomatable;
break; break;
@ -149,31 +149,25 @@ protected:
const TimePosition &timePos = getTimePosition(); const TimePosition &timePos = getTimePosition();
float targetFreq = 4.0f; float targetFreq = 4.0f;
int syncIndex = static_cast<int>(lfoSync_);
if (syncIndex < 0)
syncIndex = 0;
if (syncIndex > 6)
syncIndex = 6;
if (timePos.bbt.valid && timePos.playing && if (timePos.bbt.valid && timePos.playing &&
timePos.bbt.beatsPerMinute > 0.0) { timePos.bbt.beatsPerMinute > 0.0) {
float bpb = static_cast<float>(timePos.bbt.beatsPerBar);
float bpm = static_cast<float>(timePos.bbt.beatsPerMinute); float bpm = static_cast<float>(timePos.bbt.beatsPerMinute);
float bar = static_cast<float>(timePos.bbt.bar);
float baseFreq = (bpm / 60.0f) * 4.0f; if (bar != currentBar_) {
lfo_.reset();
currentBar_ = bar;
}
float baseFreq = (bpm / 60.0f) / bpb;
static const float multipliers[] = {1.0f, 2.0f, 4.0f, 8.0f, static const float multipliers[] = {1.0f, 2.0f, 4.0f, 8.0f,
16.0f, 32.0f, 64.0f}; 16.0f, 32.0f, 64.0f};
targetFreq = baseFreq * multipliers[syncIndex]; targetFreq = baseFreq * multipliers[static_cast<int>(lfoSync_)];
static int lastBar = -1;
if (timePos.bbt.bar != lastBar) {
lfo_.reset();
lastBar = timePos.bbt.bar;
}
} else { } else {
targetFreq = 1.0f; targetFreq = 1.0f;
} }
@ -193,6 +187,7 @@ private:
Filter filter_; Filter filter_;
Oscillator lfo_; Oscillator lfo_;
float lfoSync_; float lfoSync_;
uint32_t currentBar_ = 0;
float lfoBuffer_[BUFFER_SIZE]; float lfoBuffer_[BUFFER_SIZE];
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeFilter); DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SquidgeFilter);