use crate::codecs::g729::impls::dsp::arith32::l_add;
use crate::codecs::g729::impls::dsp::types::{DspContext, Word16, Word32, MAX_16, MIN_16};
#[inline(always)]
pub fn sature(ctx: &mut DspContext, l_var1: Word32) -> Word16 {
if l_var1.0 > i32::from(MAX_16) {
ctx.overflow = true;
Word16(MAX_16)
} else if l_var1.0 < i32::from(MIN_16) {
ctx.overflow = true;
Word16(MIN_16)
} else {
ctx.overflow = false;
Word16(l_var1.0 as i16)
}
}
#[inline(always)]
pub fn add(ctx: &mut DspContext, var1: Word16, var2: Word16) -> Word16 {
let l_sum = i32::from(var1.0) + i32::from(var2.0);
sature(ctx, Word32(l_sum))
}
#[inline(always)]
pub fn sub(ctx: &mut DspContext, var1: Word16, var2: Word16) -> Word16 {
let l_diff = i32::from(var1.0) - i32::from(var2.0);
sature(ctx, Word32(l_diff))
}
#[inline(always)]
pub fn abs_s(_ctx: &mut DspContext, var1: Word16) -> Word16 {
if var1.0 == MIN_16 {
Word16(MAX_16)
} else if var1.0 < 0 {
Word16(-var1.0)
} else {
var1
}
}
#[inline(always)]
pub fn negate(_ctx: &mut DspContext, var1: Word16) -> Word16 {
if var1.0 == MIN_16 {
Word16(MAX_16)
} else {
Word16(-var1.0)
}
}
#[inline(always)]
pub const fn extract_h(l_var1: Word32) -> Word16 {
Word16((l_var1.0 >> 16) as i16)
}
#[inline(always)]
pub const fn extract_l(l_var1: Word32) -> Word16 {
Word16(l_var1.0 as i16)
}
#[inline(always)]
pub fn round(ctx: &mut DspContext, l_var1: Word32) -> Word16 {
let l_arrondi = l_add(ctx, l_var1, Word32(0x0000_8000));
extract_h(l_arrondi)
}
#[inline(always)]
pub fn mult(ctx: &mut DspContext, var1: Word16, var2: Word16) -> Word16 {
let p = i32::from(var1.0).wrapping_mul(i32::from(var2.0)) as u32;
let mut l_prod = ((p & 0xFFFF_8000) >> 15) as i32;
if (l_prod & 0x0001_0000) != 0 {
l_prod |= !0x0000_FFFF;
}
sature(ctx, Word32(l_prod))
}
#[inline(always)]
pub fn mult_r(ctx: &mut DspContext, var1: Word16, var2: Word16) -> Word16 {
let p = i32::from(var1.0).wrapping_mul(i32::from(var2.0));
let mut l_prod = (p.wrapping_add(0x0000_4000) as u32) & 0xFFFF_8000;
l_prod >>= 15;
let mut signed = l_prod as i32;
if (signed & 0x0001_0000) != 0 {
signed |= !0x0000_FFFF;
}
sature(ctx, Word32(signed))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dsp_add_saturates() {
let mut ctx = DspContext::default();
let r = add(&mut ctx, Word16(MAX_16), Word16(1));
assert_eq!(r.0, MAX_16);
assert!(ctx.overflow);
}
#[test]
fn dsp_mult_corner_min_min() {
let mut ctx = DspContext::default();
let r = mult(&mut ctx, Word16(MIN_16), Word16(MIN_16));
assert_eq!(r.0, MAX_16);
assert!(ctx.overflow);
}
#[test]
fn dsp_round_matches_reference_shape() {
let mut ctx = DspContext::default();
let r = round(&mut ctx, Word32(0x0001_7FFF));
assert_eq!(r.0, 1);
let r2 = round(&mut ctx, Word32(0x0001_8000));
assert_eq!(r2.0, 2);
}
}