mirror of
https://codeberg.org/armin/rmx-19.git
synced 2026-10-11 16:51:55 +02:00
Revert per-sample parameter smoothing; caused filter hiss/edginess and broke MIDI CC mapping
This commit is contained in:
parent
51a6944326
commit
43e90ca448
4 changed files with 18 additions and 77 deletions
|
|
@ -175,23 +175,6 @@ void RMX19AudioProcessor::processMidi (juce::MidiBuffer& midi, const VParams& p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RMX19AudioProcessor::smoothGain (juce::AudioBuffer<float>& 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<float>& buffer, juce::MidiBuffer& midi)
|
void RMX19AudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midi)
|
||||||
{
|
{
|
||||||
juce::ScopedNoDenormals noDenormals;
|
juce::ScopedNoDenormals noDenormals;
|
||||||
|
|
@ -266,7 +249,7 @@ void RMX19AudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::
|
||||||
L[s] = oL;
|
L[s] = oL;
|
||||||
R[s] = oR;
|
R[s] = oR;
|
||||||
}
|
}
|
||||||
smoothGain (buffer, p.vol);
|
if (p.vol != 1.0f) buffer.applyGain (p.vol);
|
||||||
}
|
}
|
||||||
else if (L != nullptr)
|
else if (L != nullptr)
|
||||||
{
|
{
|
||||||
|
|
@ -296,7 +279,7 @@ void RMX19AudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::
|
||||||
}
|
}
|
||||||
for (int c = 0; c < numChannels; ++c)
|
for (int c = 0; c < numChannels; ++c)
|
||||||
buffer.copyFrom (c, 0, dummy, 0, 0, numSamples);
|
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);
|
cpu = 0.7f * cpu + 0.3f * (float) (juce::Time::getMillisecondCounter() - start);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ int getPatchIndex() const noexcept { return patchIndex; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processMidi (juce::MidiBuffer&, const VParams&);
|
void processMidi (juce::MidiBuffer&, const VParams&);
|
||||||
void smoothGain (juce::AudioBuffer<float>& buffer, float targetVol);
|
|
||||||
|
|
||||||
juce::AudioProcessorValueTreeState::ParameterLayout createParams();
|
juce::AudioProcessorValueTreeState::ParameterLayout createParams();
|
||||||
|
|
||||||
|
|
@ -59,7 +58,6 @@ private:
|
||||||
juce::uint32 lastMidi = 0;
|
juce::uint32 lastMidi = 0;
|
||||||
float cpu = 0.0f;
|
float cpu = 0.0f;
|
||||||
float dcL = 0.0f, dcR = 0.0f, dcPrevL = 0.0f, dcPrevR = 0.0f;
|
float dcL = 0.0f, dcR = 0.0f, dcPrevL = 0.0f, dcPrevR = 0.0f;
|
||||||
float volSmooth = 1.0f;
|
|
||||||
juce::AudioBuffer<float> osBuf; // internal 2x oversample target (HQ mode)
|
juce::AudioBuffer<float> osBuf; // internal 2x oversample target (HQ mode)
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RMX19AudioProcessor)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RMX19AudioProcessor)
|
||||||
|
|
|
||||||
|
|
@ -62,25 +62,6 @@ SynthEngine::Voice* SynthEngine::acquireVoice()
|
||||||
return &voices[stealIdx];
|
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)
|
void SynthEngine::noteOn (int midiNote, float velocity)
|
||||||
{
|
{
|
||||||
const float noteFreq = (float) (440.0 * std::exp2 ((midiNote - 69.0) / 12.0));
|
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)
|
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)
|
for (auto& v : voices)
|
||||||
{
|
{
|
||||||
v.amp.setRates (sp.ampA, sp.ampD, sp.ampS, sp.ampR, sr);
|
v.amp.setRates (p.ampA, p.ampD, p.ampS, p.ampR, sr);
|
||||||
v.flt.setRates (sp.fA, sp.fD, sp.fS, sp.fR, sr);
|
v.flt.setRates (p.fA, p.fD, p.fS, p.fR, sr);
|
||||||
}
|
}
|
||||||
lastGlide = p.glide;
|
lastGlide = p.glide;
|
||||||
lastPan = sp.pan;
|
lastPan = p.pan;
|
||||||
polyLimit = juce::jlimit (1, maxVoice, (int) p.poly);
|
polyLimit = juce::jlimit (1, maxVoice, (int) p.poly);
|
||||||
|
|
||||||
const float glideRate = sp.glide <= 0.001f ? 1.0f
|
const float glideRate = p.glide <= 0.001f ? 1.0f
|
||||||
: 1.0f - std::exp (-1.0f / (sp.glide * (float) sr));
|
: 1.0f - std::exp (-1.0f / (p.glide * (float) sr));
|
||||||
const float detuneRatio = std::exp2f (sp.detune / 1200.0f);
|
const float detuneRatio = std::exp2f (p.detune / 1200.0f);
|
||||||
const float tuneRatio = std::exp2f (p.tune / 12.0f);
|
const float tuneRatio = std::exp2f (p.tune / 12.0f);
|
||||||
const float maxFc = 18000.0f, minFc = 30.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;
|
float mixL = 0.0f, mixR = 0.0f;
|
||||||
|
|
||||||
glideParams (sp, p, k);
|
|
||||||
|
|
||||||
for (auto& v : voices)
|
for (auto& v : voices)
|
||||||
{
|
{
|
||||||
if (! v.active)
|
if (! v.active)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sp.glide > 0.001f)
|
if (p.glide > 0.001f)
|
||||||
v.curFreq += (v.targetFreq - v.curFreq) * glideRate;
|
v.curFreq += (v.targetFreq - v.curFreq) * glideRate;
|
||||||
else
|
else
|
||||||
v.curFreq = v.targetFreq;
|
v.curFreq = v.targetFreq;
|
||||||
|
|
||||||
// LFO
|
// LFO
|
||||||
v.lfoPh += (double) sp.lfoRate / sr;
|
v.lfoPh += (double) p.lfoRate / sr;
|
||||||
while (v.lfoPh >= 1.0)
|
while (v.lfoPh >= 1.0)
|
||||||
{
|
{
|
||||||
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
|
// frequency, vibrato, bend, tune
|
||||||
float freq = v.curFreq * tuneRatio;
|
float freq = v.curFreq * tuneRatio;
|
||||||
if ((int) p.lfoTarget == 1)
|
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)
|
if (bendSmooth != bendCents)
|
||||||
bendSmooth += (bendCents - bendSmooth) * 0.08f;
|
bendSmooth += (bendCents - bendSmooth) * 0.08f;
|
||||||
freq *= std::exp2f (bendSmooth / 1200.0f);
|
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 o1 = osc ((int) p.osc1w, v.ph1);
|
||||||
const float o2 = osc ((int) p.osc2w, v.ph2);
|
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;
|
float sig = o1 * (1.0f - mixb) + o2 * mixb;
|
||||||
|
|
||||||
const float fe = v.flt.next();
|
const float fe = v.flt.next();
|
||||||
|
|
||||||
// cutoff with keytrack + filter envelope + LFO + mod wheel
|
// cutoff with keytrack + filter envelope + LFO + mod wheel
|
||||||
float fc = sp.fltCut;
|
float fc = p.fltCut;
|
||||||
fc *= std::exp2f (sp.fltKey * 0.01f * std::log2f (freq / 261.6256f));
|
fc *= std::exp2f (p.fltKey * 0.01f * std::log2f (freq / 261.6256f));
|
||||||
fc *= std::exp2f (sp.fltEnv * 0.01f * fe * std::log2f (maxFc / fc));
|
fc *= std::exp2f (p.fltEnv * 0.01f * fe * std::log2f (maxFc / fc));
|
||||||
if ((int) p.lfoTarget == 0)
|
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::exp2f (mod);
|
||||||
fc = std::min (maxFc, std::max (minFc, fc));
|
fc = std::min (maxFc, std::max (minFc, fc));
|
||||||
v.fcSm += (fc - v.fcSm) * 0.25f;
|
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
|
// SVF (cap f1 to keep the Chamberlin structure stable; past ~1.5 the
|
||||||
// resonance feedback can self-oscillate and sputter at maxed cutoff+res)
|
// resonance feedback can self-oscillate and sputter at maxed cutoff+res)
|
||||||
const float f1 = std::min (1.50f, 2.0f * std::sin (juce::MathConstants<float>::pi * fc / (float) sr));
|
const float f1 = std::min (1.50f, 2.0f * std::sin (juce::MathConstants<float>::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;
|
v.f1c = f1;
|
||||||
const float hp = sig - v.lp - q1 * v.bp;
|
const float hp = sig - v.lp - q1 * v.bp;
|
||||||
v.bp += f1 * hp;
|
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();
|
const float ae = v.amp.next();
|
||||||
float ampMod = 1.0f;
|
float ampMod = 1.0f;
|
||||||
if ((int) p.lfoTarget == 2)
|
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;
|
v.outSmooth += (filtered - v.outSmooth) * 0.12f;
|
||||||
float o = v.outSmooth * (ae * ampMod) * v.vel;
|
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;
|
left[s] += mixL;
|
||||||
right[s] += mixR;
|
right[s] += mixR;
|
||||||
|
|
||||||
sv = sp;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -112,8 +112,6 @@ public:
|
||||||
int activeVoices() const noexcept { return active; }
|
int activeVoices() const noexcept { return active; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void glideParams (VParams& sp, const VParams& tgt, float k);
|
|
||||||
|
|
||||||
struct Voice
|
struct Voice
|
||||||
{
|
{
|
||||||
bool active = false;
|
bool active = false;
|
||||||
|
|
@ -136,8 +134,6 @@ private:
|
||||||
int active = 0;
|
int active = 0;
|
||||||
int polyLimit = 16;
|
int polyLimit = 16;
|
||||||
float mod = 0.0f, bendCents = 0.0f, bendSmooth = 0.0f;
|
float mod = 0.0f, bendCents = 0.0f, bendSmooth = 0.0f;
|
||||||
VParams sv; // smoothed parameter values (per-sample glide)
|
|
||||||
bool svValid = false;
|
|
||||||
bool pedal = false;
|
bool pedal = false;
|
||||||
float lastNoteFreq = 440.0f, lastGlide = 0.0f, lastPan = 0.0f;
|
float lastNoteFreq = 440.0f, lastGlide = 0.0f, lastPan = 0.0f;
|
||||||
int stealIdx = 0;
|
int stealIdx = 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue