You've already forked ivan-torvalds-GuitarPedal
forked from AllSpiceMirrors/torvalds-GuitarPedal
This is one of the things I wanted to do but was just too painful to do with a screen and rotary encoder model: re-order the effects in the effect chain. It's trivial to do from an _audio_ standpoint - it's just an array of effect indexes that says what order to run the effects in. But from an UI angle, it was just too painful to do. Until I bit the bullet and decided that the WebMIDI thing is the only real configuration tool, and you configure things into scenes. Now it's pretty straightforward. The rule is simple: you always have to start with the noise gate. It doesn't have to be *enabled*, but it has to be there in the effect chain. Then we just use one of the reserved bytes in the effect save state to say what the next effect is. Voilà, an almost arbitrary effect chain. This reorganizes the effect chain in another way too: not only can you re-order the effects, but the effect chain now deals with the 'mix' for you, which means that every single effect now automatically has a mix setting, and the ones that did it explicitly have been removed. Note that the vibrato effect did an interesting equal-power mix thing, and that also was removed, but I'm making a note of it here because I wonder if that thing should be how we do the generic mixing. But I wanted to keep the changes _fairly_ minimal. As always, the WebMIDI code is all antigravity. And let's be honest, in this case that's the complex case. But it would have been a nightmare to do in the embedded context on the pedal, and with this whole "UI through WebMIDI" the effect chain changes are fairly simple. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
53 lines
1.3 KiB
C
53 lines
1.3 KiB
C
// NAME: Noise Gate [GATE]
|
|
// PRIORITY: 0 (Special: always runs first outside of effect_chain)
|
|
// POT: "Active" ENUM(Off On) = On
|
|
// POT: "Level" LINEAR(-100.0 -40.0) = -70.0 dB
|
|
// POT: "Attack" LINEAR(0.0 10.0) = 1.5 ms
|
|
// POT: "Release" LINEAR(50.0 500.0) = 150.0 ms
|
|
//
|
|
// Noise Gate
|
|
//
|
|
// Same envelope calculations as the compressor. I wonder if
|
|
// I should just have a combined noise gate / compressor thing?
|
|
//
|
|
// But the attack/release values are probably different.
|
|
//
|
|
|
|
static struct {
|
|
struct envelope envelope;
|
|
float mult, level;
|
|
int active;
|
|
} gate;
|
|
|
|
static inline void gate_init(unsigned char pot[10])
|
|
{
|
|
gate.active = (int)gate_pot0(pot[0]);
|
|
float level_db = gate_pot1(pot[1]);
|
|
gate.level = db_to_level(level_db);
|
|
|
|
float attack_ms = gate_pot2(pot[2]);
|
|
float release_ms = gate_pot3(pot[3]);
|
|
envelope_init(&gate.envelope, attack_ms, release_ms);
|
|
}
|
|
|
|
static inline float gate_step(float in)
|
|
{
|
|
if (!gate.active) return in;
|
|
float env = envelope_step(&gate.envelope, in);
|
|
float mult = gate.mult;
|
|
|
|
// Ramp up fairly quickly, ramp down slowly
|
|
if (env >= gate.level) {
|
|
mult = linear(0.01f, mult, 1.0f);
|
|
if (mult > 0.99f)
|
|
mult = 1.0f;
|
|
} else {
|
|
mult = linear(0.001f, mult, 0.0f);
|
|
if (mult < 0.01f)
|
|
mult = 0.0f;
|
|
gate_effect.intense = 1;
|
|
}
|
|
gate.mult = mult;
|
|
return in * mult;
|
|
}
|