use crate::helpers::misc::*;
pub enum WavetableizeMethod {
Raw,
Smooth,
Supersmooth,
}
pub fn wavetableize(
buffer: &[f32],
matrix_size: (usize, usize),
start: f32,
method: WavetableizeMethod,
) -> Vec<Vec<f32>> {
match method {
WavetableizeMethod::Raw => raw(buffer, matrix_size, start),
WavetableizeMethod::Smooth => smooth(buffer, matrix_size, start),
WavetableizeMethod::Supersmooth => supersmooth(buffer, matrix_size, start),
}
}
fn raw(buffer: &[f32], matrix_size: (usize, usize), start: f32) -> Vec<Vec<f32>> {
let remaining_length = buffer.len() - (buffer.len() as f32 * start) as usize;
let step_size = if remaining_length / matrix_size.1 < matrix_size.0 {
remaining_length / matrix_size.0
} else {
matrix_size.1
};
let mut wavematrix = Vec::new();
let start: usize = (buffer.len() as f32 * start) as usize;
for i in 0..matrix_size.0 {
let offset = start + i * step_size;
wavematrix.push(buffer[offset..offset + matrix_size.1].to_vec());
}
wavematrix
}
fn smooth(buffer: &[f32], matrix_size: (usize, usize), start: f32) -> Vec<Vec<f32>> {
let remaining_length = buffer.len() - (buffer.len() as f32 * start) as usize;
let step_size = if remaining_length / matrix_size.1 < matrix_size.0 {
remaining_length / matrix_size.0
} else {
matrix_size.1
};
let mut wavematrix = Vec::new();
let start: usize = (buffer.len() as f32 * start) as usize;
for i in 0..matrix_size.0 {
let offset = start + i * step_size;
let mut buf = buffer[offset..offset + matrix_size.1].to_vec();
buf.append(&mut buf.clone());
let center = buf.len() / 2;
let smooth_start = center - 8;
for i in smooth_start..smooth_start + 16 {
buf[i] = (buf[i - 3]
+ 2.0 * buf[i - 2]
+ 3.0 * buf[i - 1]
+ 4.0 * buf[i]
+ 3.0 * buf[i + 1]
+ 2.0 * buf[i + 2]
+ buf[i + 3])
/ 16.0;
}
for i in 0..8 {
buf[i] = buf[center + i];
}
buf.truncate(center);
wavematrix.push(buf);
}
wavematrix
}
fn supersmooth(buffer: &[f32], matrix_size: (usize, usize), start_factor: f32) -> Vec<Vec<f32>> {
let remaining_length = buffer.len() - (buffer.len() as f32 * start_factor) as usize;
let step_size = if remaining_length / matrix_size.1 < matrix_size.0 {
remaining_length / matrix_size.0
} else {
matrix_size.1
};
let mut wavematrix = Vec::new();
let start: usize = (buffer.len() as f32 * start_factor) as usize;
for i in 0..matrix_size.0 {
let begin_idx = find_closest_upward_zerocrossing(buffer, start + i * step_size);
let end_idx =
find_closest_downward_zerocrossing(buffer, start + i * step_size + matrix_size.1);
let begin_idx_inv = find_closest_downward_zerocrossing(buffer, start + i * step_size);
let end_idx_inv =
find_closest_upward_zerocrossing(buffer, start + i * step_size + matrix_size.1);
let mut buf = if ((end_idx - begin_idx) as i32 - matrix_size.1 as i32).abs()
> ((end_idx_inv - begin_idx_inv) as i32 - matrix_size.1 as i32).abs()
{
let mut buf = buffer[begin_idx_inv..end_idx_inv + 1].to_vec();
buf = buf.iter_mut().map(|x| *x * -1.0).collect();
buf
} else {
buffer[begin_idx..end_idx + 1].to_vec()
};
buf[0] = 0.0;
buf.push(0.0);
buf.push(0.0);
buf.insert(0, 0.0);
buf = stretch_to_size(&buf, matrix_size.1);
wavematrix.push(buf);
}
wavematrix
}