1#[cfg(target_arch = "aarch64")]
2use core::arch::aarch64::*;
3#[cfg(target_arch = "x86_64")]
4use core::arch::x86_64::*;
5
6use crate::g729::basic_operations::*;
7use crate::g729::codebooks::MA_PREDICTION_COEFFICIENTS;
8use crate::g729::fixed_point_math::*;
9use crate::g729::ld8k::*;
10
11pub fn insertion_sort(x: &mut [Word16], length: usize) {
12 for i in 1..length {
13 let current_value = x[i];
14 let mut j = (i as i32) - 1;
15 while j >= 0 && x[j as usize] > current_value {
16 x[(j + 1) as usize] = x[j as usize];
17 j -= 1;
18 }
19 x[(j + 1) as usize] = current_value;
20 }
21}
22
23pub fn get_min_in_array(x: &[Word16], length: usize) -> Word16 {
24 let mut min = MAX_16;
25 for i in 0..length {
26 if x[i] < min {
27 min = x[i];
28 }
29 }
30 min
31}
32
33pub fn compute_parity(mut adaptative_codebook_index: UWord16) -> UWord16 {
34 let mut parity = 1;
35 adaptative_codebook_index = adaptative_codebook_index >> 2; for _ in 0..6 {
38 parity ^= adaptative_codebook_index & 1; adaptative_codebook_index = adaptative_codebook_index >> 1;
40 }
41 parity
42}
43
44pub fn rearrange_coefficients(q_lsp: &mut [Word16], j: Word16) {
45 for i in 1..NB_LSP_COEFF {
47 let delta = (add16(sub16(q_lsp[i - 1], q_lsp[i]), j)) / 2; if delta > 0 {
49 q_lsp[i - 1] = sub16(q_lsp[i - 1], delta); q_lsp[i] = add16(q_lsp[i], delta);
51 }
52 }
53}
54
55pub fn synthesis_filter(
56 input_signal: &[Word16],
57 filter_coefficients: &[Word16],
58 filtered_signal: &mut [Word16],
59) {
60 for i in 0..L_SUBFRAME {
88 let mut acc = sshl(input_signal[i] as Word32, 12); for j in 0..NB_LSP_COEFF {
90 acc = msu16_16(
97 acc,
98 filter_coefficients[j],
99 filtered_signal[i + NB_LSP_COEFF - j - 1],
100 );
101 }
102 filtered_signal[i + NB_LSP_COEFF] = saturate(pshr(acc, 12), MAX_16 as Word32) as Word16;
103 }
104}
105
106pub fn dot_product(x: &[Word16], y: &[Word16]) -> Word32 {
107 let len = x.len().min(y.len());
108 #[allow(unused)]
109 let mut sum: Word32 = 0;
110 let mut i = 0;
111
112 #[cfg(target_arch = "aarch64")]
113 unsafe {
114 let mut sum_vec = vdupq_n_s32(0);
115 while i + 8 <= len {
116 let a = vld1q_s16(x.as_ptr().add(i));
117 let b = vld1q_s16(y.as_ptr().add(i));
118 let a_low = vget_low_s16(a);
119 let b_low = vget_low_s16(b);
120 let a_high = vget_high_s16(a);
121 let b_high = vget_high_s16(b);
122
123 sum_vec = vmlal_s16(sum_vec, a_low, b_low);
124 sum_vec = vmlal_s16(sum_vec, a_high, b_high);
125
126 i += 8;
127 }
128 sum = vaddvq_s32(sum_vec);
129 }
130
131 #[cfg(target_arch = "x86_64")]
132 unsafe {
133 let mut sum_vec = _mm_setzero_si128();
134 while i + 8 <= len {
135 let a = _mm_loadu_si128(x.as_ptr().add(i) as *const _);
136 let b = _mm_loadu_si128(y.as_ptr().add(i) as *const _);
137 let prod = _mm_madd_epi16(a, b);
138 sum_vec = _mm_add_epi32(sum_vec, prod);
139 i += 8;
140 }
141 let high = _mm_unpackhi_epi64(sum_vec, sum_vec);
142 let sum_vec = _mm_add_epi32(sum_vec, high);
143 let high = _mm_shuffle_epi32(sum_vec, 1);
144 let sum_vec = _mm_add_epi32(sum_vec, high);
145 sum = _mm_cvtsi128_si32(sum_vec);
146 }
147
148 while i < len {
149 sum = mac16_16(sum, x[i], y[i]);
150 i += 1;
151 }
152 sum
153}
154
155pub fn dot_product_16_32_q12(x: &[Word16], y: &[Word32]) -> Word32 {
156 let len = x.len().min(y.len());
157 #[allow(unused)]
158 let mut sum: Word32 = 0;
159 let mut i = 0;
160
161 #[cfg(target_arch = "aarch64")]
162 unsafe {
163 let mut sum_vec = vdupq_n_s32(0);
164 while i + 4 <= len {
165 let a = vld1_s16(x.as_ptr().add(i)); let b = vld1q_s32(y.as_ptr().add(i)); let a_32 = vmovl_s16(a); let prod_low = vmull_s32(vget_low_s32(a_32), vget_low_s32(b));
172 let prod_high = vmull_high_s32(a_32, b);
173
174 let prod_low_shifted = vshrq_n_s64(prod_low, 12);
176 let prod_high_shifted = vshrq_n_s64(prod_high, 12);
177
178 let res_low = vmovn_s64(prod_low_shifted); let res_high = vmovn_s64(prod_high_shifted); let res = vcombine_s32(res_low, res_high);
184
185 sum_vec = vaddq_s32(sum_vec, res);
187
188 i += 4;
189 }
190 sum = vaddvq_s32(sum_vec);
191 }
192
193 while i < len {
194 sum = mac16_32_q12(sum, x[i], y[i]);
195 i += 1;
196 }
197 sum
198}
199
200pub fn vec_mult_16_16(x: &[Word16], y: &[Word16], out: &mut [Word32]) {
201 let len = x.len().min(y.len()).min(out.len());
202 let mut i = 0;
203
204 #[cfg(target_arch = "aarch64")]
205 unsafe {
206 while i + 8 <= len {
207 let a = vld1q_s16(x.as_ptr().add(i));
208 let b = vld1q_s16(y.as_ptr().add(i));
209
210 let prod_low = vmull_s16(vget_low_s16(a), vget_low_s16(b));
211 let prod_high = vmull_high_s16(a, b);
212
213 vst1q_s32(out.as_mut_ptr().add(i), prod_low);
214 vst1q_s32(out.as_mut_ptr().add(i + 4), prod_high);
215
216 i += 8;
217 }
218 }
219
220 #[cfg(target_arch = "x86_64")]
221 unsafe {
222 while i + 8 <= len {
223 let a = _mm_loadu_si128(x.as_ptr().add(i) as *const _);
224 let b = _mm_loadu_si128(y.as_ptr().add(i) as *const _);
225
226 let lo = _mm_mullo_epi16(a, b);
227 let hi = _mm_mulhi_epi16(a, b);
228
229 let res_lo = _mm_unpacklo_epi16(lo, hi);
230 let res_hi = _mm_unpackhi_epi16(lo, hi);
231
232 _mm_storeu_si128(out.as_mut_ptr().add(i) as *mut _, res_lo);
233 _mm_storeu_si128(out.as_mut_ptr().add(i + 4) as *mut _, res_hi);
234
235 i += 8;
236 }
237 }
238
239 while i < len {
240 out[i] = mult16_16(x[i], y[i]);
241 i += 1;
242 }
243}
244
245pub fn correlate_vectors(x: &[Word16], y: &[Word16], c: &mut [Word32]) {
246 for i in 0..L_SUBFRAME {
247 c[i] = dot_product(&x[i..L_SUBFRAME], &y[0..L_SUBFRAME - i]);
248 }
249}
250
251#[inline]
252pub fn count_leading_zeros(x: Word32) -> UWord16 {
253 if x == 0 {
254 31
255 } else {
256 (x as u32).leading_zeros() as UWord16 - 1
257 }
258}
259
260#[inline]
261pub fn unsigned_count_leading_zeros(x: UWord32) -> UWord16 {
262 x.leading_zeros() as UWord16
263}
264
265pub fn ma_code_gain_prediction(
266 previous_gain_prediction_error: &[Word16],
267 fixed_codebook_vector: &[Word16],
268) -> Word32 {
269 let mut fixed_codebook_vector_squares_sum: Word32 = 0;
271
272 for i in 0..L_SUBFRAME {
273 if fixed_codebook_vector[i] != 0 {
274 fixed_codebook_vector_squares_sum = mac16_16(
275 fixed_codebook_vector_squares_sum,
276 fixed_codebook_vector[i],
277 fixed_codebook_vector[i],
278 );
279 }
280 }
281
282 let mut acc = mac16_32_q13(
284 8145364,
285 -24660,
286 g729_log2_q0q16(fixed_codebook_vector_squares_sum),
287 ); acc = shl(acc, 8); for i in 0..4 {
292 acc = mac16_16(
293 acc,
294 previous_gain_prediction_error[i],
295 MA_PREDICTION_COEFFICIENTS[i],
296 );
297 }
298
299 acc = shr(acc, 2); acc = mult16_32_q15(5442, acc); acc = pshr(acc, 11); g729_exp2_q11q16(acc as Word16)
308}
309
310pub fn compute_gain_prediction_error(
311 fixed_codebook_gain_correction_factor: Word16,
312 previous_gain_prediction_error: &mut [Word16],
313) {
314 let mut current_gain_prediction_error = sub32(
319 g729_log2_q0q16(fixed_codebook_gain_correction_factor as Word32),
320 786432,
321 );
322 current_gain_prediction_error = pshr(mult16_32_q12(24660, current_gain_prediction_error), 6); previous_gain_prediction_error[3] = previous_gain_prediction_error[2];
326 previous_gain_prediction_error[2] = previous_gain_prediction_error[1];
327 previous_gain_prediction_error[1] = previous_gain_prediction_error[0];
328 previous_gain_prediction_error[0] = current_gain_prediction_error as Word16;
329}
330
331pub fn parameters_array_2_bit_stream(parameters: &[UWord16], bit_stream: &mut [u8]) {
332 bit_stream[0] = (((parameters[0] & 0x1) << 7) | (parameters[1] & 0x7f)) as u8;
333
334 bit_stream[1] = (((parameters[2] & 0x1f) << 3) | ((parameters[3] >> 2) & 0x7)) as u8;
335
336 bit_stream[2] = (((parameters[3] & 0x3) << 6) | ((parameters[4] >> 2) & 0x3f)) as u8;
337
338 bit_stream[3] = (((parameters[4] & 0x3) << 6)
339 | ((parameters[5] & 0x1) << 5)
340 | ((parameters[6] >> 8) & 0x1f)) as u8;
341
342 bit_stream[4] = (parameters[6] & 0xff) as u8;
343
344 bit_stream[5] = (((parameters[7] & 0xf) << 4)
345 | ((parameters[8] & 0x7) << 1)
346 | ((parameters[9] >> 3) & 0x1)) as u8;
347
348 bit_stream[6] = (((parameters[9] & 0x7) << 5) | (parameters[10] & 0x1f)) as u8;
349
350 bit_stream[7] = ((parameters[11] >> 5) & 0xff) as u8;
351
352 bit_stream[8] = (((parameters[11] & 0x1f) << 3) | ((parameters[12] >> 1) & 0x7)) as u8;
353
354 bit_stream[9] = (((parameters[12] & 0x1) << 7)
355 | ((parameters[13] & 0x7) << 4)
356 | (parameters[14] & 0xf)) as u8;
357}
358
359pub fn cng_parameters_array_2_bit_stream(parameters: &[UWord16], bit_stream: &mut [u8]) {
360 bit_stream[0] = (((parameters[0] & 0x1) << 7)
361 | ((parameters[1] & 0x1f) << 2)
362 | ((parameters[2] >> 2) & 0x3)) as u8;
363
364 bit_stream[1] = (((parameters[2] & 0x03) << 6) | ((parameters[3] & 0x1f) << 1)) as u8;
365}
366
367pub fn parameters_bit_stream_2_array(bit_stream: &[u8], parameters: &mut [UWord16]) {
368 parameters[0] = ((bit_stream[0] >> 7) & 0x1) as UWord16;
369 parameters[1] = (bit_stream[0] & 0x7f) as UWord16;
370 parameters[2] = ((bit_stream[1] >> 3) & 0x1f) as UWord16;
371 parameters[3] =
372 (((bit_stream[1] & 0x7) as UWord16) << 2) | ((bit_stream[2] >> 6) & 0x3) as UWord16;
373 parameters[4] =
374 (((bit_stream[2] & 0x3f) as UWord16) << 2) | ((bit_stream[3] >> 6) & 0x3) as UWord16;
375 parameters[5] = ((bit_stream[3] >> 5) & 0x1) as UWord16;
376 parameters[6] = (((bit_stream[3] & 0x1f) as UWord16) << 8) | bit_stream[4] as UWord16;
377 parameters[7] = ((bit_stream[5] >> 4) & 0xf) as UWord16;
378 parameters[8] = ((bit_stream[5] >> 1) & 0x7) as UWord16;
379 parameters[9] =
380 (((bit_stream[5] & 0x1) as UWord16) << 3) | ((bit_stream[6] >> 5) & 0x7) as UWord16;
381 parameters[10] = (bit_stream[6] & 0x1f) as UWord16;
382 parameters[11] = ((bit_stream[7] as UWord16) << 5) | ((bit_stream[8] >> 3) & 0x1f) as UWord16;
383 parameters[12] =
384 (((bit_stream[8] & 0x7) as UWord16) << 1) | ((bit_stream[9] >> 7) & 0x1) as UWord16;
385 parameters[13] = ((bit_stream[9] >> 4) & 0x7) as UWord16;
386 parameters[14] = (bit_stream[9] & 0xf) as UWord16;
387}
388
389pub fn pseudo_random(random_generator_seed: &mut UWord16) -> UWord16 {
390 let res = mac16_16(13849, *random_generator_seed as Word16, 31821);
397 *random_generator_seed = res as UWord16;
398 *random_generator_seed
399}
400
401#[cfg(test)]
402mod tests {
403 use super::*;
404
405 #[test]
406 fn test_dot_product() {
407 let x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
408 let y = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
409 assert_eq!(dot_product(&x, &y), 55);
411
412 let x = [MAX_16, 1];
413 let y = [1, 1];
414 assert_eq!(dot_product(&x, &y), MAX_16 as Word32 + 1);
415
416 let x = [-1, -2];
418 let y = [1, 1];
419 assert_eq!(dot_product(&x, &y), -3);
420 }
421}