From a06266892eccf3a549807a4514b21e21b51efb83 Mon Sep 17 00:00:00 2001 From: Gordon JC Pearce Date: Tue, 7 Jan 2025 14:02:31 +0000 Subject: [PATCH] lfo, partial sub --- plugin/alphaosc.cpp | 50 +++++++++++++++++++++++++++----- plugin/alphaosc.hpp | 11 +++---- plugin/parameters.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 12 deletions(-) diff --git a/plugin/alphaosc.cpp b/plugin/alphaosc.cpp index f0b0ef8..7bb0562 100644 --- a/plugin/alphaosc.cpp +++ b/plugin/alphaosc.cpp @@ -38,7 +38,6 @@ void AlphaOsc::initAudioPort(bool input, uint32_t index, AudioPort &port) { void AlphaOsc::activate() { // calculate filter coefficients and stuff printf("called activate()\n"); - omega = (1 << 31) / sampleRate * 130; lfoOmega = (1 << 31) / sampleRate * 3.51; omega = (130 / sampleRate) * (1 << 23); } @@ -57,16 +56,23 @@ void AlphaOsc::run(const float **, float **outputs, uint32_t frames, const MidiE uint16_t i; uint32_t osc; uint8_t lfo; - float saw, sqr, sub, wave; + float saw, sqr, sub; float oct1, oct3, pwg; + float sub1, sub2; float out, in; + // steeply "logarithmic" curve similar to the Juno 106 LFO rate curve + // goes from about 0.1Hz to about 60Hz because this "feels about right" + // totally unscientific + lfoOmega = (0.1 + (pwmrate / (1 + (1 - pwmrate) * 4.75)*60)) / sampleRate * (1<<23); + omega = (130 / sampleRate) * (1 << 23); + // calculate an entire block of samples for (i = 0; i < frames; i++) { // increment phase of saw counter - // phase is a 32-bit counter because we're on a PC and we can afford to be profligate with silicon + // phase is a 24-bit counter because we're on a PC and we can afford to be profligate with silicon // the actual Alpha Juno oscillators might well have been 8-bit for reasons loosely explained in the README phase += omega; @@ -78,10 +84,10 @@ void AlphaOsc::run(const float **, float **outputs, uint32_t frames, const MidiE osc = phase >> 14; // LFO is 7-bit triangle - lfo = (lfoPhase >> 24) & 0x7f; - lfo = (lfoPhase & 0x80000000) ? lfo : 127 - lfo; + lfo = (lfoPhase >> 16) & 0x7f; + lfo = (lfoPhase & 0x00800000) ? lfo : 127 - lfo; - pw = 0; + pw = lfo * pwmdepth; // the oscillator outputs in the chip are probably digital signals // with the saw being the 8-bit outputs of the counter @@ -95,13 +101,40 @@ void AlphaOsc::run(const float **, float **outputs, uint32_t frames, const MidiE sqr = (float)(osc & 0x80) != 0; oct1 = (float)(osc & 0x40) != 0; oct3 = (float)(osc & 0x10) != 0; + sub1 = (float)(osc & 0x40) != 0; + sub2 = (float)(osc & 0x10) != 0; + + // pulse width gate // lower seven bits of the saw osc, compared with PW setting - pw = lfo*0.5; pwg = (float)((osc & 0x7f) >= pw) != 0; + + // calculate the oscillator output + + switch (submode) { + case 0: + sub = sub1; + break; // one octave down + case 1: + sub = sub1 * sqr; + break; // saw is fine, do nothing + case 2: + saw *= oct1; // pulsed + break; + case 3: + saw *= pwg; // pwm + break; + case 4: + saw *= oct3; // oct3 pulse + break; + case 5: + saw *= oct1 * oct3; // both pulse + break; + } + switch (sqrmode) { case 0: case 4: @@ -137,6 +170,9 @@ void AlphaOsc::run(const float **, float **outputs, uint32_t frames, const MidiE break; } + + + // mix the signals, probably done with some resistors in the chip in = (saw * 0.8) + (sqr * 0.63); // scaled similarly to Juno 106 diff --git a/plugin/alphaosc.hpp b/plugin/alphaosc.hpp index c1b7dfa..4960844 100644 --- a/plugin/alphaosc.hpp +++ b/plugin/alphaosc.hpp @@ -27,10 +27,11 @@ class AlphaOsc : public Plugin { enum Parameters { pSqrMode, pSawMode, - //pSubMode, + pSubMode, + pSubLevel, - //pLFORate, - //pLFODepth, + pPWMRate, + pPWMDepth, parameterCount }; @@ -59,7 +60,6 @@ class AlphaOsc : public Plugin { void deactivate() override; void run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) override; - private: double sampleRate; uint32_t omega, lfoOmega; @@ -67,9 +67,10 @@ class AlphaOsc : public Plugin { uint8_t pw; + float pwmrate, pwmdepth, sublevel; uint8_t sqrmode, sawmode, submode; - float hpfx, hpfy; + float hpfx = 0, hpfy = 0; DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AlphaOsc); }; diff --git a/plugin/parameters.cpp b/plugin/parameters.cpp index 6da3793..ac9a46f 100644 --- a/plugin/parameters.cpp +++ b/plugin/parameters.cpp @@ -74,6 +74,61 @@ void AlphaOsc::initParameter(uint32_t index, Parameter& parameter) { parameter.enumValues.values = enumValues; } break; + + case pSubMode: + // set up Sub slider + parameter.hints = kParameterIsAutomatable | kParameterIsInteger; + parameter.name = "Sub"; + parameter.symbol = "ao_sub"; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 5.0f; + parameter.ranges.def = 1.0f; + parameter.enumValues.count = 6; + parameter.enumValues.restrictedMode = true; + { + ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[6]; + enumValues[0].value = 0; + enumValues[0].label = "-1 oct"; + enumValues[1].value = 1; + enumValues[1].label = "-1 oct 25%"; + enumValues[2].value = 2; + enumValues[2].label = "-1 oct + 2 oct"; + enumValues[3].value = 3; + enumValues[3].label = "-1 oct + 3 oct"; + enumValues[3].value = 4; + enumValues[3].label = "-2 oct"; + enumValues[3].value = 5; + enumValues[3].label = "-2 oct 25%"; + parameter.enumValues.values = enumValues; + } + break; + case pSubLevel: + // set up Sub slider + parameter.hints = kParameterIsAutomatable; + parameter.name = "Sub Level"; + parameter.symbol = "ao_sublev"; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + parameter.ranges.def = 0.0f; + break; + case pPWMRate: + // set up PWM Rate slider + parameter.hints = kParameterIsAutomatable; + parameter.name = "PWM Rate"; + parameter.symbol = "ao_pwmrate"; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + parameter.ranges.def = 0.5f; + break; + case pPWMDepth: + // set up PWM Depth slider + parameter.hints = kParameterIsAutomatable; + parameter.name = "PWM Depth"; + parameter.symbol = "ao_pwmdepth"; + parameter.ranges.min = 0.0f; + parameter.ranges.max = 1.0f; + parameter.ranges.def = 0.5f; + break; } } @@ -85,6 +140,18 @@ void AlphaOsc::setParameterValue(uint32_t index, float value) { case pSawMode: sawmode = value; break; + case pSubMode: + submode = value; + break; + case pSubLevel: + sublevel = value; + break; + case pPWMDepth: + pwmdepth = value; + break; + case pPWMRate: + pwmrate = value; + break; } // we don't need to handle a default condition // if there's a parameter left unhandled, it's probably