#![feature(test)]
extern crate test;
use lac::{decode_frame, encode_frame};
use test::Bencher;
fn silence(n: usize) -> Vec<i32> {
vec![0i32; n]
}
fn multi_sine(n: usize) -> Vec<i32> {
(0..n)
.map(|i| {
let t = i as f64;
let a = (t * 0.11).sin() * 3_000_000.0;
let b = (t * 0.27).sin() * 1_500_000.0;
let c = (t * 0.43).sin() * 750_000.0;
(a + b + c) as i32
})
.collect()
}
fn lfsr_noise(n: usize, seed: u32) -> Vec<i32> {
let mut state = if seed == 0 { 0xACE1_ACE1 } else { seed };
(0..n)
.map(|_| {
let lsb = state & 1;
state >>= 1;
if lsb != 0 {
state ^= 0x8020_0003;
}
(state as i32) >> 12
})
.collect()
}
fn pseudo_speech(n: usize) -> Vec<i32> {
const A1_Q14: i64 = 30_933;
const A2_Q14: i64 = -15_751;
let excitation = lfsr_noise(n, 0x5EED);
let mut out = Vec::with_capacity(n);
let mut y1: i64 = 0;
let mut y2: i64 = 0;
for &e in &excitation {
let sum = A1_Q14 * y1 + A2_Q14 * y2;
let ar = (sum + (1 << 13)) >> 14;
let y = ar + e as i64;
let clamped = y.clamp(-((1 << 23) - 1), (1 << 23) - 1);
out.push(clamped as i32);
y2 = y1;
y1 = clamped;
}
out
}
fn filtered_noise(n: usize) -> Vec<i32> {
const POLE_Q15: i64 = 29_491; const ONE_MINUS_POLE_Q15: i64 = (1 << 15) - POLE_Q15;
let excitation = lfsr_noise(n, 0xFEED);
let mut out = Vec::with_capacity(n);
let mut y: i64 = 0;
for &e in &excitation {
let sum = POLE_Q15 * y + ONE_MINUS_POLE_Q15 * e as i64;
y = (sum + (1 << 14)) >> 15;
out.push(y.clamp(-((1 << 23) - 1), (1 << 23) - 1) as i32);
}
out
}
macro_rules! encode_bench {
($name:ident, $signal:ident, $size:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let samples = $signal($size);
b.iter(|| encode_frame(test::black_box(&samples)));
}
};
}
macro_rules! decode_bench {
($name:ident, $signal:ident, $size:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let samples = $signal($size);
let encoded = encode_frame(&samples);
b.iter(|| decode_frame(test::black_box(&encoded)).unwrap());
}
};
}
encode_bench!(encode_silence_960, silence, 960);
encode_bench!(encode_silence_4096, silence, 4096);
encode_bench!(encode_sine_256, multi_sine, 256);
encode_bench!(encode_sine_960, multi_sine, 960);
encode_bench!(encode_sine_1024, multi_sine, 1024);
encode_bench!(encode_sine_2048, multi_sine, 2048);
encode_bench!(encode_sine_2880, multi_sine, 2880);
encode_bench!(encode_sine_4096, multi_sine, 4096);
encode_bench!(encode_speech_320, pseudo_speech, 320);
encode_bench!(encode_speech_960, pseudo_speech, 960);
encode_bench!(encode_speech_2048, pseudo_speech, 2048);
encode_bench!(encode_music_960, filtered_noise, 960);
encode_bench!(encode_music_2048, filtered_noise, 2048);
encode_bench!(encode_music_4096, filtered_noise, 4096);
decode_bench!(decode_silence_4096, silence, 4096);
decode_bench!(decode_sine_960, multi_sine, 960);
decode_bench!(decode_sine_4096, multi_sine, 4096);
decode_bench!(decode_speech_960, pseudo_speech, 960);
decode_bench!(decode_music_2048, filtered_noise, 2048);
macro_rules! compute_residuals_bench {
($name:ident, $order:expr, $len:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let samples = multi_sine($len);
let coeffs: Vec<i16> = (0..$order)
.map(|i| ((i as i16) * 711).wrapping_sub(100))
.collect();
b.iter(|| {
lac::compute_residuals(test::black_box(&samples), test::black_box(&coeffs), 1)
});
}
};
}
compute_residuals_bench!(compute_residuals_order_4_n320, 4, 320);
compute_residuals_bench!(compute_residuals_order_8_n320, 8, 320);
compute_residuals_bench!(compute_residuals_order_16_n320, 16, 320);
compute_residuals_bench!(compute_residuals_order_32_n320, 32, 320);
compute_residuals_bench!(compute_residuals_order_8_n960, 8, 960);
compute_residuals_bench!(compute_residuals_order_32_n960, 32, 960);
compute_residuals_bench!(compute_residuals_order_32_n4096, 32, 4096);