1use crate::g729::basic_operations::*;
2use crate::g729::ld8k::*;
3use crate::g729::adaptative_codebook_search::*;
5use crate::g729::compute_adaptative_codebook_gain::*;
6use crate::g729::compute_lp::*;
7use crate::g729::compute_weighted_speech::*;
8use crate::g729::find_open_loop_pitch_delay::*;
9use crate::g729::fixed_codebook_search::*;
10use crate::g729::gain_quantization::*;
11use crate::g729::interpolate_q_lsp::*;
12use crate::g729::lp2lsp_conversion::*;
13use crate::g729::lp_synthesis_filter::lp_synthesis_filter;
14use crate::g729::lsp_quantization::*;
15use crate::g729::pre_processing::*;
16use crate::g729::q_lsp_2_lp::*;
17use crate::g729::utils::*;
18
19pub struct EncoderChannelContext {
20 pub signal_buffer: [Word16; L_LP_ANALYSIS_WINDOW],
23
24 pub previous_lsp_coefficients: [Word16; NB_LSP_COEFF],
28 pub previous_q_lsp_coefficients: [Word16; NB_LSP_COEFF],
29
30 pub weighted_input_signal: [Word16; MAXIMUM_INT_PITCH_DELAY + L_FRAME],
31 pub excitation_vector: [Word16; L_PAST_EXCITATION + L_FRAME],
32
33 pub target_signal: [Word16; NB_LSP_COEFF + L_SUBFRAME],
34
35 pub last_quantized_adaptative_codebook_gain: Word16,
36
37 pub pre_processing_state: PreProcessingState,
39
40 pub previous_q_lsf: [[Word16; NB_LSP_COEFF]; MA_MAX_K],
42
43 pub previous_gain_prediction_error: [Word16; 4],
45 }
49
50const PREVIOUS_LSP_INITIAL_VALUES: [Word16; NB_LSP_COEFF] = [
51 30000, 26000, 21000, 15000, 8000, 0, -8000, -15000, -21000, -26000,
52];
53
54const SIGNAL_LAST_INPUT_FRAME_IDX: usize = L_LP_ANALYSIS_WINDOW - L_FRAME;
56const SIGNAL_CURRENT_FRAME_IDX: usize = L_LP_ANALYSIS_WINDOW - L_SUBFRAME - L_FRAME;
57
58impl EncoderChannelContext {
59 pub fn new(_enable_vad: bool) -> Self {
60 let mut ctx = EncoderChannelContext {
61 signal_buffer: [0; L_LP_ANALYSIS_WINDOW],
62 previous_lsp_coefficients: PREVIOUS_LSP_INITIAL_VALUES,
63 previous_q_lsp_coefficients: PREVIOUS_LSP_INITIAL_VALUES,
64 weighted_input_signal: [0; MAXIMUM_INT_PITCH_DELAY + L_FRAME],
65 excitation_vector: [0; L_PAST_EXCITATION + L_FRAME],
66 target_signal: [0; NB_LSP_COEFF + L_SUBFRAME],
67 last_quantized_adaptative_codebook_gain: O2_IN_Q14,
68 pre_processing_state: PreProcessingState::new(),
69 previous_q_lsf: [[0; NB_LSP_COEFF]; MA_MAX_K],
70 previous_gain_prediction_error: [0; 4],
71 };
72
73 init_lsp_quantization(&mut ctx.previous_q_lsf);
78
79 for i in 0..4 {
85 ctx.previous_gain_prediction_error[i] = -14336;
86 }
87
88 ctx
89 }
90
91 pub fn encode(
92 &mut self,
93 input_frame: &[Word16],
94 bit_stream: &mut [u8],
95 bit_stream_length: &mut u8,
96 ) {
97 let mut parameters = [0u16; NB_PARAMETERS];
98
99 let mut lp_coefficients = [0i16; NB_LSP_COEFF];
101 let _lsf_coefficients = [0i16; NB_LSP_COEFF];
102 let mut q_lp_coefficients = [0i16; 2 * NB_LSP_COEFF];
103 let mut weighted_q_lp_coefficients = [0i16; 2 * NB_LSP_COEFF];
104 let mut lsp_coefficients = [0i16; NB_LSP_COEFF];
105 let mut q_lsp_coefficients = [0i16; NB_LSP_COEFF];
106 let mut interpolated_q_lsp = [0i16; NB_LSP_COEFF];
107
108 let mut parameters_index = 4;
109 let mut impulse_response_input = [0i16; L_SUBFRAME];
110
111 let mut reflection_coefficients = [0i32; NB_LSP_COEFF];
113 let mut auto_correlation_coefficients = [0i32; NB_LSP_COEFF + 3];
114 let mut no_lag_auto_correlation_coefficients = [0i32; NB_LSP_COEFF + 3];
115 let mut auto_correlation_coefficients_scale = 0i8;
116
117 self.pre_processing_state.pre_processing(
121 input_frame,
122 &mut self.signal_buffer[SIGNAL_LAST_INPUT_FRAME_IDX..],
123 );
124
125 compute_lp(
129 &self.signal_buffer,
130 &mut lp_coefficients,
131 &mut reflection_coefficients,
132 &mut auto_correlation_coefficients,
133 &mut no_lag_auto_correlation_coefficients,
134 &mut auto_correlation_coefficients_scale,
135 NB_LSP_COEFF + 1, );
137
138 if !lp2lsp_conversion(&lp_coefficients, &mut lsp_coefficients) {
140 lsp_coefficients.copy_from_slice(&self.previous_lsp_coefficients);
141 }
142
143 *bit_stream_length = 10;
145
146 lsp_quantization(
148 &mut self.previous_q_lsf,
149 &mut lsp_coefficients,
150 &mut q_lsp_coefficients,
151 &mut parameters,
152 );
153 interpolate_q_lsp(
155 &self.previous_q_lsp_coefficients,
156 &q_lsp_coefficients,
157 &mut interpolated_q_lsp,
158 );
159
160 self.previous_q_lsp_coefficients
162 .copy_from_slice(&q_lsp_coefficients);
163
164 q_lsp_2_lp(&interpolated_q_lsp, &mut q_lp_coefficients[0..NB_LSP_COEFF]);
167 q_lsp_2_lp(&q_lsp_coefficients, &mut q_lp_coefficients[NB_LSP_COEFF..]);
169
170 for i in 0..2 * NB_LSP_COEFF {
172 let gamma_idx = i % NB_LSP_COEFF;
176 let gamma = match gamma_idx {
177 0 => GAMMA_E1,
178 1 => GAMMA_E2,
179 2 => GAMMA_E3,
180 3 => GAMMA_E4,
181 4 => GAMMA_E5,
182 5 => GAMMA_E6,
183 6 => GAMMA_E7,
184 7 => GAMMA_E8,
185 8 => GAMMA_E9,
186 9 => GAMMA_E10,
187 _ => 0,
188 };
189 weighted_q_lp_coefficients[i] = mult16_16_p15(q_lp_coefficients[i], gamma) as Word16;
190 }
191
192 compute_weighted_speech(
199 &self.signal_buffer[SIGNAL_CURRENT_FRAME_IDX - NB_LSP_COEFF..],
200 &q_lp_coefficients,
201 &weighted_q_lp_coefficients,
202 &mut self.weighted_input_signal[MAXIMUM_INT_PITCH_DELAY - NB_LSP_COEFF..],
203 &mut self.excitation_vector[L_PAST_EXCITATION..],
204 );
205
206 let open_loop_pitch_delay = find_open_loop_pitch_delay(&self.weighted_input_signal);
208 let mut int_pitch_delay_min = open_loop_pitch_delay as i16 - 3;
209 if int_pitch_delay_min < 20 {
210 int_pitch_delay_min = 20;
211 }
212 let mut int_pitch_delay_max = int_pitch_delay_min + 6;
213 if int_pitch_delay_max > MAXIMUM_INT_PITCH_DELAY as i16 {
214 int_pitch_delay_max = MAXIMUM_INT_PITCH_DELAY as i16;
215 int_pitch_delay_min = MAXIMUM_INT_PITCH_DELAY as i16 - 6;
216 }
217
218 impulse_response_input[0] = ONE_IN_Q12 as Word16;
220 for i in 1..L_SUBFRAME {
221 impulse_response_input[i] = 0;
222 }
223
224 let mut lp_coefficients_index = 0;
225
226 for subframe_index in (0..L_FRAME).step_by(L_SUBFRAME) {
227 let mut int_pitch_delay: i16 = 0;
228 let mut frac_pitch_delay: i16 = 0;
229 let adaptative_codebook_gain: Word16;
230
231 let mut impulse_response_buffer = [0i16; NB_LSP_COEFF + L_SUBFRAME];
232 let mut filtered_adaptative_codebook_vector = [0i16; NB_LSP_COEFF + L_SUBFRAME];
233 let mut gain_quantization_xy: Word64 = 0;
234 let mut gain_quantization_yy: Word64 = 0;
235 let mut fixed_codebook_vector = [0i16; L_SUBFRAME];
236 let mut convolved_fixed_codebook_vector = [0i16; L_SUBFRAME];
237 let mut quantized_adaptative_codebook_gain: Word16 = 0;
238 let mut quantized_fixed_codebook_gain: Word16 = 0;
239
240 lp_synthesis_filter(
244 &impulse_response_input,
245 &weighted_q_lp_coefficients[lp_coefficients_index..],
246 &mut impulse_response_buffer,
247 );
248
249 lp_synthesis_filter(
252 &self.excitation_vector[L_PAST_EXCITATION + subframe_index
253 ..L_PAST_EXCITATION + subframe_index + L_SUBFRAME],
254 &weighted_q_lp_coefficients[lp_coefficients_index..],
255 &mut self.target_signal,
256 );
257
258 let mut param_pitch_delay: u16 = 0;
260 adaptative_codebook_search(
261 &mut self.excitation_vector,
262 L_PAST_EXCITATION + subframe_index,
263 &mut int_pitch_delay_min,
264 &mut int_pitch_delay_max,
265 &impulse_response_buffer[NB_LSP_COEFF..],
266 &self.target_signal[NB_LSP_COEFF..],
267 &mut int_pitch_delay,
268 &mut frac_pitch_delay,
269 &mut param_pitch_delay,
270 subframe_index as u16,
271 );
272 parameters[parameters_index] = param_pitch_delay;
273
274 lp_synthesis_filter(
277 &self.excitation_vector[L_PAST_EXCITATION + subframe_index
278 ..L_PAST_EXCITATION + subframe_index + L_SUBFRAME],
279 &weighted_q_lp_coefficients[lp_coefficients_index..],
280 &mut filtered_adaptative_codebook_vector,
281 );
282
283 adaptative_codebook_gain = compute_adaptative_codebook_gain(
284 &self.target_signal[NB_LSP_COEFF..],
285 &filtered_adaptative_codebook_vector[NB_LSP_COEFF..],
286 &mut gain_quantization_xy,
287 &mut gain_quantization_yy,
288 );
289
290 parameters_index += 1;
291 if subframe_index == 0 {
292 parameters[parameters_index] = compute_parity(parameters[parameters_index - 1]);
293 parameters_index += 1;
294 }
295
296 let mut param_fixed_codebook_idx: u16 = 0;
298 let mut param_fixed_codebook_sign: u16 = 0;
299
300 fixed_codebook_search(
301 &self.target_signal[NB_LSP_COEFF..],
302 &mut impulse_response_buffer[NB_LSP_COEFF..],
303 int_pitch_delay,
304 self.last_quantized_adaptative_codebook_gain,
305 &filtered_adaptative_codebook_vector[NB_LSP_COEFF..],
306 adaptative_codebook_gain,
307 &mut param_fixed_codebook_idx,
308 &mut param_fixed_codebook_sign,
309 &mut fixed_codebook_vector,
310 &mut convolved_fixed_codebook_vector,
311 );
312 parameters[parameters_index] = param_fixed_codebook_idx;
313 parameters[parameters_index + 1] = param_fixed_codebook_sign;
314 parameters_index += 2;
315
316 let mut param_gain_stage1: u16 = 0;
318 let mut param_gain_stage2: u16 = 0;
319
320 gain_quantization(
321 &self.target_signal[NB_LSP_COEFF..],
322 &filtered_adaptative_codebook_vector[NB_LSP_COEFF..],
323 &convolved_fixed_codebook_vector,
324 &fixed_codebook_vector,
325 gain_quantization_xy,
326 gain_quantization_yy,
327 &mut self.previous_gain_prediction_error,
328 &mut quantized_adaptative_codebook_gain,
329 &mut quantized_fixed_codebook_gain,
330 &mut param_gain_stage1,
331 &mut param_gain_stage2,
332 );
333 parameters[parameters_index] = param_gain_stage1;
334 parameters[parameters_index + 1] = param_gain_stage2;
335 parameters_index += 2;
336
337 lp_coefficients_index += NB_LSP_COEFF;
339 self.last_quantized_adaptative_codebook_gain = quantized_adaptative_codebook_gain;
340 if self.last_quantized_adaptative_codebook_gain > ONE_POINT_2_IN_Q14 {
341 self.last_quantized_adaptative_codebook_gain = ONE_POINT_2_IN_Q14;
342 }
343 if self.last_quantized_adaptative_codebook_gain < O2_IN_Q14 {
344 self.last_quantized_adaptative_codebook_gain = O2_IN_Q14;
345 }
346
347 for i in 0..L_SUBFRAME {
349 self.excitation_vector[L_PAST_EXCITATION + subframe_index + i] = saturate(
350 pshr(
351 add32(
352 mult16_16(
353 self.excitation_vector[L_PAST_EXCITATION + subframe_index + i],
354 quantized_adaptative_codebook_gain,
355 ),
356 mult16_16(fixed_codebook_vector[i], quantized_fixed_codebook_gain),
357 ),
358 14,
359 ),
360 MAX_INT16 as Word32,
361 )
362 as Word16;
363 }
364
365 let quantized_adaptative_codebook_gain_q13 =
367 pshr(quantized_adaptative_codebook_gain as Word32, 1) as Word16;
368 for i in 0..NB_LSP_COEFF {
369 let acc = mac16_16(
370 mult16_16(
371 quantized_adaptative_codebook_gain_q13,
372 filtered_adaptative_codebook_vector[L_SUBFRAME + i],
373 ),
374 quantized_fixed_codebook_gain,
375 convolved_fixed_codebook_vector[L_SUBFRAME - NB_LSP_COEFF + i],
376 );
377 self.target_signal[i] = saturate(
378 sub32(self.target_signal[L_SUBFRAME + i] as Word32, pshr(acc, 13)),
379 MAX_INT16 as Word32,
380 ) as Word16;
381 }
382 }
383
384 self.signal_buffer.copy_within(L_FRAME.., 0);
387
388 self.previous_lsp_coefficients
390 .copy_from_slice(&lsp_coefficients);
391 self.previous_q_lsp_coefficients
392 .copy_from_slice(&q_lsp_coefficients);
393
394 self.weighted_input_signal.copy_within(L_FRAME.., 0);
396
397 self.excitation_vector.copy_within(L_FRAME.., 0);
399
400 parameters_array_2_bit_stream(¶meters, bit_stream);
402 }
403}
404
405pub struct Encoder {
406 context: EncoderChannelContext,
407}
408
409impl Encoder {
410 pub fn new(enable_vad: bool) -> Self {
411 Encoder {
412 context: EncoderChannelContext::new(enable_vad),
413 }
414 }
415
416 pub fn encode(
417 &mut self,
418 input_frame: &[i16],
419 bit_stream: &mut [u8],
420 bit_stream_length: &mut u8,
421 ) {
422 self.context
423 .encode(input_frame, bit_stream, bit_stream_length);
424 }
425}