acron.dsp¶
Offline DSP for baked game audio, and the versioned WAV cache it lands in.
The trade this kit serves: an engine with no live audio graph plays baked
WAVs, so the synthesis runs once into a cache and playback is gain staging.
Everything here is plain Python over array('d') buffers — offline, run
once per cache version, deterministic from a seeded acron.noise.RNG,
so a given seed renders the same buffer every time on any machine. Signals
go in as any sequence of floats (a list, an array, a memoryview);
stereo is a (left, right) pair of them.
Conventions worth stating once:
Biquad Q is RBJ-cookbook Q (Audio EQ Cookbook, R. Bristow-Johnson), one linear convention for every kind; 0.7071 is the flattest (Butterworth) response, and a
qof 0 divides by zero — nothing here interprets Q in dB.Filter a LOOP circularly (
loop_filter()): the exact steady state of the periodic input, seamless by construction. It is computed in the time domain — the biquad run from the one initial state that its own period maps back onto itself — which is the same answer an FFT gives (each bin times the response at that bin) in two passes over the loop.Normalise a reverb impulse before convolving (
plate_norm()): send gains then mean the same wetness whatever the IR’s seed, length or decay — skipping it renders a plate about twenty times too wet (measured).A stereo plate is applied as its channel mean: the tail of a mono source through
(left, right)averaged is, by linearity, the source through(left + right) / 2— one convolution, not two.
|
A versioned directory of baked WAVs with a manifest of true levels. |
Global Functions
- biquad_h(kind: str, f0: float, freqs, fs: float, q: float = 0.7071, gain_db: float = 0.0) list[complex]¶
The complex response of a biquad filter — the Audio EQ Cookbook coefficient formulas, S=1 shelves — evaluated at each of
freqs.
- brown_noise(rng, sec: float, rate: int) array¶
Brown-ish noise, heavier at the bottom: a leaky integrator over the seeded stream, one draw per sample, so a given seed renders the same buffer every time.
- env_exp(n: int, rate: float, peak: float, attack: float, decay: float) array¶
An exponential attack/decay envelope:
ENV_FLOOR->peakinattackseconds, back to the floor overdecay.
- impulse(rng, sec: float, decay: float, rate: int) tuple[array, array]¶
A plate-reverb impulse response — decaying white noise, stereo
(left, right).
- loop_bins(length: int, rate: int, f0: float) tuple[int, float]¶
Quantise
f0to a loop’s FFT grid — a loop only loops if every component sits on its grid. Returns (bin, the frequency that bin is).
- loop_filter(sig, kind: str, f0: float, fs: float, q: float = 1.0, gain_db: float = 0.0) array¶
Filter a LOOP circularly: the exact steady state of the periodic input, and seamless by construction.
The biquad’s zero-input state map over one period is
A**n; running the loop once from rest lands onr; the periodic state is the fixed points = A**n s + r, and the loop run fromsis the answer.
- plate_norm(ir, rate: float)¶
Equal-power normalisation of a reverb impulse response — see
PLATE_RMS_REF. Same shape out as in (mono, or a channel tuple).
- reverb_loop(sig, ir, send: float) array¶
dry + send * (sig (x) ir), circularly — a loop’s steady-state plate. Each IR channel is cut to the loop’s length, as a circular plate must be.