Files
Linus Torvalds 3be9e6a482 Let an effect say how its wet and dry should be mixed
Back when mixing was each effect's own business, they all did a plain
linear blend except for the vibrato, which did an equal-power one with a
sin/cos pair.  When the mix moved into the effect chain that distinction
got flattened, and the vibrato quietly lost it.

It shouldn't have.  The two laws differ in what they assume about
whether the wet and dry are correlated, and each is wrong by 3dB in the
other's case.  When the wet is a filtered version of the dry - which is
most of what's here - the amplitudes add, half of each gives you back
the original, and an equal-power mix puts a 3dB hump right in the middle
of the sweep where everyone leaves the knob.  When they're uncorrelated
the powers add instead, and it's the linear mix that leaves a 3dB hole
there.

So it isn't one law for everything, it is a property of the effect, and
the effect header is where it should say so.  Add a 'MIX:' annotation
alongside PRIORITY and DEFAULT_MIX, defaulting to LINEAR, and mark the
four whose wet really is decorrelated from the dry: vibrato, echo,
reverb and the pitch shifter.

Phaser and flanger stay linear on purpose, even though it's tempting.
An allpass or comb has the same magnitude spectrum as the input and only
differs in phase, and the cancellation is the whole point - equal power
would fill the notches back in by 3dB and make them sound weak.

Nothing uses the field yet; do_effect_step() still does what it did.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-07-27 17:38:00 -07:00

33 lines
1.1 KiB
C

// NAME: Vibrato [VIB]
// PRIORITY: 70
// MIX: POWER // a modulated delay - the wet is the dry displaced in time
// POT: "Rate" FREQUENCY(0.1 8.0) = 2.0 Hz
// POT: "Depth" LINEAR(0.0 5.0) = 0.875 ms
// Vibrato: LFO-modulated delay line for a classic Doppler shift.
// Blending dry signal with the wet signal produces a rich chorus-like effect.
// At 100% wet only the pitch-shifted signal is audible; fun for rotary speaker emulation.
#define VIBRATO_CENTER_SAMPLES (6.0f * SAMPLES_PER_MSEC)
static struct {
struct lfo_state lfo;
float depth; // delay amplitude in samples
unsigned int idx;
float samples[1024]; // ~21ms at 48kHz; max read = center(6ms) + depth(5ms) = 528 samples
} vibrato;
static void vibrato_init(unsigned char pot[10])
{
set_lfo_freq(&vibrato.lfo, vibrato_pot0(pot[0]));
vibrato.depth = vibrato_pot1(pot[1]) * SAMPLES_PER_MSEC;
}
static float vibrato_step(float in)
{
float d = VIBRATO_CENTER_SAMPLES + vibrato.depth * lfo_step(&vibrato.lfo, lfo_sinewave);
sample_array_write(in, &vibrato.idx, vibrato.samples);
float wet = sample_array_read(d, &vibrato.idx, vibrato.samples);
return wet;
}