use core::f32::consts::PI;
#[derive(Debug, Clone)]
pub struct Signal {
pub name: String,
pub sample_rate: u32,
pub channels: u16,
pub pcm: Vec<f32>,
}
pub const LEN: usize = 4608;
const SR: u32 = 44_100;
fn lcg(state: &mut u32) -> f32 {
*state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
((*state >> 8) as f32 / (1u32 << 24) as f32) * 2.0 - 1.0
}
fn sig(name: &str, pcm: Vec<f32>) -> Signal {
Signal {
name: name.to_string(),
sample_rate: SR,
channels: 1,
pcm,
}
}
pub fn tone(freq: f32) -> Signal {
let pcm = (0..LEN)
.map(|i| 0.5 * (2.0 * PI * freq * i as f32 / SR as f32).sin())
.collect();
sig(&format!("tone-{}hz", freq as u32), pcm)
}
pub fn two_tones(f1: f32, f2: f32) -> Signal {
let pcm = (0..LEN)
.map(|i| {
let t = i as f32 / SR as f32;
0.35 * (2.0 * PI * f1 * t).sin() + 0.35 * (2.0 * PI * f2 * t).sin()
})
.collect();
sig(&format!("two-tones-{}+{}", f1 as u32, f2 as u32), pcm)
}
pub fn sweep(f0: f32, f1: f32) -> Signal {
let mut phase = 0.0f32;
let mut pcm = Vec::with_capacity(LEN);
for i in 0..LEN {
let frac = i as f32 / LEN as f32;
let f = f0 + (f1 - f0) * frac;
phase += 2.0 * PI * f / SR as f32;
pcm.push(0.5 * phase.sin());
}
sig("sweep", pcm)
}
pub fn white(seed: u32) -> Signal {
let mut s = seed;
let pcm = (0..LEN).map(|_| 0.4 * lcg(&mut s)).collect();
sig("white-noise", pcm)
}
pub fn transient() -> Signal {
let mut s = 0x1234_5678u32;
let pcm = (0..LEN)
.map(|i| {
if i < LEN / 2 {
0.0
} else {
let k = (i - LEN / 2) as f32;
0.9 * lcg(&mut s) * (-k / 256.0).exp()
}
})
.collect();
sig("transient", pcm)
}
pub fn dc() -> Signal {
sig("dc", vec![0.3; LEN])
}
pub fn corpus() -> Vec<Signal> {
vec![
tone(1000.0),
two_tones(440.0, 5000.0),
sweep(50.0, 18_000.0),
white(0xC0FFEE),
transient(),
dc(),
]
}
pub fn by_name(name: &str) -> Option<Signal> {
corpus().into_iter().find(|s| s.name == name)
}