pub(crate) mod fixed;
pub(crate) mod rng;
mod tables;
use rng::RandomStream;
use tables::{SINC, TAN};
#[inline]
pub(crate) fn mul_shift(a: i32, b: i32, shift: u32) -> i32 {
a.wrapping_mul(b) >> shift
}
#[inline]
pub(crate) fn round_q14(value: i32) -> i32 {
if value >= 0 {
value.wrapping_add(8192) >> 14
} else {
value.wrapping_sub(8192) >> 14
}
}
pub(crate) fn db_to_gain(db: f64) -> f64 {
10.0_f64.powf(db / 20.0)
}
pub(crate) fn coefficient_to_exp_value(min: f32, max: f32, start: f32, position: f32) -> f32 {
let f = max - min;
let g = start - min;
let b = (((g / f) as f64 - 1.0).ln() * 2.0) as f32;
let a = (g as f64 / ((b as f64).exp() - 1.0)) as f32;
(a as f64 * (((b * position) as f64).exp() - 1.0) + min as f64) as f32
}
#[inline]
fn quadratic(y0: i32, y1: i32, y2: i32, fraction: i32) -> i32 {
let a = (y0.wrapping_add(y2) >> 1).wrapping_sub(y1);
let b = y2.wrapping_sub(y0) >> 1;
mul_shift(mul_shift(a, fraction, 14).wrapping_add(b), fraction, 14).wrapping_add(y1)
}
pub(crate) fn fast_sinc(input: i32) -> i32 {
let scaled = (input >> 1).wrapping_mul(256);
let index = (scaled.wrapping_add(8192) >> 14).clamp(1, 254);
let fraction = scaled.wrapping_sub(index.wrapping_shl(14));
let i = index as usize;
quadratic(SINC[i - 1], SINC[i], SINC[i + 1], fraction)
}
#[derive(Debug)]
pub(crate) struct AtanQ14 {
index: usize,
}
impl Default for AtanQ14 {
fn default() -> Self {
Self { index: 1 }
}
}
impl AtanQ14 {
pub(crate) fn process(&mut self, input: i32, shift: u32) -> i32 {
let value = input.wrapping_shl(shift);
let negative = value < 0;
let value = value.wrapping_abs();
if TAN[self.index] > value {
while TAN[self.index - 1] > value {
self.index -= 1;
}
} else {
while self.index <= 298 && TAN[self.index] < value {
self.index += 1;
}
}
let index = self.index;
let angle = if TAN[index] >= value {
let fraction = value.wrapping_sub(TAN[index - 1]).wrapping_mul(64)
/ TAN[index].wrapping_sub(TAN[index - 1]);
((index as i32 - 1) * 16384) / 300 + fraction.wrapping_shl(8) / 300
} else {
0x3fc9
};
let result = mul_shift(angle, 25722, 14);
if negative {
result.wrapping_neg()
} else {
result
}
}
}
pub(crate) fn envelope_decay(milliseconds: f64, rate: f64, window: usize) -> f64 {
let time = milliseconds * 0.001 * rate / window as f64;
0.5_f64.powf(1.0 / time)
}
#[derive(Debug)]
pub(crate) struct NumericContext {
pub atan_q14: AtanQ14,
pub random: RandomStream,
}
impl NumericContext {
pub(crate) fn new(seed: u32) -> Self {
Self {
atan_q14: AtanQ14::default(),
random: RandomStream::new(seed),
}
}
}
pub(crate) const HISTORY: usize = 11_568;
pub(crate) const ONE: i32 = 16_384;
#[inline]
pub(crate) fn mul14(left: i32, right: i32) -> i32 {
left.wrapping_mul(right) >> 14
}
#[inline]
pub(crate) fn ring(index: i32) -> usize {
index.rem_euclid(HISTORY as i32) as usize
}