1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum SilkBandwidth {
11 NarrowBand,
13 MediumBand,
15 WideBand,
17 SuperWideBand,
19}
20
21impl SilkBandwidth {
22 pub fn sample_rate(&self) -> u32 {
24 match self {
25 Self::NarrowBand => 8_000,
26 Self::MediumBand => 12_000,
27 Self::WideBand => 16_000,
28 Self::SuperWideBand => 24_000,
29 }
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq)]
35pub struct SilkFrameHeader {
36 pub vad_flag: bool,
38 pub lbrr_flag: bool,
40 pub signal_type: u8,
42 pub quantization_offset: u8,
44}
45
46impl SilkFrameHeader {
47 pub fn parse(data: &[u8]) -> Result<Self, String> {
62 if data.is_empty() {
63 return Err("SILK frame data is empty".to_string());
64 }
65
66 let b0 = data[0];
67
68 let vad_flag = (b0 & 0x80) != 0;
69 let lbrr_flag = (b0 & 0x40) != 0;
70 let raw_signal = (b0 >> 4) & 0x03;
71 let signal_type = if raw_signal > 2 { 0 } else { raw_signal };
72 let quantization_offset = (b0 >> 3) & 0x01;
73
74 Ok(Self {
75 vad_flag,
76 lbrr_flag,
77 signal_type,
78 quantization_offset,
79 })
80 }
81}
82
83#[derive(Debug, Clone)]
88pub struct SilkLpcCoeffs {
89 pub order: usize,
91 pub coeffs: Vec<i16>,
93}
94
95impl SilkLpcCoeffs {
96 pub fn new(order: usize) -> Self {
98 Self {
99 order,
100 coeffs: vec![0i16; order],
101 }
102 }
103}
104
105#[derive(Debug, Clone)]
107pub struct SilkFrame {
108 pub header: SilkFrameHeader,
110 pub lpc: SilkLpcCoeffs,
112 pub samples: Vec<i16>,
114 pub sample_count: usize,
116}
117
118impl SilkFrame {
119 pub fn new() -> Self {
121 Self {
122 header: SilkFrameHeader {
123 vad_flag: false,
124 lbrr_flag: false,
125 signal_type: 0,
126 quantization_offset: 0,
127 },
128 lpc: SilkLpcCoeffs::new(16),
129 samples: Vec::new(),
130 sample_count: 0,
131 }
132 }
133
134 pub fn sample_count(&self) -> usize {
136 self.sample_count
137 }
138
139 pub fn as_f32_samples(&self) -> Vec<f32> {
141 self.samples
142 .iter()
143 .map(|&s| s as f32 / i16::MAX as f32)
144 .collect()
145 }
146}
147
148#[derive(Debug)]
155pub struct SilkDecoder {
156 pub bandwidth: SilkBandwidth,
158 pub frame_size: usize,
160 pub prev_samples: Vec<i16>,
162}
163
164impl SilkDecoder {
165 pub fn new(bandwidth: SilkBandwidth) -> Self {
167 let frame_size = (bandwidth.sample_rate() as usize) * 20 / 1000;
169 let lpc_order = match bandwidth {
171 SilkBandwidth::NarrowBand | SilkBandwidth::MediumBand => 10,
172 SilkBandwidth::WideBand | SilkBandwidth::SuperWideBand => 16,
173 };
174 Self {
175 bandwidth,
176 frame_size,
177 prev_samples: vec![0i16; lpc_order],
178 }
179 }
180
181 pub fn decode_frame(&mut self, data: &[u8]) -> Result<SilkFrame, String> {
188 let header = SilkFrameHeader::parse(data)?;
189
190 let lpc_order = self.prev_samples.len();
191 let lpc = SilkLpcCoeffs::new(lpc_order);
192
193 let samples = vec![0i16; self.frame_size];
194 let sample_count = self.frame_size;
195
196 Ok(SilkFrame {
197 header,
198 lpc,
199 samples,
200 sample_count,
201 })
202 }
203
204 pub fn apply_lpc_synthesis(&mut self, excitation: &[i16], lpc: &SilkLpcCoeffs) -> Vec<i16> {
216 let order = lpc.order;
217 let n = excitation.len();
218 let mut output = vec![0i16; n];
219
220 let history: Vec<i16> = self.prev_samples.clone();
223
224 for i in 0..n {
225 let mut acc: i64 = excitation[i] as i64;
226 for k in 0..order {
227 let back = k + 1;
229 let sample = if back <= i {
230 output[i - back] as i64
231 } else {
232 let hist_idx = order as isize - (back as isize - i as isize);
234 if hist_idx >= 0 && (hist_idx as usize) < history.len() {
235 history[hist_idx as usize] as i64
236 } else {
237 0i64
238 }
239 };
240 acc += (lpc.coeffs[k] as i64 * sample) >> 12;
241 }
242 output[i] = acc.clamp(i16::MIN as i64, i16::MAX as i64) as i16;
243 }
244
245 let keep = order.min(n);
247 let src_start = n - keep;
248 for (dst, src) in self.prev_samples[order - keep..]
249 .iter_mut()
250 .zip(output[src_start..].iter())
251 {
252 *dst = *src;
253 }
254
255 output
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn test_silk_bandwidth_sample_rate_narrowband() {
265 assert_eq!(SilkBandwidth::NarrowBand.sample_rate(), 8_000);
266 }
267
268 #[test]
269 fn test_silk_bandwidth_sample_rate_mediumband() {
270 assert_eq!(SilkBandwidth::MediumBand.sample_rate(), 12_000);
271 }
272
273 #[test]
274 fn test_silk_bandwidth_sample_rate_wideband() {
275 assert_eq!(SilkBandwidth::WideBand.sample_rate(), 16_000);
276 }
277
278 #[test]
279 fn test_silk_bandwidth_sample_rate_superwideband() {
280 assert_eq!(SilkBandwidth::SuperWideBand.sample_rate(), 24_000);
281 }
282
283 #[test]
284 fn test_silk_frame_header_parse_basic() {
285 let data = [0x90u8];
288 let hdr = SilkFrameHeader::parse(&data).expect("should succeed");
289 assert!(hdr.vad_flag);
290 assert!(!hdr.lbrr_flag);
291 assert_eq!(hdr.signal_type, 1);
292 assert_eq!(hdr.quantization_offset, 0);
293 }
294
295 #[test]
296 fn test_silk_frame_header_parse_empty_returns_error() {
297 let result = SilkFrameHeader::parse(&[]);
298 assert!(result.is_err());
299 }
300
301 #[test]
302 fn test_silk_decoder_new() {
303 let dec = SilkDecoder::new(SilkBandwidth::WideBand);
304 assert_eq!(dec.bandwidth, SilkBandwidth::WideBand);
305 assert_eq!(dec.frame_size, 320);
307 }
308
309 #[test]
310 fn test_silk_decoder_decode_frame() {
311 let mut dec = SilkDecoder::new(SilkBandwidth::NarrowBand);
312 let data = [0x00u8; 10];
313 let frame = dec.decode_frame(&data).expect("should succeed");
314 assert_eq!(frame.sample_count(), 160);
316 assert_eq!(frame.samples.len(), 160);
317 }
318
319 #[test]
320 fn test_silk_lpc_synthesis_zero_excitation_gives_zero_output() {
321 let mut dec = SilkDecoder::new(SilkBandwidth::NarrowBand);
322 let excitation = vec![0i16; 160];
323 let lpc = SilkLpcCoeffs::new(10);
324 let output = dec.apply_lpc_synthesis(&excitation, &lpc);
325 assert!(output.iter().all(|&s| s == 0));
326 }
327
328 #[test]
329 fn test_silk_frame_as_f32_samples_i16_max() {
330 let mut frame = SilkFrame::new();
331 frame.samples = vec![i16::MAX];
332 frame.sample_count = 1;
333 let f32s = frame.as_f32_samples();
334 assert!((f32s[0] - 1.0f32).abs() < 1e-4);
335 }
336
337 #[test]
338 fn test_silk_frame_as_f32_samples_i16_min() {
339 let mut frame = SilkFrame::new();
340 frame.samples = vec![i16::MIN];
341 frame.sample_count = 1;
342 let f32s = frame.as_f32_samples();
343 assert!(f32s[0] < -0.999);
345 }
346
347 #[test]
348 fn test_silk_lpc_coeffs_new() {
349 let lpc = SilkLpcCoeffs::new(10);
350 assert_eq!(lpc.order, 10);
351 assert_eq!(lpc.coeffs.len(), 10);
352 assert!(lpc.coeffs.iter().all(|&c| c == 0));
353 }
354}