use serde::{ Serialize, Deserialize };
use simpleio::read_file_into_buffer;
use std::f32::consts::PI;
#[derive(Serialize, Deserialize)]
pub struct WaveTable(f32, usize, usize, Vec<(f32, Vec<f32>)>);
impl Default for WaveTable{
fn default() -> Self{
let hz = 440.0;
let sr = 44100;
let samples = (sr as f32 / hz).round() as usize;
let table = (0.0, (0..samples).map(|s| ((s as f32 / sr as f32) * hz * PI * 2.0).sin())
.collect::<Vec<f32>>());
Self(hz, sr, samples, vec![table])
}
}
fn into_mono(stereo: Vec<i16>) -> Vec<f32>{
let mut mono = Vec::new();
let mut i = 0;
let mut y = 0i32;
for x in stereo{
y += x as i32;
if i == 0{
i = 1;
} else {
i = 0;
mono.push((y / 2) as f32 / i16::MAX as f32);
y = 0;
}
}
mono
}
pub fn parse_wavetable_from_buffer(buffer: &[u8]) -> Option<WaveTable>{
if let Ok(table) = bincode::deserialize(buffer) { Some(table) }
else { None }
}
pub fn read_wavetable_from_file(file: &str) -> Option<WaveTable>{
let buffer = match read_file_into_buffer(file){
Err(_) => { return None; },
Ok(x) => x,
};
parse_wavetable_from_buffer(&buffer)
}
pub fn create_wavetable(stereo: Vec<i16>, sr: usize, hz: f32) -> WaveTable{
let mono = into_mono(stereo);
let max = mono.iter().fold(0.0, |max: f32, v| max.max(v.abs()));
let mono = mono.into_iter().map(|v| v / max).collect::<Vec<_>>();
let samples = (sr as f32 / hz).round() as usize;
let mut waves = vec![(0.0, mono.iter().copied().take(samples).collect::<Vec<_>>())];
let mut t = samples;
loop{
if t + samples >= mono.len() { break; }
waves.push((t as f32 / sr as f32, mono.iter().copied().skip(t).take(samples).collect::<Vec<_>>()));
t *= 2;
}
WaveTable(hz, sr, samples, waves)
}
pub type WaveTableState = (usize, usize, f32);
fn initial_state_internal(waves: &[(f32, Vec<f32>)], t: f32) -> WaveTableState{
let mut a = 0;
let mut b = 0;
let mut diff = 0.0;
if waves.len() > 1{
for (i, (wave_time, _)) in waves.iter().enumerate(){
if t <= *wave_time{
a = i;
b = i + 1;
if b >= waves.len() { a = waves.len() - 2;
b = waves.len() - 1;
}
diff = waves[b].0 - waves[a].0;
break;
}
}
if b == 0{ a = waves.len() - 1;
b = waves.len() - 1;
diff = 0.0;
}
}
(a, b, diff)
}
pub fn initial_state(WaveTable(_, _, _, waves): &WaveTable, t: f32) -> WaveTableState{
initial_state_internal(waves, t)
}
pub fn wavetable_act(WaveTable(waves_hz, _sr, samples, waves): &WaveTable, hz: f32, t: f32, sr: f32, len: usize) -> Vec<f32>{
let mut res = Vec::new();
if waves.is_empty() {
return res;
}
let (mut a, mut b, mut diff) = initial_state_internal(waves, t);
let off = (t * sr) as usize;
let sr_rat = *_sr as f32 / sr;
for i in 0..len{
let tt = t + (i as f32 / sr);
if tt > waves[b].0 && b < waves.len() - 1{
a += 1;
b += 1;
diff = waves[b].0 - waves[a].0;
}
let float_frame = (off + i) as f32 * sr_rat * (hz / waves_hz);
let under = float_frame.floor() as usize % samples;
let above = float_frame.ceil() as usize % samples;
let fract = float_frame.fract();
let a_val = waves[a].1[under] + fract * (waves[a].1[above] - waves[a].1[under]);
let b_val = waves[b].1[under] + fract * (waves[b].1[above] - waves[b].1[under]);
let norm_t = ((tt - waves[a].0) / diff).min(1.0);
let v = a_val + norm_t * (b_val - a_val);
res.push(v);
}
res
}
pub fn wavetable_act_state(WaveTable(waves_hz, _sr, samples, waves): &WaveTable, (a, b, diff): &mut WaveTableState,
hz: f32, t: f32, sr: f32) -> f32{
if waves.is_empty() {
return 0.0;
}
let sr_rat = *_sr as f32 / sr;
if t > waves[*b].0 && *b < waves.len() - 1{
*a += 1;
*b += 1;
*diff = waves[*b].0 - waves[*a].0;
}
let float_frame = t * sr * sr_rat * (hz / waves_hz);
let under = float_frame.floor() as usize % samples;
let above = float_frame.ceil() as usize % samples;
let fract = float_frame.fract();
let a_val = waves[*a].1[under] + fract * (waves[*a].1[above] - waves[*a].1[under]);
let b_val = waves[*b].1[under] + fract * (waves[*b].1[above] - waves[*b].1[under]);
let norm_t = ((t - waves[*a].0) / *diff).min(1.0);
a_val + norm_t * (b_val - a_val)
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}