use opus_rs::range_coder::RangeCoder;
use opus_rs::silk::dec_api::SilkDecoder;
use opus_rs::silk::decode_frame::FLAG_DECODE_NORMAL;
mod hex {
pub fn encode(data: &[u8]) -> String {
let mut s = String::with_capacity(data.len() * 2);
for &b in data {
let _ = std::fmt::Write::write_fmt(&mut s, format_args!("{:02x}", b));
}
s
}
}
const C_ENCODED_8KHZ_20MS: &[u8] = &[
0x0b, 0x01, 0x84, 0xc1, 0xc1, 0xc7, 0xb6, 0x6f, 0x5e, 0x06, 0xa4, 0xb7, 0x28, 0xc8, 0x1c, 0x95,
0x61, 0x20, 0xe0, 0x78, 0x1c, 0x26, 0x4a, 0x17, 0x60,
];
const C_DECODED_OUTPUT: [i16; 160] = [
0, 0, 0, 0, 0, 96, 88, -40, -221, -254, -140, -137, -50, 143, 196, 308, 312, 170, -49, -142,
-98, -174, -159, -17, 188, 442, 705, 769, 816, 892, 940, 957, 931, 694, 468, 144, -285, -539,
-615, -548, -359, -71, 286, 669, 859, 615, 23, -133, -511, -579, -194, 398, 534, 9881, 17993,
24112, 27741, 27748, 22514, 14768, 6459, -4981, -14998, -22576, -27136, -28032, -28689, -25749,
-19147, -10515, -1472, 6676, 14070, 19202, 22220, 23035, 21366, 16971, 10466, 2930, -4784,
-11799, -19794, -24772, -28815, -29737, -26770, -20986, -12941, -2659, 7189, 16824, 24320,
28228, 28996, 26677, 21352, 13676, 4720, -5720, -15126, -21808, -25876, -26722, -24395, -19678,
-12851, -4686, 3415, 10846, 16881, 20841, 22387, 21458, 18307, 13037, 6373, -430, -6965,
-12590, -16299, -18131, -17694, -15420, -11394, -5332, 1854, 8371, 14311, 18235, 19646, 19002,
15403, 10174, 3355, -3381, -10082, -15317, -18443, -19567, -18499, -14524, -9203, -2225, 5588,
13002, 18315, 21218, 21622, 19489, 14464, 8000, 257, -7033, -14071, -19362, -21837, -21914,
-19643, -15421,
];
fn parse_toc(toc: u8) -> (i32, i32, i32) {
let bandwidth = (toc >> 5) & 0x03;
let config = (toc >> 3) & 0x07;
let frame_count_code = toc & 0x03;
let sample_rate_hz = match bandwidth {
0 => 8000, 1 => 12000, 2 => 16000, _ => 24000, };
(sample_rate_hz, config as i32, frame_count_code as i32)
}
#[test]
fn test_decode_c_encoded_silk_8khz() {
let toc = C_ENCODED_8KHZ_20MS[0];
let (sample_rate_hz, _config, frame_count_code) = parse_toc(toc);
println!("TOC: 0x{:02x}", toc);
println!("Sample rate: {} Hz", sample_rate_hz);
println!("Frame count code: {}", frame_count_code);
assert_eq!(sample_rate_hz, 8000, "Expected 8kHz sample rate");
let mut decoder = SilkDecoder::new();
let ret = decoder.init(sample_rate_hz, 1);
assert_eq!(ret, 0, "Failed to initialize decoder");
let frame_length = decoder.frame_length();
println!("Decoder frame length: {}", frame_length);
assert_eq!(frame_length, 160, "Expected 160 samples frame length");
let silk_payload = &C_ENCODED_8KHZ_20MS[1..];
println!("SILK payload: {} bytes", silk_payload.len());
println!("SILK hex: {}", hex::encode(silk_payload));
let mut range_coder = RangeCoder::new_decoder(silk_payload.to_vec());
let mut output = vec![0i16; 160];
let n_samples = decoder.decode(
&mut range_coder,
&mut output,
FLAG_DECODE_NORMAL,
true,
20,
8000,
);
println!("Decoded {} samples", n_samples);
println!();
println!("=== Comparison with C reference ===");
println!("Rust output [0..20]: {:?}", &output[..20]);
println!("C reference [0..20]: {:?}", &C_DECODED_OUTPUT[..20]);
println!();
let sum_sq: i64 = output[..n_samples as usize]
.iter()
.map(|&x| (x as i64) * (x as i64))
.sum();
let rust_rms = ((sum_sq as f64) / (n_samples as f64)).sqrt();
let c_sum_sq: i64 = C_DECODED_OUTPUT
.iter()
.map(|&x| (x as i64) * (x as i64))
.sum();
let c_rms = ((c_sum_sq as f64) / (C_DECODED_OUTPUT.len() as f64)).sqrt();
println!("Rust RMS energy: {:.2}", rust_rms);
println!("C reference RMS: {:.2}", c_rms);
println!("RMS ratio: {:.4}", rust_rms / c_rms);
println!();
let mut dot_product: i64 = 0;
let mut rust_norm: i64 = 0;
let mut c_norm: i64 = 0;
for i in 0..n_samples as usize {
dot_product += (output[i] as i64) * (C_DECODED_OUTPUT[i] as i64);
rust_norm += (output[i] as i64) * (output[i] as i64);
c_norm += (C_DECODED_OUTPUT[i] as i64) * (C_DECODED_OUTPUT[i] as i64);
}
let correlation = if rust_norm > 0 && c_norm > 0 {
(dot_product as f64) / ((rust_norm as f64).sqrt() * (c_norm as f64).sqrt())
} else {
0.0
};
println!("Correlation: {:.4}", correlation);
let non_zero_count = output[..n_samples as usize]
.iter()
.filter(|&&x| x != 0)
.count();
println!("Non-zero samples: {} / {}", non_zero_count, n_samples);
assert!(non_zero_count > 0, "Output is all zeros");
}
#[test]
fn test_decode_synth_16khz() {
let sample_rate = 16000;
let frame_size = 320;
let mut decoder = SilkDecoder::new();
let ret = decoder.init(sample_rate, 1);
assert_eq!(ret, 0, "Failed to initialize decoder");
assert_eq!(decoder.frame_length(), frame_size);
let toc: u8 = 0b10_001_0_00; println!("TOC for 16kHz 20ms: 0x{:02x}", toc);
println!("Decoder initialized successfully for 16kHz");
}
#[test]
fn test_decoder_reset() {
let mut decoder = SilkDecoder::new();
let ret = decoder.init(16000, 1);
assert_eq!(ret, 0, "Init 16kHz failed");
assert_eq!(decoder.sample_rate(), 16000);
decoder.reset();
let ret = decoder.init(8000, 1);
assert_eq!(ret, 0, "Init 8kHz failed");
assert_eq!(decoder.sample_rate(), 8000);
assert_eq!(decoder.channel_state[0].first_frame_after_reset, 1);
}
#[test]
fn test_decoder_invalid_sample_rate() {
let mut decoder = SilkDecoder::new();
let ret = decoder.init(48000, 1);
assert!(ret < 0, "Should reject 48kHz");
let ret = decoder.init(44100, 1);
assert!(ret < 0, "Should reject 44.1kHz");
let ret = decoder.init(24000, 1);
assert!(ret < 0, "Should reject 24kHz");
}