diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index 2030b37..5690a88 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -175,23 +175,6 @@ void RMX19AudioProcessor::processMidi (juce::MidiBuffer& midi, const VParams& p) } } -void RMX19AudioProcessor::smoothGain (juce::AudioBuffer& buffer, float targetVol) -{ - const int num = buffer.getNumSamples(); - const int ch = buffer.getNumChannels(); - if (num <= 0 || ch <= 0) { volSmooth = targetVol; return; } - - const float k = 0.03f; // per-sample glide so volume doesn't step between blocks - for (int s = 0; s < num; ++s) - { - volSmooth += (targetVol - volSmooth) * k; - const float g = volSmooth; - for (int c = 0; c < ch; ++c) - *buffer.getWritePointer (c, s) *= g; - } - volSmooth = targetVol; -} - void RMX19AudioProcessor::processBlock (juce::AudioBuffer& buffer, juce::MidiBuffer& midi) { juce::ScopedNoDenormals noDenormals; @@ -266,7 +249,7 @@ void RMX19AudioProcessor::processBlock (juce::AudioBuffer& buffer, juce:: L[s] = oL; R[s] = oR; } - smoothGain (buffer, p.vol); + if (p.vol != 1.0f) buffer.applyGain (p.vol); } else if (L != nullptr) { @@ -296,7 +279,7 @@ void RMX19AudioProcessor::processBlock (juce::AudioBuffer& buffer, juce:: } for (int c = 0; c < numChannels; ++c) buffer.copyFrom (c, 0, dummy, 0, 0, numSamples); - smoothGain (buffer, p.vol); + buffer.applyGain (p.vol); } cpu = 0.7f * cpu + 0.3f * (float) (juce::Time::getMillisecondCounter() - start); diff --git a/Source/PluginProcessor.h b/Source/PluginProcessor.h index 5cf7838..8e3f6d4 100644 --- a/Source/PluginProcessor.h +++ b/Source/PluginProcessor.h @@ -45,7 +45,6 @@ int getPatchIndex() const noexcept { return patchIndex; } private: void processMidi (juce::MidiBuffer&, const VParams&); - void smoothGain (juce::AudioBuffer& buffer, float targetVol); juce::AudioProcessorValueTreeState::ParameterLayout createParams(); @@ -59,7 +58,6 @@ private: juce::uint32 lastMidi = 0; float cpu = 0.0f; float dcL = 0.0f, dcR = 0.0f, dcPrevL = 0.0f, dcPrevR = 0.0f; - float volSmooth = 1.0f; juce::AudioBuffer osBuf; // internal 2x oversample target (HQ mode) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RMX19AudioProcessor) diff --git a/Source/SynthEngine.cpp b/Source/SynthEngine.cpp index 1a0841a..5290565 100644 --- a/Source/SynthEngine.cpp +++ b/Source/SynthEngine.cpp @@ -62,25 +62,6 @@ SynthEngine::Voice* SynthEngine::acquireVoice() return &voices[stealIdx]; } -void SynthEngine::glideParams (VParams& sp, const VParams& tgt, float k) -{ - auto glide = [k] (float& cur, float tgtv) { cur += (tgtv - cur) * k; }; - glide (sp.detune, tgt.detune); - glide (sp.oscMix, tgt.oscMix); - glide (sp.fltCut, tgt.fltCut); - glide (sp.fltRes, tgt.fltRes); - glide (sp.fltEnv, tgt.fltEnv); - glide (sp.fltKey, tgt.fltKey); - glide (sp.ampA, tgt.ampA); glide (sp.ampD, tgt.ampD); - glide (sp.ampS, tgt.ampS); glide (sp.ampR, tgt.ampR); - glide (sp.fA, tgt.fA); glide (sp.fD, tgt.fD); - glide (sp.fS, tgt.fS); glide (sp.fR, tgt.fR); - glide (sp.lfoRate, tgt.lfoRate); glide (sp.lfoDepth, tgt.lfoDepth); - glide (sp.fxAmt, tgt.fxAmt); - glide (sp.vol, tgt.vol); glide (sp.pan, tgt.pan); - glide (sp.glide, tgt.glide); -} - void SynthEngine::noteOn (int midiNote, float velocity) { const float noteFreq = (float) (440.0 * std::exp2 ((midiNote - 69.0) / 12.0)); @@ -127,31 +108,18 @@ void SynthEngine::noteOff (int midiNote) void SynthEngine::render (const VParams& p, float* left, float* right, int num) { - // Parameter glide: smooth CC/automation changes that arrive between blocks. - // Without this, several MIDI CC values that fall inside one audio block are - // collapsed into a single block step, so fast knob rotation appears to skip - // intermediate values ("zipper"/stepped sound). We ramp the continuous - // parameters per-sample toward their targets instead of snapping. - if (! svValid) - { - sv = p; - svValid = true; - } - VParams sp = sv; - const float k = 0.02f; - for (auto& v : voices) { - v.amp.setRates (sp.ampA, sp.ampD, sp.ampS, sp.ampR, sr); - v.flt.setRates (sp.fA, sp.fD, sp.fS, sp.fR, sr); + v.amp.setRates (p.ampA, p.ampD, p.ampS, p.ampR, sr); + v.flt.setRates (p.fA, p.fD, p.fS, p.fR, sr); } lastGlide = p.glide; - lastPan = sp.pan; + lastPan = p.pan; polyLimit = juce::jlimit (1, maxVoice, (int) p.poly); - const float glideRate = sp.glide <= 0.001f ? 1.0f - : 1.0f - std::exp (-1.0f / (sp.glide * (float) sr)); - const float detuneRatio = std::exp2f (sp.detune / 1200.0f); + const float glideRate = p.glide <= 0.001f ? 1.0f + : 1.0f - std::exp (-1.0f / (p.glide * (float) sr)); + const float detuneRatio = std::exp2f (p.detune / 1200.0f); const float tuneRatio = std::exp2f (p.tune / 12.0f); const float maxFc = 18000.0f, minFc = 30.0f; @@ -159,20 +127,18 @@ void SynthEngine::render (const VParams& p, float* left, float* right, int num) { float mixL = 0.0f, mixR = 0.0f; - glideParams (sp, p, k); - for (auto& v : voices) { if (! v.active) continue; - if (sp.glide > 0.001f) + if (p.glide > 0.001f) v.curFreq += (v.targetFreq - v.curFreq) * glideRate; else v.curFreq = v.targetFreq; // LFO - v.lfoPh += (double) sp.lfoRate / sr; + v.lfoPh += (double) p.lfoRate / sr; while (v.lfoPh >= 1.0) { v.lfoPh -= 1.0; @@ -193,7 +159,7 @@ void SynthEngine::render (const VParams& p, float* left, float* right, int num) // frequency, vibrato, bend, tune float freq = v.curFreq * tuneRatio; if ((int) p.lfoTarget == 1) - freq *= std::exp2f (lfo * sp.lfoDepth * 1.6f / 12.0f); + freq *= std::exp2f (lfo * p.lfoDepth * 1.6f / 12.0f); if (bendSmooth != bendCents) bendSmooth += (bendCents - bendSmooth) * 0.08f; freq *= std::exp2f (bendSmooth / 1200.0f); @@ -206,17 +172,17 @@ void SynthEngine::render (const VParams& p, float* left, float* right, int num) const float o1 = osc ((int) p.osc1w, v.ph1); const float o2 = osc ((int) p.osc2w, v.ph2); - const float mixb = sp.oscMix * 0.01f; + const float mixb = p.oscMix * 0.01f; float sig = o1 * (1.0f - mixb) + o2 * mixb; const float fe = v.flt.next(); // cutoff with keytrack + filter envelope + LFO + mod wheel - float fc = sp.fltCut; - fc *= std::exp2f (sp.fltKey * 0.01f * std::log2f (freq / 261.6256f)); - fc *= std::exp2f (sp.fltEnv * 0.01f * fe * std::log2f (maxFc / fc)); + float fc = p.fltCut; + fc *= std::exp2f (p.fltKey * 0.01f * std::log2f (freq / 261.6256f)); + fc *= std::exp2f (p.fltEnv * 0.01f * fe * std::log2f (maxFc / fc)); if ((int) p.lfoTarget == 0) - fc *= std::exp2f (lfo * sp.lfoDepth * 10.0f / 12.0f); + fc *= std::exp2f (lfo * p.lfoDepth * 10.0f / 12.0f); fc *= std::exp2f (mod); fc = std::min (maxFc, std::max (minFc, fc)); v.fcSm += (fc - v.fcSm) * 0.25f; @@ -225,7 +191,7 @@ void SynthEngine::render (const VParams& p, float* left, float* right, int num) // SVF (cap f1 to keep the Chamberlin structure stable; past ~1.5 the // resonance feedback can self-oscillate and sputter at maxed cutoff+res) const float f1 = std::min (1.50f, 2.0f * std::sin (juce::MathConstants::pi * fc / (float) sr)); - const float q1 = 1.0f / (1.0f + sp.fltRes * 3.0f); + const float q1 = 1.0f / (1.0f + p.fltRes * 3.0f); v.f1c = f1; const float hp = sig - v.lp - q1 * v.bp; v.bp += f1 * hp; @@ -244,7 +210,7 @@ void SynthEngine::render (const VParams& p, float* left, float* right, int num) const float ae = v.amp.next(); float ampMod = 1.0f; if ((int) p.lfoTarget == 2) - ampMod = 1.0f - sp.lfoDepth * 0.5f * (1.0f + lfo); + ampMod = 1.0f - p.lfoDepth * 0.5f * (1.0f + lfo); v.outSmooth += (filtered - v.outSmooth) * 0.12f; float o = v.outSmooth * (ae * ampMod) * v.vel; @@ -267,7 +233,5 @@ void SynthEngine::render (const VParams& p, float* left, float* right, int num) left[s] += mixL; right[s] += mixR; - - sv = sp; } } \ No newline at end of file diff --git a/Source/SynthEngine.h b/Source/SynthEngine.h index 8c0141c..a2d54ec 100644 --- a/Source/SynthEngine.h +++ b/Source/SynthEngine.h @@ -112,8 +112,6 @@ public: int activeVoices() const noexcept { return active; } private: - void glideParams (VParams& sp, const VParams& tgt, float k); - struct Voice { bool active = false; @@ -136,8 +134,6 @@ private: int active = 0; int polyLimit = 16; float mod = 0.0f, bendCents = 0.0f, bendSmooth = 0.0f; - VParams sv; // smoothed parameter values (per-sample glide) - bool svValid = false; bool pedal = false; float lastNoteFreq = 440.0f, lastGlide = 0.0f, lastPan = 0.0f; int stealIdx = 0;