Skip to main content

g729_sys/g729/
decoder.rs

1use crate::g729::basic_operations::*;
2use crate::g729::cng::*;
3use crate::g729::decode_adaptative_code_vector::*;
4use crate::g729::decode_fixed_code_vector::*;
5use crate::g729::decode_gains::*;
6use crate::g729::decode_lsp::*;
7use crate::g729::interpolate_q_lsp::interpolate_q_lsp;
8use crate::g729::ld8k::*;
9use crate::g729::lp_synthesis_filter::lp_synthesis_filter;
10use crate::g729::post_filter::*;
11use crate::g729::post_processing::*;
12use crate::g729::q_lsp_2_lp::q_lsp_2_lp;
13use crate::g729::utils::*;
14
15/* buffers allocation */
16static PREVIOUS_Q_LSP_INITIAL_VALUES: [Word16; NB_LSP_COEFF] = [
17    30000, 26000, 21000, 15000, 8000, 0, -8000, -15000, -21000, -26000,
18]; /* in Q0.15 the initials values for the previous qLSP buffer */
19
20pub struct DecoderChannelContext {
21    /*** buffers used in decoder bloc ***/
22    pub previous_q_lsp: [Word16; NB_LSP_COEFF], /* previous quantised LSP in Q0.15 */
23    pub excitation_vector: [Word16; L_PAST_EXCITATION + L_FRAME], /* in Q0 this vector contains:
24                                                0->153 : the past excitation vector.(length is Max Pitch Delay: 144 + interpolation window size : 10)
25                                                154-> 154+L_FRAME-1 : the current frame adaptative Code Vector first used to compute then the excitation vector */
26    pub bounded_adaptative_codebook_gain: Word16, /* the pitch gain from last subframe bounded in range [0.2,0.8] in Q0.14 */
27    pub adaptative_codebook_gain: Word16, /* the gains needs to be stored in case of frame erasure in Q14 */
28    pub fixed_codebook_gain: Word16,      /* in Q14.1 */
29    pub reconstructed_speech: [Word16; NB_LSP_COEFF + L_FRAME], /* in Q0, output of the LP synthesis filter, the first 10 words store the previous frame output */
30    pub pseudo_random_seed: u16, /* seed used in the pseudo random number generator */
31    pub cng_pseudo_random_seed: u16, /* seed used in the pseudo random number generator for CNG */
32
33    /*** buffers used in decodeLSP bloc ***/
34    pub last_q_lsf: [Word16; NB_LSP_COEFF], /* this buffer stores the last qLSF to be used in case of frame lost in Q2.13 */
35    /* buffer to store the last 4 frames codewords, used to compute the current qLSF */
36    pub previous_l_code_word: [[Word16; NB_LSP_COEFF]; MA_MAX_K], /* in Q2.13, buffer to store the last 4 frames codewords, used to compute the current qLSF */
37    /* the values stored are the codewords computed from the codebooks and rearranged */
38    pub last_valid_l0: u16, /* this one store the L0 of last valid frame to be used in case of frame erased */
39
40    /*** buffer used in decodeAdaptativeCodeVector bloc ***/
41    pub previous_int_pitch_delay: i16, /* store the last valid Integer Pitch Delay computed, used in case of parity error or frame erased */
42
43    /*** buffer used in decodeGains bloc ***/
44    pub previous_gain_prediction_error: [Word16; 4], /* the last four gain prediction error U(m) eq69 and eq72, spec3.9.1 in Q10*/
45
46    /*** buffers used in postFilter bloc ***/
47    pub residual_signal_buffer: [Word16; MAXIMUM_INT_PITCH_DELAY + L_FRAME], /* store the residual signal (current subframe and MAXIMUM_INT_PITCH_DELAY of previous values) in Q0 */
48    pub scaled_residual_signal_buffer: [Word16; MAXIMUM_INT_PITCH_DELAY + L_FRAME], /* same as previous but in Q-2 */
49    pub long_term_filtered_residual_signal_buffer: [Word16; 1 + L_SUBFRAME], /* the output of long term filter in Q0, need 1 word from previous subframe for tilt compensation filter */
50    pub short_term_filtered_residual_signal_buffer: [Word16; NB_LSP_COEFF + L_SUBFRAME], /* the output of short term filter(synthesis filter) in Q0, need NB_LSP_COEFF word from previous subframe as filter memory */
51    pub previous_adaptative_gain: Word16, /* previous gain for adaptative gain control */
52
53    /*** buffers used in postProcessing bloc ***/
54    pub input_x0: Word16,
55    pub input_x1: Word16,
56    pub output_y2: Word32,
57    pub output_y1: Word32,
58
59    /* SID frame management */
60    pub cng_channel_context: CngChannelContext, /* store informations specific to CNG */
61    pub previous_frame_is_active_flag: u8,      /* store last processed frame type */
62}
63
64pub fn init_bcg729_decoder_channel() -> DecoderChannelContext {
65    let mut ctx = DecoderChannelContext {
66        previous_q_lsp: PREVIOUS_Q_LSP_INITIAL_VALUES,
67        excitation_vector: [0; L_PAST_EXCITATION + L_FRAME],
68        bounded_adaptative_codebook_gain: BOUNDED_PITCH_GAIN_MIN,
69        adaptative_codebook_gain: 0,
70        fixed_codebook_gain: 0,
71        reconstructed_speech: [0; NB_LSP_COEFF + L_FRAME],
72        pseudo_random_seed: 21845,
73        cng_pseudo_random_seed: CNG_DTX_RANDOM_SEED_INIT,
74        last_q_lsf: [0; NB_LSP_COEFF],
75        previous_l_code_word: [[0; NB_LSP_COEFF]; MA_MAX_K],
76        last_valid_l0: 0,
77        previous_int_pitch_delay: 0,
78        previous_gain_prediction_error: [0; 4],
79        residual_signal_buffer: [0; MAXIMUM_INT_PITCH_DELAY + L_FRAME],
80        scaled_residual_signal_buffer: [0; MAXIMUM_INT_PITCH_DELAY + L_FRAME],
81        long_term_filtered_residual_signal_buffer: [0; 1 + L_SUBFRAME],
82        short_term_filtered_residual_signal_buffer: [0; NB_LSP_COEFF + L_SUBFRAME],
83        previous_adaptative_gain: 0,
84        input_x0: 0,
85        input_x1: 0,
86        output_y2: 0,
87        output_y1: 0,
88        cng_channel_context: init_bcg729_cng_channel(),
89        previous_frame_is_active_flag: 1,
90    };
91
92    init_decode_lsp(
93        &mut ctx.previous_l_code_word,
94        &mut ctx.last_valid_l0,
95        &mut ctx.last_q_lsf,
96    );
97    init_decode_adaptative_code_vector(&mut ctx.previous_int_pitch_delay);
98    init_decode_gains(&mut ctx.previous_gain_prediction_error);
99    init_post_filter(
100        &mut ctx.residual_signal_buffer,
101        &mut ctx.scaled_residual_signal_buffer,
102        &mut ctx.long_term_filtered_residual_signal_buffer,
103        &mut ctx.short_term_filtered_residual_signal_buffer,
104        &mut ctx.previous_adaptative_gain,
105    );
106    init_post_processing(
107        &mut ctx.output_y2,
108        &mut ctx.output_y1,
109        &mut ctx.input_x0,
110        &mut ctx.input_x1,
111    );
112
113    ctx
114}
115
116pub fn bcg729_decoder(
117    decoder_channel_context: &mut DecoderChannelContext,
118    bit_stream: Option<&[u8]>,
119    bit_stream_length: u8,
120    frame_erasure_flag: u8,
121    mut sid_frame_flag: u8,
122    rfc3389_payload_flag: u8,
123    signal: &mut [Word16],
124) {
125    let mut parameters = [0 as u16; NB_PARAMETERS];
126    /* internal buffers which we do not need to keep between calls */
127    let mut q_lsp = [0 as Word16; NB_LSP_COEFF]; /* store the qLSP coefficients in Q0.15 */
128    let mut interpolated_q_lsp = [0 as Word16; NB_LSP_COEFF]; /* store the interpolated qLSP coefficient in Q0.15 */
129    let mut lp = [0 as Word16; 2 * NB_LSP_COEFF]; /* store the 2 sets of LP coefficients in Q12 */
130    let mut int_pitch_delay: i16 = 0; /* store the Pitch Delay in and out of decodeAdaptativeCodeVector, in for decodeFixedCodeVector */
131    let mut fixed_codebook_vector = [0 as Word16; L_SUBFRAME]; /* the fixed Codebook Vector in Q1.13*/
132    let mut post_filtered_signal = [0 as Word16; L_SUBFRAME]; /* store the postfiltered signal in Q0 */
133
134    let parity_error_flag: u8;
135    let mut parameters_index = 4; /* this is used to select the right parameter according to the subframe currently computed, start pointing to P1 */
136    let mut lp_coefficients_index = 0; /* this is used to select the right LP Coefficients according to the subframe currently computed */
137
138    /*** parse the bitstream and get all parameter into an array as in spec 4 - Table 8 ***/
139    if let Some(bs) = bit_stream {
140        if sid_frame_flag == 0 {
141            parameters_bit_stream_2_array(bs, &mut parameters);
142        }
143    } else {
144        for i in 0..NB_PARAMETERS {
145            parameters[i] = 0;
146        }
147    }
148
149    /* manage frameErasure and CNG as specified in B.27 */
150    if frame_erasure_flag != 0 {
151        if decoder_channel_context.previous_frame_is_active_flag != 0 {
152            sid_frame_flag = 0;
153        } else {
154            sid_frame_flag = 1;
155        }
156    }
157
158    /* this is a SID frame, process it using the dedicated function */
159    if sid_frame_flag == 1 {
160        decode_sid_frame(
161            &mut decoder_channel_context.cng_channel_context,
162            decoder_channel_context.previous_frame_is_active_flag,
163            bit_stream,
164            bit_stream_length,
165            &mut decoder_channel_context.excitation_vector[L_PAST_EXCITATION..],
166            &mut decoder_channel_context.previous_q_lsp,
167            &mut lp,
168            &mut decoder_channel_context.cng_pseudo_random_seed,
169            &mut decoder_channel_context.previous_l_code_word,
170            rfc3389_payload_flag,
171        );
172        decoder_channel_context.previous_frame_is_active_flag = 0;
173
174        /* loop over the two subframes */
175        for subframe_index in (0..L_FRAME).step_by(L_SUBFRAME) {
176            /* reconstruct speech using LP synthesis filter spec 4.1.6 eq77 */
177            /* excitationVector in Q0, LP in Q12, recontructedSpeech in Q0 -> +NB_LSP_COEFF on the index of this one because the first NB_LSP_COEFF elements store the previous frame filter output */
178            // LPSynthesisFilter(&(decoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &(LP[LPCoefficientsIndex]), &(decoderChannelContext->reconstructedSpeech[NB_LSP_COEFF+subframeIndex]) );
179            lp_synthesis_filter(
180                &decoder_channel_context.excitation_vector[L_PAST_EXCITATION + subframe_index..],
181                &lp[lp_coefficients_index..],
182                &mut decoder_channel_context.reconstructed_speech[subframe_index..],
183            );
184
185            /* NOTE: ITU code check for overflow after LP Synthesis Filter computation and if it happened, divide excitation buffer by 2 and recompute the LP Synthesis Filter */
186            /*	here, possible overflows are managed directly inside the Filter by saturation at MAXINT16 on each result */
187
188            /* postFilter */
189            post_filter(
190                &mut decoder_channel_context.residual_signal_buffer,
191                &mut decoder_channel_context.scaled_residual_signal_buffer,
192                &mut decoder_channel_context.long_term_filtered_residual_signal_buffer,
193                &mut decoder_channel_context.short_term_filtered_residual_signal_buffer,
194                &mut decoder_channel_context.previous_adaptative_gain,
195                &lp[lp_coefficients_index..],
196                &decoder_channel_context.reconstructed_speech[subframe_index..],
197                decoder_channel_context.previous_int_pitch_delay,
198                subframe_index,
199                &mut post_filtered_signal,
200            );
201
202            /* postProcessing */
203            post_processing(
204                &mut decoder_channel_context.output_y2,
205                &mut decoder_channel_context.output_y1,
206                &mut decoder_channel_context.input_x0,
207                &mut decoder_channel_context.input_x1,
208                &mut post_filtered_signal,
209            );
210
211            /* copy postProcessing Output to the signal output buffer */
212            for i in 0..L_SUBFRAME {
213                signal[subframe_index + i] = post_filtered_signal[i];
214            }
215
216            /* increase LPCoefficient Indexes */
217            lp_coefficients_index += NB_LSP_COEFF;
218        }
219
220        decoder_channel_context.bounded_adaptative_codebook_gain = BOUNDED_PITCH_GAIN_MIN;
221
222        /* Shift Excitation Vector by L_FRAME left */
223        // memmove(decoderChannelContext->excitationVector, &(decoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t));
224        for i in 0..L_PAST_EXCITATION {
225            decoder_channel_context.excitation_vector[i] =
226                decoder_channel_context.excitation_vector[L_FRAME + i];
227        }
228        /* Copy the last 10 words of reconstructed Speech to the begining of the array for next frame computation */
229        // memcpy(decoderChannelContext->reconstructedSpeech, &(decoderChannelContext->reconstructedSpeech[L_FRAME]), NB_LSP_COEFF*sizeof(word16_t));
230        for i in 0..NB_LSP_COEFF {
231            decoder_channel_context.reconstructed_speech[i] =
232                decoder_channel_context.reconstructed_speech[L_FRAME + i];
233        }
234
235        return;
236    }
237
238    decoder_channel_context.previous_frame_is_active_flag = 1;
239    /* re-init the CNG pseudo random seed at each active frame spec B.4 */
240    decoder_channel_context.cng_pseudo_random_seed = CNG_DTX_RANDOM_SEED_INIT; /* re-initialise CNG pseudo Random seed to 11111 according to ITU code */
241
242    /*****************************************************************************************/
243    /*** on frame basis : decodeLSP, interpolate them with previous ones and convert to LP ***/
244    decode_lsp(
245        &mut decoder_channel_context.previous_l_code_word,
246        &mut decoder_channel_context.last_valid_l0,
247        &mut decoder_channel_context.last_q_lsf,
248        &parameters[0..4],
249        &mut q_lsp,
250        frame_erasure_flag,
251    ); /* decodeLSP need the first 4 parameters: L0-L3 */
252
253    interpolate_q_lsp(
254        &decoder_channel_context.previous_q_lsp,
255        &q_lsp,
256        &mut interpolated_q_lsp,
257    );
258    /* copy the currentqLSP to previousqLSP buffer */
259    for i in 0..NB_LSP_COEFF {
260        decoder_channel_context.previous_q_lsp[i] = q_lsp[i];
261    }
262
263    /* call the qLSP2LP function for first subframe */
264    q_lsp_2_lp(&interpolated_q_lsp, &mut lp[0..NB_LSP_COEFF]);
265    /* call the qLSP2LP function for second subframe */
266    q_lsp_2_lp(&q_lsp, &mut lp[NB_LSP_COEFF..]);
267
268    /* check the parity on the adaptativeCodebookIndexSubframe1(P1) with the received one (P0)*/
269    parity_error_flag = (compute_parity(parameters[4]) ^ parameters[5]) as u8;
270
271    /* loop over the two subframes */
272    for subframe_index in (0..L_FRAME).step_by(L_SUBFRAME) {
273        /* decode the adaptative Code Vector */
274        decode_adaptative_code_vector(
275            &mut decoder_channel_context.previous_int_pitch_delay,
276            subframe_index,
277            parameters[parameters_index],
278            parity_error_flag,
279            frame_erasure_flag,
280            &mut int_pitch_delay,
281            &mut decoder_channel_context.excitation_vector,
282        );
283        if subframe_index == 0 {
284            /* at first subframe we have P0 between P1 and C1 */
285            parameters_index += 2;
286        } else {
287            parameters_index += 1;
288        }
289
290        /* in case of frame erasure we shall generate pseudoRandom signs and index for fixed code vector decoding according to spec 4.4.4 */
291        if frame_erasure_flag != 0 {
292            parameters[parameters_index] =
293                pseudo_random(&mut decoder_channel_context.pseudo_random_seed) & 0x1fff; /* signs are set to the 13 LSB of the first pseudoRandom number */
294            parameters[parameters_index + 1] =
295                pseudo_random(&mut decoder_channel_context.pseudo_random_seed) & 0x000f;
296            /* signs are set to the 4 LSB of the second pseudoRandom number */
297        }
298
299        /* decode the fixed Code Vector */
300        decode_fixed_code_vector(
301            parameters[parameters_index + 1],
302            parameters[parameters_index],
303            int_pitch_delay,
304            decoder_channel_context.bounded_adaptative_codebook_gain,
305            &mut fixed_codebook_vector,
306        );
307        parameters_index += 2;
308
309        /* decode gains */
310        decode_gains(
311            &mut decoder_channel_context.previous_gain_prediction_error,
312            parameters[parameters_index],
313            parameters[parameters_index + 1],
314            &fixed_codebook_vector,
315            frame_erasure_flag,
316            &mut decoder_channel_context.adaptative_codebook_gain,
317            &mut decoder_channel_context.fixed_codebook_gain,
318        );
319
320        parameters_index += 2;
321
322        /* update bounded Adaptative Codebook Gain (in Q14) according to eq47 */
323        decoder_channel_context.bounded_adaptative_codebook_gain =
324            decoder_channel_context.adaptative_codebook_gain;
325        if decoder_channel_context.bounded_adaptative_codebook_gain > BOUNDED_PITCH_GAIN_MAX {
326            decoder_channel_context.bounded_adaptative_codebook_gain = BOUNDED_PITCH_GAIN_MAX;
327        }
328        if decoder_channel_context.bounded_adaptative_codebook_gain < BOUNDED_PITCH_GAIN_MIN {
329            decoder_channel_context.bounded_adaptative_codebook_gain = BOUNDED_PITCH_GAIN_MIN;
330        }
331
332        /* compute excitation vector according to eq75 */
333        /* excitationVector = adaptative Codebook Vector * adaptativeCodebookGain + fixed Codebook Vector * fixedCodebookGain */
334        /* the adaptative Codebook Vector is in the excitationVector buffer [L_PAST_EXCITATION + subframeIndex] */
335        /* with adaptative Codebook Vector in Q0, adaptativeCodebookGain in Q14, fixed Codebook Vector in Q1.13 and fixedCodebookGain in Q14.1 -> result in Q14 on 32 bits */
336        /* -> shift right 14 bits and store the value in Q0 in a 16 bits type */
337        for i in 0..L_SUBFRAME {
338            decoder_channel_context.excitation_vector[L_PAST_EXCITATION + subframe_index + i] =
339                saturate(
340                    pshr(
341                        add32(
342                            mult16_16(
343                                decoder_channel_context.excitation_vector
344                                    [L_PAST_EXCITATION + subframe_index + i],
345                                decoder_channel_context.adaptative_codebook_gain,
346                            ),
347                            mult16_16(
348                                fixed_codebook_vector[i],
349                                decoder_channel_context.fixed_codebook_gain,
350                            ),
351                        ),
352                        14,
353                    ),
354                    MAX_INT16 as Word32,
355                ) as Word16;
356        }
357
358        /* reconstruct speech using LP synthesis filter spec 4.1.6 eq77 */
359        /* excitationVector in Q0, LP in Q12, recontructedSpeech in Q0 -> +NB_LSP_COEFF on the index of this one because the first NB_LSP_COEFF elements store the previous frame filter output */
360        // LPSynthesisFilter(&(decoderChannelContext->excitationVector[L_PAST_EXCITATION + subframeIndex]), &(LP[LPCoefficientsIndex]), &(decoderChannelContext->reconstructedSpeech[NB_LSP_COEFF+subframeIndex]) );
361        lp_synthesis_filter(
362            &decoder_channel_context.excitation_vector[L_PAST_EXCITATION + subframe_index..],
363            &lp[lp_coefficients_index..],
364            &mut decoder_channel_context.reconstructed_speech[subframe_index..],
365        );
366
367        /* NOTE: ITU code check for overflow after LP Synthesis Filter computation and if it happened, divide excitation buffer by 2 and recompute the LP Synthesis Filter */
368        /*	here, possible overflows are managed directly inside the Filter by saturation at MAXINT16 on each result */
369
370        /* postFilter */
371        post_filter(
372            &mut decoder_channel_context.residual_signal_buffer,
373            &mut decoder_channel_context.scaled_residual_signal_buffer,
374            &mut decoder_channel_context.long_term_filtered_residual_signal_buffer,
375            &mut decoder_channel_context.short_term_filtered_residual_signal_buffer,
376            &mut decoder_channel_context.previous_adaptative_gain,
377            &lp[lp_coefficients_index..],
378            &decoder_channel_context.reconstructed_speech[subframe_index..],
379            int_pitch_delay,
380            subframe_index,
381            &mut post_filtered_signal,
382        ); /* postProcessing */
383
384        post_processing(
385            &mut decoder_channel_context.output_y2,
386            &mut decoder_channel_context.output_y1,
387            &mut decoder_channel_context.input_x0,
388            &mut decoder_channel_context.input_x1,
389            &mut post_filtered_signal,
390        );
391
392        /* copy postProcessing Output to the signal output buffer */
393        for i in 0..L_SUBFRAME {
394            signal[subframe_index + i] = post_filtered_signal[i];
395        }
396
397        /* increase LPCoefficient Indexes */
398        lp_coefficients_index += NB_LSP_COEFF;
399    }
400
401    /* Shift Excitation Vector by L_FRAME left */
402    // memmove(decoderChannelContext->excitationVector, &(decoderChannelContext->excitationVector[L_FRAME]), L_PAST_EXCITATION*sizeof(word16_t));
403    for i in 0..L_PAST_EXCITATION {
404        decoder_channel_context.excitation_vector[i] =
405            decoder_channel_context.excitation_vector[L_FRAME + i];
406    }
407    /* Copy the last 10 words of reconstructed Speech to the begining of the array for next frame computation */
408    // memcpy(decoderChannelContext->reconstructedSpeech, &(decoderChannelContext->reconstructedSpeech[L_FRAME]), NB_LSP_COEFF*sizeof(word16_t));
409    for i in 0..NB_LSP_COEFF {
410        decoder_channel_context.reconstructed_speech[i] =
411            decoder_channel_context.reconstructed_speech[L_FRAME + i];
412    }
413}
414
415pub struct Decoder {
416    context: DecoderChannelContext,
417}
418
419impl Decoder {
420    pub fn new() -> Self {
421        Decoder {
422            context: init_bcg729_decoder_channel(),
423        }
424    }
425
426    pub fn decode(
427        &mut self,
428        bit_stream: Option<&[u8]>,
429        bit_stream_length: u8,
430        frame_erasure_flag: u8,
431        sid_frame_flag: u8,
432        rfc3389_payload_flag: u8,
433        signal: &mut [i16],
434    ) {
435        bcg729_decoder(
436            &mut self.context,
437            bit_stream,
438            bit_stream_length,
439            frame_erasure_flag,
440            sid_frame_flag,
441            rfc3389_payload_flag,
442            signal,
443        );
444    }
445}