pub(crate) const GOLDEN_GAMMA: u64 = 0x9E37_79B9_7F4A_7C15;
pub(crate) const FNV_OFFSET: u64 = 0xCBF2_9CE4_8422_2325;
pub(crate) const FNV_PRIME: u64 = 0x0000_0100_0000_01B3;
pub(crate) fn splitmix_mix(mut z: u64) -> u64 {
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
#[derive(Clone)]
pub struct Rng(u64);
impl Rng {
pub fn new(seed: u64) -> Self {
Rng(seed)
}
pub fn next_u64(&mut self) -> u64 {
self.0 = self.0.wrapping_add(GOLDEN_GAMMA);
splitmix_mix(self.0)
}
pub fn unit(&mut self) -> f32 {
(self.next_u64() >> 40) as f32 / (1u32 << 24) as f32
}
pub fn bi(&mut self) -> f32 {
self.unit() * 2.0 - 1.0
}
pub fn range(&mut self, lo: f32, hi: f32) -> f32 {
lo + (hi - lo) * self.unit()
}
}
pub fn layer_stream_key(id: &str) -> u64 {
let mut h = FNV_OFFSET;
for b in id.as_bytes() {
h ^= *b as u64;
h = h.wrapping_mul(FNV_PRIME);
}
h
}
pub(crate) fn node_path(parent: u64, child: usize) -> u64 {
(parent ^ (child as u64).wrapping_add(1)).wrapping_mul(FNV_PRIME)
}
pub(crate) fn node_seed(path: u64) -> u64 {
splitmix_mix(path.wrapping_add(GOLDEN_GAMMA))
}
pub(crate) fn adsr_env(t: f32, a: f32, d: f32, s: f32, r: f32, punch: f32, rel_start: f32) -> f32 {
let mut v = if t < a {
if a > 0.0 { t / a } else { 1.0 }
} else if t < a + d {
let p = if d > 0.0 { (t - a) / d } else { 1.0 };
1.0 - (1.0 - s) * p
} else if t < rel_start {
s
} else if r > 0.0 {
let p = ((t - rel_start) / r).clamp(0.0, 1.0);
s * (1.0 - p)
} else {
0.0
};
let punch_win = a + d;
if punch > 0.0 && punch_win > 0.0 && t < punch_win {
v *= 1.0 + punch * (1.0 - t / punch_win);
}
v
}
pub(crate) const FREEVERB_COMB_TUNINGS: [usize; 6] = [1116, 1188, 1277, 1356, 1422, 1491];
pub(crate) const FREEVERB_ALLPASS_TUNINGS: [usize; 4] = [556, 441, 341, 225];
pub(crate) const FREEVERB_DAMP: f32 = 0.2;
pub(crate) const CHORUS_BASE_SECS: f32 = 0.015;
pub(crate) const CHORUS_SWING_SECS: f32 = 0.010;
pub(crate) const FLANGER_BASE_SECS: f32 = 0.0025;
pub(crate) const FLANGER_SWING_SECS: f32 = 0.002;
pub fn dbfs(x: f32) -> f32 {
20.0 * x.max(1e-9).log10()
}
pub fn db_to_lin(db: f32) -> f32 {
10f32.powf(db / 20.0)
}
pub const CEIL: f32 = 0.989;
pub fn peak_limit(channels: &mut [&mut [f32]]) {
let mut peak = 0.0f32;
for c in channels.iter_mut() {
for x in c.iter_mut() {
if !x.is_finite() {
*x = 0.0;
}
peak = peak.max(x.abs());
}
}
if peak > CEIL {
let g = CEIL / peak;
for c in channels.iter_mut() {
for x in c.iter_mut() {
*x *= g;
}
}
}
}
pub fn true_peak(samples: &[f32]) -> f32 {
if samples.len() < 2 {
return samples.iter().fold(0.0f32, |m, &x| m.max(x.abs()));
}
let mut peak = 0.0f32;
for w in samples.windows(2) {
for k in 0..4 {
let t = k as f32 / 4.0;
let v = (w[0] * (1.0 - t) + w[1] * t).abs();
if v > peak {
peak = v;
}
}
}
peak
}
const TP_PHASES: [[f32; 12]; 3] = [
[
-0.001_630_944,
0.010_354_987,
-0.030_093_31,
0.069_125_3,
-0.161_381_1,
0.896_035_25,
0.288_544_92,
-0.103_407_112,
0.046_242_866,
-0.018_517_122,
0.004_893_635,
-0.000_167_362,
],
[
-0.000_985_122,
0.010_349_617,
-0.033_673_15,
0.080_066_491,
-0.180_965_97,
0.625_208_14,
0.625_208_14,
-0.180_965_97,
0.080_066_491,
-0.033_673_15,
0.010_349_617,
-0.000_985_122,
],
[
-0.000_167_362,
0.004_893_635,
-0.018_517_122,
0.046_242_866,
-0.103_407_112,
0.288_544_92,
0.896_035_25,
-0.161_381_1,
0.069_125_3,
-0.030_093_31,
0.010_354_987,
-0.001_630_944,
],
];
pub fn true_peak_oversampled(samples: &[f32]) -> f32 {
let mut peak = samples.iter().fold(0.0f32, |m, &x| m.max(x.abs()));
let at = |i: isize| -> f32 {
if i < 0 || i as usize >= samples.len() {
0.0
} else {
samples[i as usize]
}
};
for i in 0..samples.len() as isize {
for phase in &TP_PHASES {
let mut v = 0.0f32;
for (t, c) in phase.iter().enumerate() {
v += c * at(i + t as isize - 5);
}
peak = peak.max(v.abs());
}
}
peak
}
pub fn loudness_lufs(samples: &[f32]) -> f32 {
if samples.is_empty() {
return -120.0;
}
let shelf = biquad_df1(
samples,
[1.535_124_9, -2.691_696_2, 1.198_392_8],
[-1.690_659_3, 0.732_480_8],
);
let weighted = biquad_df1(&shelf, [1.0, -2.0, 1.0], [-1.990_047_5, 0.990_072_3]);
let ms = weighted.iter().map(|x| x * x).sum::<f32>() / weighted.len() as f32;
-0.691 + 10.0 * ms.max(1e-12).log10()
}
fn k_weighting_coeffs(sr: u32) -> ([f32; 3], [f32; 2], [f32; 3], [f32; 2]) {
let fs = sr as f64;
let (f0, gain_db, q) = (
1_681.974_450_955_533,
3.999_843_853_973_347,
0.707_175_236_955_419_6,
);
let k = (std::f64::consts::PI * f0 / fs).tan();
let vh = 10f64.powf(gain_db / 20.0);
let vb = vh.powf(0.499_666_774_154_541_6);
let d = 1.0 + k / q + k * k;
let shelf_b = [
((vh + vb * k / q + k * k) / d) as f32,
((2.0 * (k * k - vh)) / d) as f32,
((vh - vb * k / q + k * k) / d) as f32,
];
let shelf_a = [
((2.0 * (k * k - 1.0)) / d) as f32,
((1.0 - k / q + k * k) / d) as f32,
];
let (f0, q) = (38.135_470_876_024_44, 0.500_327_037_323_877_3);
let k = (std::f64::consts::PI * f0 / fs).tan();
let d = 1.0 + k / q + k * k;
let hp_b = [1.0, -2.0, 1.0];
let hp_a = [
((2.0 * (k * k - 1.0)) / d) as f32,
((1.0 - k / q + k * k) / d) as f32,
];
(shelf_b, shelf_a, hp_b, hp_a)
}
fn k_weight(samples: &[f32], sr: u32) -> Vec<f32> {
let (sb, sa, hb, ha) = k_weighting_coeffs(sr);
biquad_df1(&biquad_df1(samples, sb, sa), hb, ha)
}
pub fn loudness_lufs_gated(channels: &[&[f32]], sr: u32) -> f32 {
let n = channels.iter().map(|c| c.len()).min().unwrap_or(0);
if n == 0 {
return -120.0;
}
let weighted: Vec<Vec<f32>> = channels.iter().map(|c| k_weight(c, sr)).collect();
let sum_ms = |range: std::ops::Range<usize>| -> f64 {
weighted
.iter()
.map(|w| {
w[range.clone()]
.iter()
.map(|x| *x as f64 * *x as f64)
.sum::<f64>()
/ range.len() as f64
})
.sum()
};
let lufs = |ms: f64| -0.691 + 10.0 * ms.max(1e-12).log10();
let block = (sr as usize * 2) / 5; if n < block || block == 0 {
return lufs(sum_ms(0..n)) as f32;
}
let hop = (block / 4).max(1); let blocks: Vec<f64> = (0..=(n - block))
.step_by(hop)
.map(|s| sum_ms(s..s + block))
.collect();
let above: Vec<f64> = blocks.into_iter().filter(|&ms| lufs(ms) > -70.0).collect();
if above.is_empty() {
return -120.0;
}
let rel = lufs(above.iter().sum::<f64>() / above.len() as f64) - 10.0;
let gated: Vec<f64> = above.into_iter().filter(|&ms| lufs(ms) > rel).collect();
if gated.is_empty() {
return -120.0;
}
lufs(gated.iter().sum::<f64>() / gated.len() as f64) as f32
}
fn biquad_df1(input: &[f32], b: [f32; 3], a: [f32; 2]) -> Vec<f32> {
let (mut x1, mut x2, mut y1, mut y2) = (0.0f32, 0.0, 0.0, 0.0);
input
.iter()
.map(|&x0| {
let y0 = b[0] * x0 + b[1] * x1 + b[2] * x2 - a[0] * y1 - a[1] * y2;
x2 = x1;
x1 = x0;
y2 = y1;
y1 = y0;
y0
})
.collect()
}
pub fn hz_to_midi(hz: f32) -> f32 {
69.0 + 12.0 * (hz / 440.0).log2()
}
pub(crate) const NEG_LN_1000: f32 = -6.907_755;
pub(crate) fn modal_coeffs(freq: f32, decay: f32, gain: f32, sr: u32) -> (f32, f32, f32) {
let srf = sr as f32;
let nyq = srf * 0.5;
let f0 = freq.clamp(1.0, (nyq - 1.0).max(1.0));
let decay = decay.max(1e-3);
let w0 = std::f32::consts::TAU * f0 / srf;
let (sin0, cos0) = (w0.sin(), w0.cos());
let r = (NEG_LN_1000 / (decay * srf)).exp();
(2.0 * r * cos0, -r * r, gain * sin0)
}
pub(crate) fn delay_line_len(secs: f32, sr: u32) -> usize {
((secs.min(30.0) * sr as f32) as usize).max(1)
}
pub(crate) fn bitcrush_levels(bits: u8) -> f32 {
(1u32 << (bits as u32).min(31)) as f32
}
pub(crate) fn freeverb_lengths(sr: u32, spread: usize) -> (Vec<usize>, Vec<usize>) {
let scale = sr as f32 / 44_100.0;
let combs = FREEVERB_COMB_TUNINGS
.iter()
.map(|t| (((t + spread) as f32 * scale) as usize).max(1))
.collect();
let allpasses = FREEVERB_ALLPASS_TUNINGS
.iter()
.map(|t| (((t + spread) as f32 * scale) as usize).max(1))
.collect();
(combs, allpasses)
}
pub(crate) fn freeverb_feedback(room: f32) -> f32 {
0.7 + 0.28 * room.clamp(0.0, 1.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn splitmix64_matches_reference_vectors() {
let mut rng = Rng::new(0);
assert_eq!(rng.next_u64(), 0xE220_A839_7B1D_CDAF);
assert_eq!(rng.next_u64(), 0x6E78_9E6A_A1B9_65F4);
assert_eq!(rng.next_u64(), 0x06C4_5D18_8009_454F);
}
#[test]
fn unit_and_bi_stay_in_range() {
let mut rng = Rng::new(42);
for _ in 0..1000 {
let u = rng.unit();
assert!((0.0..1.0).contains(&u));
}
let mut rng = Rng::new(42);
for _ in 0..1000 {
let b = rng.bi();
assert!((-1.0..1.0).contains(&b));
}
}
#[test]
fn db_conversions_roundtrip() {
assert_eq!(dbfs(1.0), 0.0);
assert!((dbfs(0.5) + 6.0206).abs() < 0.001);
assert!((db_to_lin(-6.0206) - 0.5).abs() < 0.001);
assert_eq!(dbfs(0.0), -180.0); }
#[test]
fn k_weighting_at_48k_matches_the_standard_table() {
let (sb, sa, hb, ha) = k_weighting_coeffs(48_000);
let expect = |got: f32, want: f32| {
assert!((got - want).abs() < 1e-4, "got {got}, want {want}");
};
expect(sb[0], 1.535_124_9);
expect(sb[1], -2.691_696_2);
expect(sb[2], 1.198_392_8);
expect(sa[0], -1.690_659_3);
expect(sa[1], 0.732_480_8);
assert_eq!(hb, [1.0, -2.0, 1.0]);
expect(ha[0], -1.990_047_5);
expect(ha[1], 0.990_072_3);
}
#[test]
fn oversampled_true_peak_sees_between_the_samples() {
let x: Vec<f32> = (0..1024)
.map(|i| (std::f32::consts::FRAC_PI_2 * i as f32 + std::f32::consts::FRAC_PI_4).sin())
.collect();
let sample_peak = x.iter().fold(0.0f32, |m, &v| m.max(v.abs()));
assert!((sample_peak - std::f32::consts::FRAC_1_SQRT_2).abs() < 1e-3);
assert!(true_peak(&x) <= sample_peak + 1e-6, "legacy: bounded");
let tp = true_peak_oversampled(&x);
assert!(
(0.98..=1.05).contains(&tp),
"oversampled estimate {tp} should recover the hidden 1.0 peak"
);
}
#[test]
fn gated_loudness_ignores_silence_and_sums_channels() {
let sr = 48_000u32;
let tau = std::f32::consts::TAU;
let tone: Vec<f32> = (0..4 * sr as usize)
.map(|i| 0.25 * (tau * 440.0 * i as f32 / sr as f32).sin())
.collect();
let solo = loudness_lufs_gated(&[&tone], sr);
let mut padded = tone.clone();
padded.extend(std::iter::repeat_n(0.0f32, 8 * sr as usize));
let gated = loudness_lufs_gated(&[&padded], sr);
assert!(
(gated - solo).abs() < 0.35,
"gated {gated} vs solo {solo}: silence must not drag the reading"
);
assert!(
loudness_lufs(&padded) < solo - 4.0,
"the ungated legacy reading is dragged down by the padding"
);
let stereo = loudness_lufs_gated(&[&tone, &tone], sr);
assert!(
(stereo - solo - 3.01).abs() < 0.1,
"stereo {stereo} vs mono {solo}: channels sum per BS.1770"
);
assert_eq!(loudness_lufs_gated(&[], sr), -120.0);
}
#[test]
fn peak_limit_attenuates_jointly_never_boosts() {
let mut l = vec![2.0f32, 0.5];
let mut r = vec![1.0f32, 0.25];
peak_limit(&mut [&mut l, &mut r]);
assert!((l[0] - CEIL).abs() < 1e-6); assert!((r[0] - CEIL / 2.0).abs() < 1e-6); let mut quiet = vec![0.1f32, -0.2];
peak_limit(&mut [&mut quiet]);
assert_eq!(quiet, vec![0.1, -0.2]); }
}