bosai_dsp/lib.rs
1//! Beat-synced DJ effects, in pure Rust.
2//!
3//! A library of DSP building blocks modelled on the Beat FX section of a
4//! professional DJ mixer: effects whose time base is *musical* rather than
5//! absolute. Every time-based effect here takes a `beat_value` (in beats) plus
6//! a live BPM, and derives its own delay time, loop length, or LFO rate from
7//! them — so a 1/2-beat echo stays a 1/2-beat echo when the deck's tempo fader
8//! moves.
9//!
10//! That is the distinction from general-purpose audio DSP crates, which
11//! overwhelmingly express time in seconds and leave tempo mapping to the caller.
12//!
13//! # What's here
14//!
15//! Beat-synced effects — all take `set_bpm()` + `beat_value`:
16//!
17//! - [`echo`] — stereo echo with DJ-mixer pre-filter variants (HPF / LPF / BPF)
18//! - [`ping_pong`] — cross-fed L/R bouncing delay
19//! - [`roll_fx`] — Roll, Slip Roll, Rev Roll and Helix buffer loopers
20//! - [`gater`] — rhythmic gate with noise fill
21//! - [`filter_fx`] — resonant HP/LP filter with beat-rate LFO sweep
22//! - [`flanger`], [`phaser`], [`peak_filter`] — beat-rate modulated
23//!
24//! Free-running blocks:
25//!
26//! - [`reverb`] — Freeverb, RT60-parameterised
27//! - [`eq_chain`] — 3-band Linkwitz-Riley crossover EQ + sweep filter
28//! - [`biquad`], [`svf`] — filter primitives
29//! - [`smoother`] — one-pole parameter smoothing
30//! - [`resample`] — linear/cubic interpolation helpers
31//!
32//! # Conventions
33//!
34//! **Stereo only.** [`CHANNELS`] is fixed at 2. Every DJ mixer signal path is
35//! stereo, and fixing it keeps frames on the stack as `[f64; 2]` with no
36//! allocation on the audio path.
37//!
38//! **`f64` internally.** Effects process in `f64` and are intended to sit in an
39//! `f64` mix bus; convert at the device boundary.
40//!
41//! **Click-free by construction.** Parameter changes are smoothed with one-pole
42//! filters, and changes that would jump a read pointer (delay time, beat value)
43//! are handled with short equal-power crossfades rather than discontinuities.
44//! Filter state is deliberately *not* reset on parameter change.
45//!
46//! **No allocation on the audio path.** Buffers are sized once at construction
47//! from a documented maximum; `process()` never allocates.
48
49#![forbid(unsafe_code)]
50// Audio frames are indexed by channel throughout; `for ch in 0..CHANNELS` keeps
51// the channel index visible and matches how the DSP is written on paper.
52#![allow(clippy::needless_range_loop)]
53
54/// Channel count for every frame in this crate. Stereo, fixed — see the
55/// crate-level docs for why.
56pub const CHANNELS: usize = 2;
57
58pub mod biquad;
59pub mod echo;
60pub mod eq_chain;
61pub mod filter_fx;
62pub mod flanger;
63pub mod freeverb;
64pub mod gater;
65pub mod peak_filter;
66pub mod phaser;
67pub mod ping_pong;
68pub mod resample;
69pub mod reverb;
70pub mod roll_fx;
71pub mod smoother;
72pub mod svf;