pub const DB_PER_OCTAVE: i16 = 24660;
#[inline]
pub fn acc(v: i64) -> i64 {
(v << 24) >> 24
}
#[inline]
pub fn sat(v: i64) -> i64 {
v.clamp(i32::MIN as i64, i32::MAX as i64)
}
#[inline]
pub fn hi(v: i64) -> i16 {
(v >> 16) as i16
}
#[inline]
pub fn low(v: i64) -> i16 {
v as i16
}
#[inline]
pub fn mul(x: i16, y: i16) -> i64 {
(x as i64) * (y as i64) * 2
}
#[inline]
pub fn mul_uu(x: i16, y: i16) -> i64 {
(x as u16 as i64) * (y as u16 as i64) * 2
}
#[inline]
pub fn mul_us(x: i16, y: i16) -> i64 {
(x as u16 as i64) * (y as i64) * 2
}
#[inline]
pub fn mul32x16(x: i64, y: i16) -> i64 {
let partial = acc(mul_us(low(x), y)) >> 16;
acc(partial + mul(hi(x), y))
}
#[inline]
pub fn scale32(x: i64, y: i16) -> i64 {
let low_half = ((x as u32 as u16) >> 1) as i64;
let partial = sat(shift(sat(shift(sat(low_half * (y as i64) * 2), -16)), 1));
sat(acc(partial + (hi(x) as i64) * (y as i64) * 2))
}
pub fn mul32(x: i64, y: i64) -> i64 {
let (xl, yl) = (low(x), low(y));
let (xh, yh) = (hi(x), hi(y));
let mut a = shift(acc(mul_uu(xl, yl)), -16);
a = acc(a + mul_us(xl, yh));
a = acc(a + mul_us(yl, xh));
a = shift(a, -16);
acc(a + mul(xh, yh))
}
#[inline]
pub fn square32(v: i64) -> i64 {
mul32(v, v)
}
#[inline]
pub fn round(v: i64) -> i64 {
acc(v + 0x8000) & !0xffff
}
#[inline]
pub fn mulr(x: i16, y: i16) -> i64 {
round(sat(mul(x, y)))
}
#[inline]
pub fn trunc32(v: i64) -> i64 {
v as i32 as i64
}
#[inline]
pub fn norm_shift(amount: i32) -> i32 {
let ts = amount & 0x3f;
if ts & 0x20 != 0 { ts - 64 } else { ts }
}
#[inline]
pub fn norm(v: i64, amount: i16) -> i64 {
sat(shift(acc(v), norm_shift(amount as i32)))
}
pub fn exp(v: i64) -> i32 {
let v = acc(v);
if v == 0 {
return 0;
}
let mag = if v < 0 { !v } else { v };
let top = 63 - mag.leading_zeros() as i32; 30 - top
}
#[inline]
pub fn shift(v: i64, s: i32) -> i64 {
if s >= 0 { acc(v << s) } else { acc(v >> (-s)) }
}
#[inline]
fn restoring_step(num: i64, den: i16) -> i64 {
let alu = num - ((den as i64) << 15);
acc(if alu >= 0 { (alu << 1) + 1 } else { num << 1 })
}
pub fn restoring_divide(mut num: i64, den: i16, steps: u32) -> i64 {
for _ in 0..steps {
num = restoring_step(num, den);
}
num
}
pub fn normalised_reciprocal(value: i64) -> (i64, i32) {
let e = exp(value);
let shift_out = e + 1;
let normalised = shift(value, e);
let magnitude = sat(if normalised < 0 {
-normalised
} else {
normalised
}) >> 16;
let quotient = restoring_divide((16383i64) << 16, magnitude as i16, 15);
let quotient = acc(((quotient as u64 as i64) & 0xffff) << 16);
if hi(normalised) < 0 {
(acc(-quotient), shift_out)
} else {
(quotient, shift_out)
}
}
pub fn divide(value: i64, numerator: i16) -> i64 {
let negative = value < 0;
let magnitude = if negative { acc(-value) } else { value };
let e = exp(magnitude);
let normalised = shift(magnitude, e);
let quotient = low(restoring_divide((16383i64) << 16, hi(normalised), 15));
let product = acc((quotient as i64) * (numerator as i64) * 2);
shift(if negative { acc(-product) } else { product }, e + 1)
}
pub fn sqrt(value: i64) -> i64 {
let mut r: i16 = 16384;
for step in 0..15 {
let square = acc((r as i64) * (r as i64) * 2);
let bit: i16 = if step == 14 { 0 } else { 0x2000 >> step };
r = r.wrapping_add(bit);
if acc(square - value) > 0 {
r = r.wrapping_sub(if step == 14 { 1 } else { bit << 1 });
}
}
(r as i64) << 16
}
pub fn inverse_sqrt(value: i64) -> i64 {
if acc(value) <= 0 {
return 0x7fffffff;
}
let (quotient, shift_out) = normalised_reciprocal(sqrt(value));
let amount = shift_out - 15;
sat(shift(acc(quotient), amount))
}