use crate::numeric::fixed::Q14;
use crate::numeric::{ring, HISTORY};
pub(super) fn prepare_history<T: Copy>(value: T) -> Box<[T; HISTORY]> {
vec![value; HISTORY]
.into_boxed_slice()
.try_into()
.unwrap_or_else(|_| unreachable!("prepared voice history length"))
}
#[inline]
fn interpolation_indices(center: i32) -> [usize; 3] {
let middle = ring(center);
let left = if middle == 0 { HISTORY - 1 } else { middle - 1 };
let right = if middle + 1 == HISTORY { 0 } else { middle + 1 };
[left, middle, right]
}
fn interpolation_taps<T: Copy>(buffer: &[T; HISTORY], center: i32) -> [T; 3] {
if center > 0 && center < (HISTORY - 1) as i32 {
let center = center as usize;
let taps = &buffer[center - 1..center + 2];
[taps[0], taps[1], taps[2]]
} else {
let [left, middle, right] = interpolation_indices(center);
[buffer[left], buffer[middle], buffer[right]]
}
}
pub(super) fn interpolation(buffer: &[Q14; HISTORY], position: Q14) -> (Q14, i32) {
let bits = position.to_bits();
let center = if position > Q14::ZERO {
bits.wrapping_add(8192) >> 14
} else {
-(8192_i32.wrapping_sub(bits) >> 14)
};
let fraction = Q14::from_bits(bits.wrapping_sub(center.wrapping_shl(14)));
let [left, middle, right] = interpolation_taps(buffer, center);
let curvature = ((left + right) >> 1) - middle;
let slope = (right - left) >> 1;
(
middle + (curvature.mul::<14, 14>(fraction) + slope).mul(fraction),
center,
)
}