opus-rs 0.1.7

pure Rust implementation of Opus codec
Documentation
#[inline(always)]
pub fn silk_rshift64(a: i64, shift: i32) -> i64 {
    a >> shift
}

/// silk_LSHIFT_SAT32: left shift with saturation to i32 range
#[inline(always)]
pub fn silk_lshift_sat32(a: i32, shift: i32) -> i32 {
    let result = (a as i64) << shift;
    if result > i32::MAX as i64 {
        i32::MAX
    } else if result < i32::MIN as i64 {
        i32::MIN
    } else {
        result as i32
    }
}

#[inline(always)]
pub fn silk_add_pos_sat32(a: i32, b: i32) -> i32 {
    let res = (a as i64) + (b as i64);
    if res > i32::MAX as i64 {
        i32::MAX
    } else if res < i32::MIN as i64 {
        i32::MIN
    } else {
        res as i32
    }
}

#[inline(always)]
pub fn silk_smlaww_64(a: i64, b: i64, c: i32) -> i64 {
    a.wrapping_add((b * (c as i64)) >> 16)
}

#[inline(always)]
pub fn silk_smulww(a: i32, b: i32) -> i32 {
    (((a as i64) * (b as i64)) >> 16) as i32
}

#[inline(always)]
pub fn silk_smlaww(a: i32, b: i32, c: i32) -> i32 {
    a.wrapping_add(silk_smulww(b, c))
}

#[inline(always)]
pub fn silk_rshift_round(a: i32, shift: i32) -> i32 {
    if shift <= 0 {
        return a << -shift;
    }
    if shift >= 31 {
        return 0;
    }
    (a >> shift) + ((a >> (shift - 1)) & 1)
}

#[inline(always)]
pub fn silk_rshift_round64(a: i64, shift: i32) -> i64 {
    if shift <= 0 {
        return a << -shift;
    }
    (a >> shift) + ((a >> (shift - 1)) & 1)
}

#[inline(always)]
pub fn silk_add_rshift(a: i32, b: i32, shift: i32) -> i32 {
    a.wrapping_add(b >> shift)
}

#[inline(always)]
pub fn silk_div32_16(a: i32, b: i32) -> i32 {
    a / b
}

#[inline(always)]
pub fn silk_div32_varq(vin: i32, vdiv: i32, qout: i32) -> i32 {
    if vdiv == 0 {
        return i32::MAX;
    }
    (((vin as i64) << qout) / (vdiv as i64)) as i32
}

#[inline(always)]
pub fn silk_div32(a: i32, b: i32) -> i32 {
    a / b
}

#[inline(always)]
pub fn silk_limit(a: i32, limit_low: i32, limit_high: i32) -> i32 {
    silk_limit_32(a, limit_low, limit_high)
}

#[inline(always)]
pub fn silk_limit_int(a: i32, limit_low: i32, limit_high: i32) -> i32 {
    silk_limit_32(a, limit_low, limit_high)
}

#[inline(always)]
pub fn silk_smulbb(a: i32, b: i32) -> i32 {
    (a as i16 as i32) * (b as i16 as i32)
}

#[inline(always)]
pub fn silk_smulwb(a: i32, b: i32) -> i32 {
    (((a as i64) * (b as i16 as i64)) >> 16) as i32
}

#[inline(always)]
pub fn silk_smlawb(a: i32, b: i32, c: i32) -> i32 {
    a.wrapping_add(silk_smulwb(b, c))
}

#[inline(always)]
pub fn silk_smulwt(a: i32, b: i32) -> i32 {
    ((a as i64 * (b as i64 >> 16)) >> 16) as i32
}

#[inline(always)]
pub fn silk_smlawt(a: i32, b: i32, c: i32) -> i32 {
    a.wrapping_add(silk_smulwt(b, c))
}

#[inline(always)]
pub fn silk_smlabb(a: i32, b: i32, c: i32) -> i32 {
    a.wrapping_add((b as i16 as i32).wrapping_mul(c as i16 as i32))
}

#[inline(always)]
pub fn silk_mla(a: i32, b: i32, c: i32) -> i32 {
    a.wrapping_add(b.wrapping_mul(c))
}

#[inline(always)]
pub fn silk_mul(a: i32, b: i32) -> i32 {
    a.wrapping_mul(b)
}

#[inline(always)]
pub fn silk_rshift(a: i32, shift: i32) -> i32 {
    a >> shift
}

#[inline(always)]
pub fn silk_rshift32(a: i32, shift: i32) -> i32 {
    a >> shift
}

#[inline(always)]
pub fn silk_lshift(a: i32, shift: i32) -> i32 {
    a << shift
}

#[inline(always)]
pub fn silk_sub_rshift32(a: i32, b: i32, shift: i32) -> i32 {
    a.wrapping_sub(b >> shift)
}

#[inline(always)]
pub fn silk_smulll(a: i64, b: i64) -> i64 {
    a.wrapping_mul(b)
}

#[inline(always)]
pub fn silk_smull(a: i32, b: i32) -> i64 {
    (a as i64) * (b as i64)
}

#[inline(always)]
pub fn silk_smmul(a: i32, b: i32) -> i32 {
    (((a as i64) * (b as i64)) >> 32) as i32
}

#[inline(always)]
pub fn silk_clz32(a: i32) -> i32 {
    a.leading_zeros() as i32
}

#[inline(always)]
pub fn silk_clz64(a: i64) -> i32 {
    a.leading_zeros() as i32
}

#[inline(always)]
pub fn silk_inverse32_varq(vin: i32, qout: i32) -> i32 {
    if vin == 0 {
        return i32::MAX;
    }
    ((1i64 << qout) / (vin as i64)) as i32
}

#[inline(always)]
pub fn silk_clz_frac(input: i32, lz: &mut i32, frac_q7: &mut i32) {
    let lzeros = silk_clz32(input);
    *lz = lzeros;
    *frac_q7 = (input.rotate_right((24 - lzeros) as u32)) & 0x7f;
}

#[inline(always)]
pub fn silk_sqrt_approx(x: i32) -> i32 {
    let mut y: i32;
    let mut lz = 0;
    let mut frac_q7 = 0;

    if x <= 0 {
        return 0;
    }

    silk_clz_frac(x, &mut lz, &mut frac_q7);

    if (lz & 1) != 0 {
        y = 32768;
    } else {
        y = 46214; /* 46214 = sqrt(2) * 32768 */
    }

    /* get scaling right */
    y >>= lz >> 1;

    /* increment using fractional part of input */
    y = silk_smlawb(y, y, silk_smulbb(213, frac_q7));

    y
}

#[inline(always)]
pub fn silk_min_int(a: i32, b: i32) -> i32 {
    if a < b { a } else { b }
}

#[inline(always)]
pub fn silk_max_int(a: i32, b: i32) -> i32 {
    if a > b { a } else { b }
}

#[inline(always)]
pub fn silk_max_32(a: i32, b: i32) -> i32 {
    silk_max_int(a, b)
}

#[inline(always)]
pub fn silk_sat16(a: i32) -> i32 {
    if a > i16::MAX as i32 {
        i16::MAX as i32
    } else if a < i16::MIN as i32 {
        i16::MIN as i32
    } else {
        a
    }
}

#[inline(always)]
pub fn silk_add_sat16(a: i16, b: i16) -> i16 {
    let res = (a as i32) + (b as i32);
    if res > i16::MAX as i32 {
        i16::MAX
    } else if res < i16::MIN as i32 {
        i16::MIN
    } else {
        res as i16
    }
}

#[inline(always)]
pub fn silk_add_sat32(a: i32, b: i32) -> i32 {
    let res = (a as i64) + (b as i64);
    if res > i32::MAX as i64 {
        i32::MAX
    } else if res < i32::MIN as i64 {
        i32::MIN
    } else {
        res as i32
    }
}

#[inline(always)]
pub fn silk_rand(seed: i32) -> i32 {
    // silk_MLA_ovflw(RAND_INCREMENT, seed, RAND_MULTIPLIER)
    // Uses wrapping (unsigned) arithmetic, matching C's silk_ADD32_ovflw
    (907633515u32.wrapping_add((seed as u32).wrapping_mul(196314165u32))) as i32
}

#[inline(always)]
pub fn silk_add32_ovflw(a: i32, b: i32) -> i32 {
    a.wrapping_add(b)
}

#[inline(always)]
pub fn silk_sub32_ovflw(a: i32, b: i32) -> i32 {
    a.wrapping_sub(b)
}

#[inline(always)]
pub fn silk_add32(a: i32, b: i32) -> i32 {
    a.wrapping_add(b)
}

#[inline(always)]
pub fn silk_sub32(a: i32, b: i32) -> i32 {
    a.wrapping_sub(b)
}

#[inline(always)]
pub fn silk_sub_sat32(a1: i32, a2: i32) -> i32 {
    let res = (a1 as i64) - (a2 as i64);
    if res > i32::MAX as i64 {
        i32::MAX
    } else if res < i32::MIN as i64 {
        i32::MIN
    } else {
        res as i32
    }
}

#[inline(always)]
pub fn silk_sub_lshift32(a: i32, b: i32, shift: i32) -> i32 {
    a.wrapping_sub(b << shift)
}

#[inline(always)]
pub fn silk_limit_32(a: i32, low: i32, high: i32) -> i32 {
    if a < low {
        low
    } else if a > high {
        high
    } else {
        a
    }
}

#[inline(always)]
pub fn silk_add_lshift32(a: i32, b: i32, shift: i32) -> i32 {
    a.wrapping_add(b << shift)
}

#[inline(always)]
pub fn silk_min_32(a: i32, b: i32) -> i32 {
    if a < b { a } else { b }
}

#[inline(always)]
pub fn silk_add_rshift32(a: i32, b: i32, shift: i32) -> i32 {
    a.wrapping_add(b >> shift)
}

#[inline(always)]
pub fn silk_lin2log(gain_q16: i32) -> i32 {
    if gain_q16 <= 0 {
        return 0;
    }
    let mut lz = 0;
    let mut frac_q7 = 0;
    silk_clz_frac(gain_q16, &mut lz, &mut frac_q7);
    // Piece-wise parabolic approximation (matching C's silk/lin2log.c)
    silk_smlawb(frac_q7, silk_mul(frac_q7, 128 - frac_q7), 179) + silk_lshift(31 - lz, 7)
}

#[inline(always)]
pub fn silk_log2lin(log_gain_q7: i32) -> i32 {
    if log_gain_q7 < 0 {
        return 0;
    }
    if log_gain_q7 >= 3967 {
        return i32::MAX;
    }
    let out = silk_lshift(1, log_gain_q7 >> 7);
    let frac_q7 = log_gain_q7 & 0x7F;
    // Piece-wise parabolic approximation (matching C's silk/log2lin.c)
    let val = silk_smlawb(frac_q7, silk_smulbb(frac_q7, 128 - frac_q7), -174);
    if log_gain_q7 < 2048 {
        silk_add_rshift32(out, silk_mul(out, val), 7)
    } else {
        out + silk_mul(out >> 7, val)
    }
}