use awsm_audio_schema::NoiseFlavor;
use fastrand::Rng;
pub fn generate(
flavor: NoiseFlavor,
seed: u64,
len: usize,
sample_rate: f32,
density: f32,
gaussian: bool,
) -> Vec<f32> {
let mut rng = Rng::with_seed(seed);
let mut out = match flavor {
NoiseFlavor::White => white(&mut rng, len, gaussian),
NoiseFlavor::Pink => pink(&mut rng, len, gaussian),
NoiseFlavor::Brown => brown(&mut rng, len, gaussian),
NoiseFlavor::Violet => violet(&mut rng, len, gaussian),
NoiseFlavor::Blue => blue(&mut rng, len, gaussian),
NoiseFlavor::Dust => dust(&mut rng, len, sample_rate, density),
NoiseFlavor::Velvet => velvet(&mut rng, len, sample_rate, density),
};
normalize(&mut out, 0.9);
out
}
fn white_sample(rng: &mut Rng, gaussian: bool) -> f32 {
if gaussian {
let s: f32 = (0..4).map(|_| rng.f32() * 2.0 - 1.0).sum();
s * 0.5
} else {
rng.f32() * 2.0 - 1.0
}
}
fn white(rng: &mut Rng, len: usize, gaussian: bool) -> Vec<f32> {
(0..len).map(|_| white_sample(rng, gaussian)).collect()
}
fn pink(rng: &mut Rng, len: usize, gaussian: bool) -> Vec<f32> {
let (mut b0, mut b1, mut b2) = (0.0f32, 0.0f32, 0.0f32);
(0..len)
.map(|_| {
let w = white_sample(rng, gaussian);
b0 = 0.997_76 * b0 + w * 0.099_046;
b1 = 0.963_00 * b1 + w * 0.296_516_4;
b2 = 0.570_00 * b2 + w * 1.052_691_3;
(b0 + b1 + b2 + w * 0.184_8) * 0.2
})
.collect()
}
fn brown(rng: &mut Rng, len: usize, gaussian: bool) -> Vec<f32> {
let mut last = 0.0f32;
(0..len)
.map(|_| {
let w = white_sample(rng, gaussian);
last = (last + 0.02 * w) / 1.02;
last * 3.5
})
.collect()
}
fn violet(rng: &mut Rng, len: usize, gaussian: bool) -> Vec<f32> {
let mut prev = 0.0f32;
(0..len)
.map(|_| {
let w = white_sample(rng, gaussian);
let v = w - prev;
prev = w;
v
})
.collect()
}
fn blue(rng: &mut Rng, len: usize, gaussian: bool) -> Vec<f32> {
let p = pink(rng, len, gaussian);
let mut prev = 0.0f32;
p.into_iter()
.map(|x| {
let v = x - prev;
prev = x;
v
})
.collect()
}
fn dust(rng: &mut Rng, len: usize, sample_rate: f32, density: f32) -> Vec<f32> {
let prob = (density / sample_rate).clamp(0.0, 1.0);
(0..len)
.map(|_| {
if (rng.f32()) < prob {
rng.f32() * 2.0 - 1.0
} else {
0.0
}
})
.collect()
}
fn velvet(rng: &mut Rng, len: usize, sample_rate: f32, density: f32) -> Vec<f32> {
let mut out = vec![0.0f32; len];
let window = ((sample_rate / density.max(1.0)) as usize).max(1);
let mut i = 0;
while i < len {
let pos = i + rng.usize(0..window);
if pos < len {
out[pos] = if rng.bool() { 1.0 } else { -1.0 };
}
i += window;
}
out
}
fn normalize(samples: &mut [f32], peak: f32) {
let max = samples.iter().fold(0.0f32, |m, &x| m.max(x.abs()));
if max > 1e-9 {
let g = peak / max;
for x in samples.iter_mut() {
*x *= g;
}
}
}