mirror of
https://codeberg.org/armin/monostep.git
synced 2026-09-01 12:20:46 +02:00
Add delay/reverb dry-wet, granular randomize toggles, rework accent DSP
- Add delay and reverb Dry/Wet parameters and knobs, wired into presets - Add Accent/Slide/Fine/Rate toggles to the Randomize panel with new per-aspect pattern randomizers - Soften accent: modest volume lift plus small cutoff and filter-attack modulation instead of the heavy 5x gain boost - Halve reverb comb/allpass delays so the wet speaks sooner - Regenerate a fresh build stamp on every build
This commit is contained in:
parent
342d413563
commit
662a1f7383
11 changed files with 310 additions and 97 deletions
|
|
@ -137,6 +137,10 @@ private:
|
|||
fenvStage = Stage::attack;
|
||||
}
|
||||
|
||||
// RC-style (exponential) filter envelope: the cutoff glides smoothly instead
|
||||
// of stepping linearly, so fast filter sweeps sound analog rather than
|
||||
// zippered. Each stage still reaches ~95% within the labelled time, so the
|
||||
// knob values keep their musical meaning.
|
||||
void updateFilterEnvelope()
|
||||
{
|
||||
const float sr = sampleRate;
|
||||
|
|
@ -144,23 +148,37 @@ private:
|
|||
switch (fenvStage)
|
||||
{
|
||||
case Stage::attack:
|
||||
fenv += 1.0f / (params.fAttack * sr);
|
||||
if (fenv >= 1.0f) { fenv = 1.0f; fenvStage = Stage::decay; }
|
||||
{
|
||||
// Accented notes attack the filter ever so slightly faster.
|
||||
const float acc = accentSmooth - 1.0f;
|
||||
const float t = juce::jmax (0.0005f, params.fAttack / (1.0f + acc * 0.5f));
|
||||
const float a = 1.0f - std::exp (-3.0f / (t * sr));
|
||||
fenv += (1.0f - fenv) * a;
|
||||
if (fenv >= 0.999f) { fenv = 1.0f; fenvStage = Stage::decay; }
|
||||
break;
|
||||
}
|
||||
|
||||
case Stage::decay:
|
||||
fenv -= (1.0f - params.fSustain) / (params.fDecay * sr);
|
||||
if (fenv <= params.fSustain) { fenv = params.fSustain; fenvStage = Stage::sustain; }
|
||||
{
|
||||
const float t = juce::jmax (0.0005f, params.fDecay);
|
||||
const float a = 1.0f - std::exp (-3.0f / (t * sr));
|
||||
fenv += (params.fSustain - fenv) * a;
|
||||
if (std::fabs (fenv - params.fSustain) < 0.001f) { fenv = params.fSustain; fenvStage = Stage::sustain; }
|
||||
break;
|
||||
}
|
||||
|
||||
case Stage::sustain:
|
||||
fenv = params.fSustain;
|
||||
break;
|
||||
|
||||
case Stage::release:
|
||||
fenv -= 1.0f / (params.fRelease * sr);
|
||||
if (fenv <= 0.0f) { fenv = 0.0f; fenvStage = Stage::idle; }
|
||||
{
|
||||
const float t = juce::jmax (0.0005f, params.fRelease);
|
||||
const float a = 1.0f - std::exp (-3.0f / (t * sr));
|
||||
fenv -= fenv * a;
|
||||
if (fenv <= 0.001f) { fenv = 0.0f; fenvStage = Stage::idle; }
|
||||
break;
|
||||
}
|
||||
|
||||
case Stage::idle:
|
||||
break;
|
||||
|
|
@ -278,15 +296,18 @@ private:
|
|||
|
||||
float renderSample()
|
||||
{
|
||||
updateEnvelope();
|
||||
updateFilterEnvelope();
|
||||
updateGlide();
|
||||
|
||||
// Accent gains fast attack / slow release, so the boost fades out smoothly
|
||||
// at the tail of an accented note instead of cutting off hard-edged.
|
||||
accentSmooth += (accentLevel - accentSmooth)
|
||||
* (accentLevel > accentSmooth ? accentAttackCoef : accentReleaseCoef);
|
||||
|
||||
// 0 for unaccented steps, rising with the accent knob on accented ones.
|
||||
const float accBoost = accentSmooth - 1.0f;
|
||||
|
||||
updateEnvelope();
|
||||
updateFilterEnvelope();
|
||||
updateGlide();
|
||||
|
||||
const float incA = (currentFreq * params.detuneRatioA) / sampleRate;
|
||||
const float incB = (currentFreq * params.detuneRatio) / sampleRate;
|
||||
|
||||
|
|
@ -302,14 +323,17 @@ private:
|
|||
out = (1.0f - params.ringMod) * out + params.ringMod * (a * b);
|
||||
|
||||
const float preFilter = out;
|
||||
|
||||
// Accented steps open the filter a tiny bit, so they sparkle without
|
||||
// relying on a big volume jump.
|
||||
const float envCutoff = juce::jlimit (20.0f, 20000.0f,
|
||||
params.cutoff * std::pow (2.0f, params.fAmount * fenv));
|
||||
params.cutoff * std::pow (2.0f, params.fAmount * fenv + accBoost * 1.5f));
|
||||
out = processFilter (out, envCutoff);
|
||||
|
||||
// Accented steps also get a touch of the unfiltered signal so they cut
|
||||
// through the mix (presence), not just a volume bump.
|
||||
if (accentSmooth > 1.0f)
|
||||
out += (accentSmooth - 1.0f) * 0.2f * preFilter;
|
||||
if (accBoost > 0.0f)
|
||||
out += accBoost * 0.2f * preFilter;
|
||||
|
||||
if (params.drive > 0.0f)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue