Skip to main content

melpe/
decoder.rs

1/// MELPe 600 bps Decoder
2///
3/// Accepts 6 bytes of bitstream (1 superframe),
4/// dequantizes, interpolates parameters across 3 frames,
5/// generates mixed excitation, and synthesizes 540 samples.
6
7use crate::core_types::{
8    FrameParams, FRAME_SAMPLES, SUPERFRAME_FRAMES,
9    SUPERFRAME_SAMPLES, SUPERFRAME_BYTES_600, NUM_LSF, NUM_BANDS,
10};
11use crate::bitstream::unpack_superframe;
12use crate::quantize::dequantize_superframe;
13use crate::voicing::{NoiseGen, mixed_excitation};
14use crate::synthesis::SynthesisFrameProcessor;
15
16/// MELPe 600 bps decoder.
17pub struct Decoder {
18    /// Frame-level synthesis processor (filter + de-emphasis + LPC interp)
19    synth: SynthesisFrameProcessor,
20    /// Previous superframe's anchor LSFs (needed for LSF interpolation)
21    prev_anchor_lsf: [f32; NUM_LSF],
22    /// Noise generator for mixed excitation
23    noise: NoiseGen,
24    /// Pulse train phase accumulator (carries across frames)
25    pulse_phase: f32,
26    /// Whether we've decoded at least one superframe
27    initialized: bool,
28}
29
30impl Decoder {
31    pub fn new() -> Self {
32        Self {
33            synth: SynthesisFrameProcessor::new(),
34            prev_anchor_lsf: crate::core_types::default_lsf(),
35            noise: NoiseGen::new(12345),
36            pulse_phase: 0.0,
37            initialized: false,
38        }
39    }
40
41    /// Decode one superframe: 6 bytes → 540 samples.
42    ///
43    /// `bitstream` must be exactly SUPERFRAME_BYTES_600 (6) bytes.
44    /// Writes SUPERFRAME_SAMPLES (540) samples to `output`.
45    pub fn decode(
46        &mut self,
47        bitstream: &[u8; SUPERFRAME_BYTES_600],
48        output: &mut [f32; SUPERFRAME_SAMPLES],
49    ) {
50        // Unpack bitstream → quantized indices
51        let (quantized, _bits_read) = unpack_superframe(bitstream);
52
53        // Dequantize → 3 FrameParams (with LSF interpolation)
54        let frames = dequantize_superframe(&quantized, &self.prev_anchor_lsf);
55
56        // Update previous anchor LSFs (frame 2 is the anchor)
57        self.prev_anchor_lsf = frames[SUPERFRAME_FRAMES - 1].lsf;
58
59        // Synthesize each of the 3 frames
60        for f in 0..SUPERFRAME_FRAMES {
61            let start = f * FRAME_SAMPLES;
62            let end = start + FRAME_SAMPLES;
63
64            self.synthesize_frame(
65                &frames[f],
66                &mut output[start..end],
67                f == 0 && !self.initialized,
68            );
69        }
70
71        self.initialized = true;
72    }
73
74    /// Synthesize a single frame: generate excitation, run through synthesis filter.
75    fn synthesize_frame(
76        &mut self,
77        params: &FrameParams,
78        output: &mut [f32],
79        first_frame: bool,
80    ) {
81        let n = output.len().min(FRAME_SAMPLES);
82
83        // Generate mixed excitation
84        let mut excitation = [0.0f32; FRAME_SAMPLES];
85
86        // Collapse bandpass voicing to the format mixed_excitation expects
87        let mut voicing = [0.0f32; NUM_BANDS];
88        voicing.copy_from_slice(&params.bandpass_voicing);
89
90        mixed_excitation(
91            params.pitch,
92            &voicing,
93            params.jitter,
94            &mut excitation[..n],
95            &mut self.pulse_phase,
96            &mut self.noise,
97        );
98
99        // Run synthesis (LSF→LPC + gain + filter + de-emphasis)
100        if first_frame {
101            self.synth.process_frame_no_interp(params, &excitation[..n], &mut output[..n]);
102        } else {
103            self.synth.process_frame(params, &excitation[..n], &mut output[..n]);
104        }
105    }
106
107    /// Reset decoder state.
108    pub fn reset(&mut self) {
109        self.synth.reset();
110        self.prev_anchor_lsf = crate::core_types::default_lsf();
111        self.noise = NoiseGen::new(12345);
112        self.pulse_phase = 0.0;
113        self.initialized = false;
114    }
115
116    /// Whether at least one superframe has been decoded.
117    pub fn is_initialized(&self) -> bool {
118        self.initialized
119    }
120
121    /// Previous anchor LSFs (for debugging/testing).
122    pub fn prev_anchor_lsf(&self) -> &[f32; NUM_LSF] {
123        &self.prev_anchor_lsf
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    use crate::core_types::{SAMPLE_RATE, SuperFrameQuantized};
131    use crate::bitstream::pack_superframe;
132    use crate::quantize;
133
134    /// Pack a known SuperFrameQuantized into bytes for decoder testing.
135    fn pack_known(sq: &SuperFrameQuantized) -> [u8; SUPERFRAME_BYTES_600] {
136        let mut buf = [0u8; SUPERFRAME_BYTES_600];
137        pack_superframe(sq, &mut buf);
138        buf
139    }
140
141    #[test]
142    fn test_decode_output_length() {
143        let mut dec = Decoder::new();
144        let bitstream = [0u8; SUPERFRAME_BYTES_600];
145        let mut output = [0.0f32; SUPERFRAME_SAMPLES];
146
147        dec.decode(&bitstream, &mut output);
148
149        // All 540 samples should be written (finite values)
150        assert!(
151            output.iter().all(|x| x.is_finite()),
152            "All output samples must be finite"
153        );
154    }
155
156    #[test]
157    fn test_decode_zeros_quiet() {
158        // All-zero bitstream → should produce relatively quiet output
159        let mut dec = Decoder::new();
160        let bitstream = [0u8; SUPERFRAME_BYTES_600];
161        let mut output = [0.0f32; SUPERFRAME_SAMPLES];
162
163        dec.decode(&bitstream, &mut output);
164
165        let rms = (output.iter().map(|x| x * x).sum::<f32>() / SUPERFRAME_SAMPLES as f32).sqrt();
166        // The zero bitstream dequantizes to low gain, so output should be quiet
167        // (not necessarily silent due to noise excitation and filter transients)
168        assert!(
169            rms < 1.0,
170            "Zero bitstream should produce quiet output, rms={}",
171            rms
172        );
173    }
174
175    #[test]
176    fn test_decode_nonzero_bitstream() {
177        // A bitstream with voiced excitation and moderate gain
178        let sq = SuperFrameQuantized {
179            lsf_indices: [4, 4, 4, 4, 2, 2, 2, 2, 2, 2],
180            pitch_index: 30,        // mid-range pitch
181            gain_index: 20,         // moderate gain
182            voicing_bits: 0b0111,   // all 3 frames voiced
183            jitter_bit: 0,
184        };
185        let bitstream = pack_known(&sq);
186
187        let mut dec = Decoder::new();
188        let mut output = [0.0f32; SUPERFRAME_SAMPLES];
189        dec.decode(&bitstream, &mut output);
190
191        // Voiced with moderate gain → should have real energy
192        let energy: f32 = output.iter().map(|x| x * x).sum::<f32>() / SUPERFRAME_SAMPLES as f32;
193        assert!(
194            energy > 1e-8,
195            "Voiced frame with gain should produce energy, got {}",
196            energy
197        );
198        assert!(
199            output.iter().all(|x| x.is_finite()),
200            "Output must be finite"
201        );
202    }
203
204    #[test]
205    fn test_decode_state_updates() {
206        let mut dec = Decoder::new();
207        assert!(!dec.is_initialized());
208
209        let bitstream = [0u8; SUPERFRAME_BYTES_600];
210        let mut output = [0.0f32; SUPERFRAME_SAMPLES];
211
212        dec.decode(&bitstream, &mut output);
213        assert!(dec.is_initialized());
214
215        // prev_anchor_lsf should be ordered
216        let lsf = dec.prev_anchor_lsf();
217        for i in 1..NUM_LSF {
218            assert!(
219                lsf[i] > lsf[i - 1],
220                "Anchor LSFs should be ordered after decode"
221            );
222        }
223    }
224
225    #[test]
226    fn test_decode_reset() {
227        let mut dec = Decoder::new();
228        let bitstream = [0u8; SUPERFRAME_BYTES_600];
229        let mut output = [0.0f32; SUPERFRAME_SAMPLES];
230
231        dec.decode(&bitstream, &mut output);
232        assert!(dec.is_initialized());
233
234        dec.reset();
235        assert!(!dec.is_initialized());
236    }
237
238    #[test]
239    fn test_decode_multi_superframe() {
240        // Decode 5 consecutive superframes, verify stability
241        let mut dec = Decoder::new();
242        let sq = SuperFrameQuantized {
243            lsf_indices: [3, 3, 3, 3, 1, 1, 1, 1, 1, 1],
244            pitch_index: 25,
245            gain_index: 15,
246            voicing_bits: 0b0101, // frames 0 and 2 voiced
247            jitter_bit: 0,
248        };
249        let bitstream = pack_known(&sq);
250
251        let mut output = [0.0f32; SUPERFRAME_SAMPLES];
252        for i in 0..5 {
253            dec.decode(&bitstream, &mut output);
254            assert!(
255                output.iter().all(|x| x.is_finite()),
256                "Output not finite at superframe {}",
257                i
258            );
259            let peak = output.iter().fold(0.0f32, |m, &s| m.max(s.abs()));
260            assert!(
261                peak < 100.0,
262                "Output blowing up at superframe {}: peak={}",
263                i, peak
264            );
265        }
266    }
267
268    #[test]
269    fn test_decode_deterministic() {
270        let sq = SuperFrameQuantized {
271            lsf_indices: [5, 3, 6, 2, 3, 1, 2, 3, 1, 2],
272            pitch_index: 35,
273            gain_index: 18,
274            voicing_bits: 0b0011,
275            jitter_bit: 1,
276        };
277        let bitstream = pack_known(&sq);
278
279        let mut dec1 = Decoder::new();
280        let mut dec2 = Decoder::new();
281        let mut out1 = [0.0f32; SUPERFRAME_SAMPLES];
282        let mut out2 = [0.0f32; SUPERFRAME_SAMPLES];
283
284        dec1.decode(&bitstream, &mut out1);
285        dec2.decode(&bitstream, &mut out2);
286
287        for i in 0..SUPERFRAME_SAMPLES {
288            assert!(
289                (out1[i] - out2[i]).abs() < 1e-6,
290                "Determinism failed at sample [{}]: {} vs {}",
291                i, out1[i], out2[i]
292            );
293        }
294    }
295
296    #[test]
297    fn test_voiced_vs_unvoiced_differ() {
298        // Same parameters except voicing
299        let sq_voiced = SuperFrameQuantized {
300            lsf_indices: [4, 4, 4, 4, 2, 2, 2, 2, 2, 2],
301            pitch_index: 30,
302            gain_index: 20,
303            voicing_bits: 0b0111, // all voiced
304            jitter_bit: 0,
305        };
306        let sq_unvoiced = SuperFrameQuantized {
307            lsf_indices: [4, 4, 4, 4, 2, 2, 2, 2, 2, 2],
308            pitch_index: 30,
309            gain_index: 20,
310            voicing_bits: 0b0000, // all unvoiced
311            jitter_bit: 0,
312        };
313
314        let mut dec = Decoder::new();
315        let mut out_v = [0.0f32; SUPERFRAME_SAMPLES];
316        dec.decode(&pack_known(&sq_voiced), &mut out_v);
317
318        dec.reset();
319        let mut out_uv = [0.0f32; SUPERFRAME_SAMPLES];
320        dec.decode(&pack_known(&sq_unvoiced), &mut out_uv);
321
322        // Outputs should differ
323        let diff: f32 = out_v.iter().zip(out_uv.iter())
324            .map(|(a, b)| (a - b).abs())
325            .sum::<f32>() / SUPERFRAME_SAMPLES as f32;
326        assert!(
327            diff > 1e-6,
328            "Voiced and unvoiced should produce different output, avg_diff={}",
329            diff
330        );
331    }
332
333    #[test]
334    fn test_different_bitstreams_differ() {
335        let sq1 = SuperFrameQuantized {
336            lsf_indices: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
337            pitch_index: 10,
338            gain_index: 10,
339            voicing_bits: 0b0111,
340            jitter_bit: 0,
341        };
342        let sq2 = SuperFrameQuantized {
343            lsf_indices: [6, 6, 6, 6, 3, 3, 3, 3, 3, 3],
344            pitch_index: 50,
345            gain_index: 25,
346            voicing_bits: 0b0000,
347            jitter_bit: 1,
348        };
349
350        let mut dec = Decoder::new();
351        let mut out1 = [0.0f32; SUPERFRAME_SAMPLES];
352        dec.decode(&pack_known(&sq1), &mut out1);
353
354        dec.reset();
355        let mut out2 = [0.0f32; SUPERFRAME_SAMPLES];
356        dec.decode(&pack_known(&sq2), &mut out2);
357
358        assert_ne!(
359            out1.as_slice(), out2.as_slice(),
360            "Different bitstreams should produce different output"
361        );
362    }
363}