DSP Engineering
The Audio Thread Contract
On the audio thread, you MUST NOT:
- Allocate/deallocate memory (no
new, malloc, Vec::push, Box)
- Lock mutexes (use lock-free alternatives)
- Make system calls (no file I/O, no logging, no printing)
- Throw/catch exceptions (C++)
- Call virtual functions in hot paths (C++)
Cardinal Rules
- Pre-allocate everything before audio starts
- Use fixed-size buffers - size known at initialization
- Smooth parameters - never jump values (causes clicks)
- Process in blocks - batch operations for cache efficiency
- Denormals kill performance - flush to zero
Quick Reference
| Task |
Reference |
| Lock-free patterns, thread safety |
realtime-safety.md |
| Vectorization, SIMD |
simd-optimization.md |
| Buffer allocation, ring buffers |
buffer-management.md |
| Avoiding clicks, interpolation |
parameter-smoothing.md |
| Biquads, IIR/FIR filters |
filter-design.md |
| Waveforms, anti-aliasing |
oscillator-design.md |
| Circular buffers, chorus/flanger |
delay-lines.md |
| Compressors, limiters, gates |
dynamics-processing.md |
| FFT, convolution, spectral |
fft-spectral.md |
| Panning, stereo, mid-side |
spatial-audio.md |
| Testing DSP code |
dsp-testing |
| Memory layouts, cache optimization |
data-oriented-design.md |
| Mathematical foundations, theory |
dsp-mathematics |
Common Formulas
// Frequency to angular frequency
omega = 2 * PI * freq / sample_rate
// dB to linear gain
gain = 10^(dB / 20)
// Linear gain to dB
dB = 20 * log10(gain)
// MIDI note to frequency
freq = 440 * 2^((note - 69) / 12)
// Smoothing coefficient from time constant
coeff = 1 - exp(-1 / (time_ms * sample_rate / 1000))
Typical Processing Loop
fn process(&mut self, output: &mut [f32]) {
for sample in output.iter_mut() {
// 1. Get smoothed parameters
let freq = self.freq_smoother.next();
// 2. Generate/process audio
let osc = self.oscillator.next(freq);
// 3. Apply effects chain
let filtered = self.filter.process(osc);
// 4. Output with gain
*sample = filtered * self.gain_smoother.next();
}
}
Denormal Prevention
// Rust: flush denormals
fn flush_denormal(x: f32) -> f32 {
if x.abs() < 1e-15 { 0.0 } else { x }
}
// Or use a small DC offset in feedback paths
const DC_OFFSET: f32 = 1e-25;
// C++: set FTZ/DAZ flags at plugin init
#include <xmmintrin.h>
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: dsp-engineering3description: Audio DSP programming guidance for plugins, synthesis, and effects. Use when writing realtime audio code, implementing DSP algorithms, or building audio plugins in Rust or C++. Use when this capability is needed.4---56# DSP Engineering78## The Audio Thread Contract910On the audio thread, you MUST NOT:11- **Allocate/deallocate memory** (no `new`, `malloc`, `Vec::push`, `Box`)12- **Lock mutexes** (use lock-free alternatives)13- **Make system calls** (no file I/O, no logging, no printing)14- **Throw/catch exceptions** (C++)15- **Call virtual functions in hot paths** (C++)1617## Cardinal Rules18191. **Pre-allocate everything** before audio starts202. **Use fixed-size buffers** - size known at initialization213. **Smooth parameters** - never jump values (causes clicks)224. **Process in blocks** - batch operations for cache efficiency235. **Denormals kill performance** - flush to zero2425## Quick Reference2627| Task | Reference |28|------|-----------|29| Lock-free patterns, thread safety | [realtime-safety.md](realtime-safety.md) |30| Vectorization, SIMD | [simd-optimization.md](simd-optimization.md) |31| Buffer allocation, ring buffers | [buffer-management.md](buffer-management.md) |32| Avoiding clicks, interpolation | [parameter-smoothing.md](parameter-smoothing.md) |33| Biquads, IIR/FIR filters | [filter-design.md](filter-design.md) |34| Waveforms, anti-aliasing | [oscillator-design.md](oscillator-design.md) |35| Circular buffers, chorus/flanger | [delay-lines.md](delay-lines.md) |36| Compressors, limiters, gates | [dynamics-processing.md](dynamics-processing.md) |37| FFT, convolution, spectral | [fft-spectral.md](fft-spectral.md) |38| Panning, stereo, mid-side | [spatial-audio.md](spatial-audio.md) |39| Testing DSP code | [dsp-testing](../dsp-testing/SKILL.md) |40| Memory layouts, cache optimization | [data-oriented-design.md](data-oriented-design.md) |41| Mathematical foundations, theory | [dsp-mathematics](../dsp-mathematics/SKILL.md) |4243## Common Formulas4445```46// Frequency to angular frequency47omega = 2 * PI * freq / sample_rate4849// dB to linear gain50gain = 10^(dB / 20)5152// Linear gain to dB53dB = 20 * log10(gain)5455// MIDI note to frequency56freq = 440 * 2^((note - 69) / 12)5758// Smoothing coefficient from time constant59coeff = 1 - exp(-1 / (time_ms * sample_rate / 1000))60```6162## Typical Processing Loop6364```rust65fn process(&mut self, output: &mut [f32]) {66 for sample in output.iter_mut() {67 // 1. Get smoothed parameters68 let freq = self.freq_smoother.next();6970 // 2. Generate/process audio71 let osc = self.oscillator.next(freq);7273 // 3. Apply effects chain74 let filtered = self.filter.process(osc);7576 // 4. Output with gain77 *sample = filtered * self.gain_smoother.next();78 }79}80```8182## Denormal Prevention8384```rust85// Rust: flush denormals86fn flush_denormal(x: f32) -> f32 {87 if x.abs() < 1e-15 { 0.0 } else { x }88}8990// Or use a small DC offset in feedback paths91const DC_OFFSET: f32 = 1e-25;92```9394```cpp95// C++: set FTZ/DAZ flags at plugin init96#include <xmmintrin.h>97_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);98_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);99```100101---102> Converted and distributed by [TomeVault](https://tomevault.io/claim/maxwellmattryan) — claim your Tome and manage your conversions.103<!-- tomevault:4.0:skill_md:2026-04-14 -->