The Audio Helpers

src/audio.zig. Small, dependency-free, and covered by the unit tests.

dBToLinear and linearTodB

pub fn dBToLinear(dB: f32) f32 {
    return @exp(dB * 0.11512925464970229);   // ln(10)/20
}

pub fn linearTodB(linear: f32) f32 {
    if (linear <= 0.0) return -80.0;
    return @log(linear) * 8.6858896380650365; // 20/ln(10)
}

Both avoid pow and log10 in favour of a single exp or log and a multiply. linearTodB floors at -80 dB for non-positive input, so silence returns a finite number rather than negative infinity.

The constants are worth a test of their own, and they have one. A previous copy of this file carried a stray factor of ten in the exponent, which turned dBToLinear(6) into 1000.0 instead of 1.9953. src/tests.zig now checks unity at 0 dB, the factor of two at +6 dB, the factor of ten at +20 dB, and a full round trip across -48 to +24 dB.

GainProcessor

A gain stage with a built-in ramp.

var g = danzig.GainProcessor{};
g.setGain(6.0);                            // dB
g.process(&inputs, &outputs, channels, frames);

setGain converts to a linear target. process interpolates the current gain toward the target by a fixed 0.001 per sample, so a change takes roughly a thousand samples to substantially complete. setNormalizedGain maps [0, 1] onto -48 to +48 dB, which is the range the example plugin exposes.

The interpolation coefficient is fixed and not sample-rate aware. For a rate-independent ramp, use AtomicParam with a millisecond time constant instead.

SimpleRamp

A linear ramp over a sample count, for anything that is not a gain.

var r = danzig.SimpleRamp.init(0.0, 8);   // start value, ramp length in samples
r.setTarget(1.0);
for (0..8) |_| _ = r.next();
// r.getValue() == 1.0

setTarget restarts the ramp from the current value. A ramp length of zero or one is treated as instant. The final sample is snapped to the target exactly, so the ramp does not leave a residue.

AudioBuffer

An owned multi-channel buffer, for offline work and tests. It allocates, so keep it off the audio thread.

var buf = try danzig.AudioBuffer.init(allocator, 2, 512, 48000.0);
defer buf.deinit(allocator);
buf.clear();

init zeroes every channel. clear and its alias silence re-zero.