Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "functions.h"
11 :
12 0 : static Word16 stage1_base( /* o : idx */
13 : const Word16 *t, /* i : target SCFs */
14 : #ifdef ENABLE_HR_MODE
15 : const Word32 *cdbk, /* i : SCFs cdbk */
16 : #else
17 : const Word16 *cdbk, /* i : SCFs cdbk */
18 : #endif
19 : const Word16 R /* i : number of rows in codebook */
20 : )
21 : {
22 : Counter row;
23 : Word16 k_ptr, idx;
24 : Word32 L_min_mse, L_mse;
25 : Counter col;
26 : #ifdef ENABLE_HR_MODE
27 : Word32 err;
28 : #else
29 : Word16 err;
30 : #endif
31 :
32 : #ifdef DYNMEM_COUNT
33 : Dyn_Mem_In("stage1_base", sizeof(struct {
34 : Counter row, col;
35 : Word16 k_ptr, idx, err;
36 : Word32 L_min_mse, L_mse;
37 : }));
38 : #endif
39 : #ifdef WMOPS
40 : push_wmops("stage1_base");
41 : #endif
42 :
43 : /* find first vector error energy for */
44 : /* loop probably works with saturation , but it should not occur anyway */
45 0 : L_min_mse = L_add(0, 0); /* init acc with absolute min mse sofar */
46 0 : FOR (col = 0; col < M / 2; col++) /* fixed to 8 elements */
47 : {
48 : #ifdef ENABLE_HR_MODE
49 0 : err = L_sub(cdbk[col], L_deposit_h(t[col])); /* cdbk max abs value is 2048 = 2.^11 , max nb col is 2^3 max
50 : target is approx similar (2.^14/M)*2 = +/- 2048 , errmax is 4096 */
51 0 : L_min_mse = L_add(L_min_mse, Mpy_32_32_lc3plus(err, err));
52 : #else
53 : err = sub(cdbk[col], t[col]); /* cdbk max abs value is 2048 = 2.^11 , max nb col is 2^3 max target is approx
54 : similar (2.^14/M)*2 = +/- 2048 , errmax is 4096 */
55 : L_min_mse = L_mac0(L_min_mse, err, err); /* max L_min_mse is 8*4096*4096 =2.^(3+12+12) = 2.^27 */
56 : #endif
57 : }
58 :
59 0 : idx = 0; move16();
60 :
61 0 : k_ptr = M / 2; move16(); /* ptr init to second row */
62 0 : FOR (row = 1; row < R; row++)
63 : {
64 : /* loop probably works with saturation , but it should not occur anyway */
65 :
66 0 : L_mse = L_add(L_min_mse, 0); /* init acc with min mse sofar , */
67 0 : FOR (col = 0; col < M / 2; col++) /* fixed to 8 elements */
68 : {
69 : #ifdef ENABLE_HR_MODE
70 0 : err = L_sub(cdbk[k_ptr++], L_deposit_h(t[col]));
71 0 : L_mse = L_sub(L_mse, Mpy_32_32_lc3plus(err, err));
72 : #else
73 : err = sub(cdbk[k_ptr++], t[col]);
74 : L_mse = L_msu0(L_mse, err,
75 : err); /* NB subtraction from best MSE error sofar in acc , saturation may not occur */
76 : #endif
77 : }
78 :
79 0 : L_min_mse = L_sub(L_min_mse, L_max(L_mse, 0L)); /* ALWAYS update best MSE error sofar */
80 :
81 0 : if (L_mse > 0L) /* if acc value still is positive a new lower error energy vector was found in this row */
82 : {
83 0 : idx = row; move16(); /* update 1-8 bits idx */
84 : }
85 :
86 : /* this inner loop(always updating L_min_mse), (L_msu, if ) consumes AV 19, WC ~20 STL cycles ,
87 : compared to a conventional(L_mac, IF( ) ) AV 21 WC ~23 STL cycles per
88 : loop */
89 : }
90 0 : ASSERT(idx >= 0 && idx < R);
91 :
92 : #ifdef WMOPS
93 : pop_wmops();
94 : #endif
95 : #ifdef DYNMEM_COUNT
96 : Dyn_Mem_Out();
97 : #endif
98 :
99 0 : return idx;
100 : }
101 :
102 0 : static void first_stage_split_search(
103 : #ifdef ENABLE_HR_MODE
104 : const Word32 *cbk_LF, const Word32 *cbk_HF,
105 : #else
106 : const Word16 *cbk_LF, const Word16 *cbk_HF,
107 : #endif
108 : const Word16 *target,
109 : const Word16 nbCbkEntries, Word16 *idxLF, Word16 *idxHF)
110 : {
111 : /* find base index for each SCF split */
112 0 : *idxLF = stage1_base(target, cbk_LF, nbCbkEntries);
113 0 : *idxHF = stage1_base((&target[M / 2]), cbk_HF, nbCbkEntries);
114 0 : }
115 :
116 0 : static void processDeQuantize_stage1ScfDecStage1_fx(
117 : #ifdef ENABLE_HR_MODE
118 : const Word32 *cbk_LF, const Word32 *cbk_HF,
119 : #else
120 : const Word16 *cbk_LF, const Word16 *cbk_HF,
121 : #endif
122 : Word16 st1_idx0, Word16 st1_idx1,
123 : #ifdef ENABLE_HR_MODE
124 : Word32 *st1_vector
125 : #else
126 : Word16 *st1_vector
127 : #endif
128 : )
129 : {
130 : Counter col;
131 : Word16 offset0, offset1;
132 : #ifdef DYNMEM_COUNT
133 : Dyn_Mem_In("processDeQuantize_stage1ScfDecStage1_fx", sizeof(struct {
134 : Word16 offset0, offset1;
135 : Counter col;
136 : }));
137 : #endif
138 :
139 0 : offset0 = shl_pos(st1_idx0, 3); /* mult by M/2 */
140 0 : offset1 = shl_pos(st1_idx1, 3);
141 0 : FOR (col = 0; col < M / 2; col++)
142 : {
143 0 : st1_vector[col] = cbk_LF[offset0++]; move16();
144 0 : st1_vector[col + 8] = cbk_HF[offset1++]; move16();
145 : #ifdef ENABLE_HR_MODE
146 0 : move16();
147 0 : move16();
148 : #endif
149 : }
150 : #ifdef DYNMEM_COUNT
151 : Dyn_Mem_Out();
152 : #endif
153 0 : }
154 :
155 0 : void downshift_w32_arr(Word32 *w32_arr, Word16 *w16_arr, Word16 shft_val, Word32 len)
156 : {
157 : Word32 i;
158 0 : FOR (i = 0; i < len; i++)
159 : {
160 0 : w16_arr[i] = extract_l(L_shr_pos(w32_arr[i], shft_val));
161 0 : move16();
162 : }
163 0 : return;
164 : }
165 :
166 0 : void round_w32tow16_arr(Word32 *w32_arr, Word16 *w16_arr,Word32 len)
167 : {
168 : Word32 i;
169 0 : FOR (i = 0; i < len; i++)
170 : {
171 0 : w16_arr[i] = round_fx(w32_arr[i]);
172 0 : move16();
173 : }
174 0 : return;
175 : }
176 :
177 0 : static void processQuantize_stage1ScfEncStage1_fx(const Word16 *target_st1,
178 : #ifdef ENABLE_HR_MODE
179 : Word32 *st1_vector,
180 : #else
181 : Word16 *st1_vector,
182 : #endif
183 : Word16 *st1_idx0Ptr, Word16 *st1_idx1Ptr)
184 :
185 : {
186 : #ifdef WMOPS
187 : push_wmops("processQuantize_stage1ScfEncStage1_fx");
188 : #endif
189 :
190 : #ifdef ENABLE_HR_MODE
191 0 : first_stage_split_search(st1SCF0_7_base5_32x8_Q27, st1SCF8_15_base5_32x8_Q27, target_st1, SCF_STAGE1_NBCDKENTRIES,
192 : st1_idx0Ptr, st1_idx1Ptr);
193 :
194 0 : processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q27, st1SCF8_15_base5_32x8_Q27, *st1_idx0Ptr,
195 0 : *st1_idx1Ptr, st1_vector);
196 : #else
197 : first_stage_split_search(st1SCF0_7_base5_32x8_Q11, st1SCF8_15_base5_32x8_Q11, target_st1, SCF_STAGE1_NBCDKENTRIES,
198 : st1_idx0Ptr, st1_idx1Ptr);
199 :
200 : processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q11, st1SCF8_15_base5_32x8_Q11, *st1_idx0Ptr,
201 : *st1_idx1Ptr, st1_vector);
202 : #endif
203 :
204 : #ifdef WMOPS
205 : pop_wmops();
206 : #endif
207 :
208 0 : return;
209 : }
210 :
211 : /* gain-shape MSE search in warped SCF-residual domain, synthesis in SCF resiudal domain allows for easy weighting */
212 :
213 0 : static void pvq_enc_find_best_submode_pre_post_fx(
214 : #ifdef ENABLE_HR_MODE
215 : const Word32 *target_st2, /* this target is in the linearized warped domain , same as input to PVQ search */
216 : #else
217 : const Word16 *target_st2, /* this target is in the linearized warped domain , same as input to PVQ search */
218 : #endif
219 : const Word16 *enc_pulses_far, Word16 *enc_pulses_near, const Word16 *enc_pulsesA, const Word16 *enc_pulsesB,
220 : Word16 *sub_mode_ptr, Word16 *i_gain_ptr,
221 : #ifdef ENABLE_HR_MODE
222 : Word32 *enc_adj_glob_warped_vec,
223 : #else
224 : Word16 *enc_adj_glob_warped_vec,
225 : #endif
226 : Word8 *scratchBuffer) /* Size = 18 * M */
227 : {
228 :
229 : Counter L_section, idx;
230 : #ifdef ENABLE_HR_MODE
231 : const Word32 *search_en1shape[N_SCF_SHAPES_ST2];
232 : #else
233 : const Word16 *search_en1shape[N_SCF_SHAPES_ST2];
234 : #endif
235 : const Word16 *search_gainTab[N_SCF_SHAPES_ST2];
236 : Word16 search_n_gains[N_SCF_SHAPES_ST2];
237 : Word32 L_mse, L_mse_min, L_idx;
238 : Word16 * pulses_far, *pulses_near, *pulsesAB, *pulsesA;
239 : #ifdef ENABLE_HR_MODE
240 : Word32 * target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
241 : #else
242 : Word16 * target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
243 : #endif
244 : #ifdef ENABLE_HR_MODE
245 : Word32 tmp, err;
246 : #else
247 : Word16 tmp, err;
248 : #endif
249 : Counter i;
250 :
251 : #ifdef DYNMEM_COUNT
252 : #ifdef ENABLE_HR_MODE
253 : Dyn_Mem_In("pvq_enc_find_best_submode_pre_post_fx", sizeof(struct {
254 : Counter i, L_section, idx;
255 : Word32 *search_en1shape[N_SCF_SHAPES_ST2];
256 : Word16 *search_gainTab[N_SCF_SHAPES_ST2];
257 : Word16 search_n_gains[N_SCF_SHAPES_ST2];
258 : Word32 L_mse, L_mse_min, L_idx;
259 : Word16 *pulses_far, *pulses_near, *pulsesAB, *pulsesA;
260 : Word32 *target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
261 : Word32 tmp, err;
262 : }));
263 : #else
264 : Dyn_Mem_In("pvq_enc_find_best_submode_pre_post_fx", sizeof(struct {
265 : Counter i, L_section, idx;
266 : Word16 *search_en1shape[N_SCF_SHAPES_ST2];
267 : Word16 *search_gainTab[N_SCF_SHAPES_ST2];
268 : Word16 search_n_gains[N_SCF_SHAPES_ST2];
269 : Word32 L_mse, L_mse_min, L_idx;
270 : Word16 *pulses_far, *pulses_near, *pulsesAB, *pulsesA;
271 : Word16 *target_w, *shape_far, *shape_near, *shapeAB, *shapeA;
272 : Word16 tmp, err;
273 : }));
274 : #endif /* ENABLE_HR_MODE */
275 : #endif /* DYNMEM_COUNT */
276 :
277 0 : pulses_near = (Word16 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * M */
278 :
279 0 : pulsesAB = (Word16 *)scratchAlign(pulses_near, sizeof(*pulses_near) * M); /* Size = 2 * M */
280 :
281 0 : pulsesA = (Word16 *)scratchAlign(pulsesAB, sizeof(*pulsesAB) * M); /* Size = 2 * M */
282 :
283 : #ifdef ENABLE_HR_MODE
284 0 : target_w = (Word32 *)scratchAlign(pulsesA, sizeof(*pulsesA) * M); /* Size = 2 * M */
285 :
286 0 : shape_near = (Word32 *)scratchAlign(target_w, sizeof(*target_w) * M); /* Size = 4 * M */
287 :
288 0 : shapeAB = (Word32 *)scratchAlign(shape_near, sizeof(*shape_near) * M); /* Size = 4 * M */
289 :
290 0 : shapeA = (Word32 *)scratchAlign(shapeAB, sizeof(*shapeAB) * M); /* Size = 4 * M */
291 : #else
292 : target_w = (Word16 *)scratchAlign(pulsesA, sizeof(*pulsesA) * M); /* Size = 2 * M */
293 :
294 : shape_near = (Word16 *)scratchAlign(target_w, sizeof(*target_w) * M); /* Size = 2 * M */
295 :
296 : shapeAB = (Word16 *)scratchAlign(shape_near, sizeof(*shape_near) * M); /* Size = 2 * M */
297 :
298 : shapeA = (Word16 *)scratchAlign(shapeAB, sizeof(*shapeAB) * M); /* Size = 2 * M */
299 : #endif
300 :
301 0 : pulses_far = (Word16 *)scratchAlign(shapeA, sizeof(*shapeA) * M); /* Size = 2 * M */
302 :
303 : #ifdef ENABLE_HR_MODE
304 0 : shape_far = (Word32 *)scratchAlign(pulses_far, sizeof(*pulses_far) * M); /* Size = 2 * M */
305 : #else
306 : shape_far = (Word16 *)scratchAlign(pulses_far, sizeof(*pulses_far) * M); /* Size = 2 * M */
307 : #endif
308 :
309 : #ifdef WMOPS
310 : push_wmops("pvq_enc_find_best_submode_pre_post_fx");
311 : #endif
312 :
313 : /* construct pulse vectors and en1 normalized shape vectors */ /* use shape Q in Q14 */
314 0 : basop_memmove(pulses_far, enc_pulses_far, M * sizeof(*pulses_far));
315 0 : basop_memmove(pulses_near, enc_pulses_near, M * sizeof(*pulses_near));
316 0 : basop_memmove(target_w, target_st2, M * sizeof(*target_w));
317 :
318 0 : pvq_dec_en1_normQ14_fx(shape_near, pulses_near, sns_Kval[2][0], M); /* near outlier mode */
319 0 : pvq_dec_en1_normQ14_fx(shape_far, pulses_far, sns_Kval[3][0], M); /* far outlier mode */
320 :
321 : /* regular mode(with a split), prepare vectors of full length M */
322 0 : basop_memmove(pulsesAB, enc_pulsesA, N_SETA * sizeof(*pulsesAB));
323 0 : basop_memmove(pulsesA, enc_pulsesA, N_SETA * sizeof(*pulsesA));
324 :
325 0 : FOR (i = N_SETA; i < M; i++)
326 : {
327 0 : pulsesAB[i] = enc_pulsesB[sub(i, N_SETA)]; move16();
328 : }
329 :
330 : IF (M > N_SETA)
331 : {
332 0 : basop_memset(&pulsesA[N_SETA], 0, (M - N_SETA) * sizeof(*pulsesA));
333 : }
334 :
335 0 : pvq_dec_en1_normQ14_fx(shapeAB, pulsesAB, sns_Kval[0][0], M);
336 : /* regular AB , b_pulses = 1 ;*/ /* OPT: combine with shapeA */
337 :
338 0 : pvq_dec_en1_normQ14_fx(shapeA, pulsesA, sns_Kval[1][0], M);
339 : /* regular A , b_pulses = 0 */ /* OPT: M-> N_SETA */
340 :
341 : /* setup search structure */
342 :
343 : /* now aligned with order of j {regular=0, regular_lf=1, outlier_near=2, outlier far=3} */
344 :
345 0 : search_en1shape[0] = shapeAB;
346 0 : search_gainTab[0] = sns_gaintabPtr[0];
347 0 : search_n_gains[0] = sns_gainSz[0]; /* assumes whole bits */
348 :
349 0 : search_en1shape[1] = shapeA;
350 0 : search_gainTab[1] = sns_gaintabPtr[1];
351 0 : search_n_gains[1] = sns_gainSz[1]; /* assumes whole bits */
352 :
353 0 : search_en1shape[2] = shape_near;
354 0 : search_gainTab[2] = sns_gaintabPtr[2];
355 0 : search_n_gains[2] = sns_gainSz[2]; /*assume whole bits */
356 :
357 0 : search_en1shape[3] = shape_far;
358 0 : search_gainTab[3] = sns_gaintabPtr[3];
359 0 : search_n_gains[3] = sns_gainSz[3]; /*assume whole bits */
360 :
361 : /* start actual search loop */
362 :
363 : /* basic raw MSE loop, */
364 0 : L_mse_min = INT32_MAX; move32();
365 0 : L_idx = L_deposit_l(-1); /* section in low 2 bits* gain idx above */
366 :
367 0 : FOR (L_section = 0; L_section < N_SCF_SHAPES_ST2; L_section++)
368 : {
369 : /* raw MSE over gain and shape */
370 0 : FOR (idx = 0; idx < search_n_gains[L_section]; idx++)
371 : {
372 : /* MSE ( proc_target_local[i]-adjGain[i]*en1Shape[i] ) */
373 :
374 0 : L_mse = L_deposit_l(0);
375 0 : FOR (i = 0; i < M; i++)
376 : {
377 : #ifdef ENABLE_HR_MODE
378 0 : tmp = Mpy_32_16_lc3plus(search_en1shape[L_section][i], search_gainTab[L_section][idx]); /* Q30 + 14 - 15 = Q29 */
379 0 : err = L_sub(target_w[i], tmp); /* both in Q29 */
380 0 : L_mse = L_add(L_mse, L_shr_pos(Mpy_32_32_lc3plus(err, err), 1)); /* Q29+29-31 = Q27 */
381 : #else
382 : tmp = mult_r(search_gainTab[L_section][idx], search_en1shape[L_section][i]); /* Q15+14+1-16= Q14 */
383 : err = sub(target_w[i], tmp); /* both in Q14 */
384 : L_mse = L_mac0(L_mse, err, err); /* Q14+14 = Q28 */
385 : #endif /* Q14+14 = Q28 */
386 : }
387 :
388 0 : IF (L_sub(L_mse, L_mse_min) < 0) /* OPT: always update L_mse_min) */
389 : {
390 0 : L_mse_min = L_mse; move32();
391 0 : L_idx = L_mac0(L_section, idx, 1 << 2); /* save both section and gain idx */
392 : }
393 : } /* gains */
394 : } /*submodes*/
395 :
396 0 : L_section = L_and(0x3L, L_idx); /* section was stored in two lowest bits */
397 0 : ASSERT(L_section >= 0 && L_section <= 3);
398 0 : *i_gain_ptr = extract_l(L_shr_pos(L_idx, 2)); /*1,2,3 bit gain */
399 0 : ASSERT(*i_gain_ptr >= 0 && *i_gain_ptr <= 7);
400 :
401 : /* returns a scaled and transformed vector, ___EXACTLY__ as a decoder would scale it */
402 0 : ASSERT(enc_adj_glob_warped_vec != NULL);
403 : {
404 : /* warp/rotate search result to SCF residual domain */
405 : #ifdef ENABLE_HR_MODE
406 0 : idct32_32_fx(search_en1shape[L_section], target_w);
407 : #else
408 : idct16_fx(search_en1shape[L_section], target_w); /* fwd synthesis warping */
409 : #endif
410 : /* actual synthesis gain scaling in SCF-residual domain, for easy weighting analysis */
411 0 : pvq_dec_scale_vec_fx(target_w, search_gainTab[L_section][*i_gain_ptr], enc_adj_glob_warped_vec);
412 : }
413 :
414 0 : *sub_mode_ptr = extract_l(L_section);
415 0 : move16(); /* 0,1,2,3 */
416 :
417 : #ifdef WMOPS
418 : pop_wmops();
419 : #endif
420 : #ifdef DYNMEM_COUNT
421 : Dyn_Mem_Out();
422 : #endif
423 0 : return;
424 : }
425 :
426 0 : static void processQuantize_stage2ScfEncStage2_fx(
427 : #ifdef ENABLE_HR_MODE
428 : const Word32 *target_st2, Word32 *st2_vector,
429 : #else
430 : const Word16 *target_st2, Word16 *st2_vector,
431 : #endif
432 : Word32 *L_prm_idx,
433 : Word16 submodes, Word8 *scratchBuffer) /* Size = 26 * M + 48 */
434 : { /*func */
435 : #ifdef ENABLE_HR_MODE
436 : Word32 *proc_target;
437 : #else
438 : Word16 *proc_target;
439 : #endif
440 :
441 : Word16 *enc_pulses_far, *enc_pulses_near, *enc_pulsesA, *enc_pulsesB;
442 :
443 : Word16 *pulses_fin, *pulses_proj;
444 : Word32 L_tmp;
445 :
446 : Word8 *buffer_pvq_enc_find_best_submode_pre_post_fx;
447 :
448 : PvqEntry_fx enc_PVQ_OA, enc_PVQ_B;
449 : Word16 submode, i_gain, submodeMSB, submodeLSB;
450 : Word32 * L_search_corr, *L_search_en;
451 : #ifdef ENABLE_HR_MODE
452 : Word16 * proc_target_lp;
453 : #endif
454 :
455 : #ifdef DYNMEM_COUNT
456 : #ifdef ENABLE_HR_MODE
457 : Dyn_Mem_In("processQuantize_stage2ScfEncStage2_fx", sizeof(struct {
458 : Word32 *proc_target;
459 : Word16 *enc_pulses_far, *enc_pulses_near, *enc_pulsesA, *enc_pulsesB;
460 : Word16 *pulses_fin, *pulses_proj;
461 : Word32 L_tmp;
462 : Word8 *buffer_pvq_enc_find_best_submode_pre_post_fx;
463 : PvqEntry_fx enc_PVQ_OA, enc_PVQ_B;
464 : Word16 submode, i_gain, submodeMSB, submodeLSB;
465 : Word32 * L_search_corr, *L_search_en;
466 : Word16 * proc_target_lp;
467 : }));
468 : #else
469 : Dyn_Mem_In("processQuantize_stage2ScfEncStage2_fx", sizeof(struct {
470 : Word16 *proc_target;
471 : Word16 *enc_pulses_far, *enc_pulses_near, *enc_pulsesA, *enc_pulsesB;
472 : Word16 *pulses_fin, *pulses_proj;
473 : Word32 L_tmp;
474 : Word8 *buffer_pvq_enc_find_best_submode_pre_post_fx;
475 : PvqEntry_fx enc_PVQ_OA, enc_PVQ_B;
476 : Word16 submode, i_gain, submodeMSB, submodeLSB;
477 : Word32 * L_search_corr, *L_search_en;
478 : }));
479 : #endif /* ENABLE_HR_MODE */
480 : #endif /* DYNMEM_COUNT */
481 :
482 : #ifdef ENABLE_HR_MODE
483 0 : buffer_pvq_enc_find_best_submode_pre_post_fx = (Word8 *) scratchAlign(scratchBuffer, 0);
484 0 : proc_target = (Word32 *) scratchAlign(buffer_pvq_enc_find_best_submode_pre_post_fx, sizeof(*buffer_pvq_enc_find_best_submode_pre_post_fx) * 28 * M);
485 : #else
486 : buffer_pvq_enc_find_best_submode_pre_post_fx = scratchAlign(scratchBuffer, 0); /* Size = 18 * M */
487 : proc_target =
488 : (Word16 *)scratchAlign(buffer_pvq_enc_find_best_submode_pre_post_fx,
489 : sizeof(*buffer_pvq_enc_find_best_submode_pre_post_fx) * 18 * M); /* Size = 2 * M */
490 : #endif
491 :
492 0 : enc_pulses_near = (Word16 *)scratchAlign(proc_target, sizeof(*proc_target) * M); /* Size = 2 * M */
493 0 : enc_pulsesA = (Word16 *)scratchAlign(enc_pulses_near, sizeof(*enc_pulses_near) * M); /* Size = 2 * N_SETA */
494 0 : enc_pulsesB = (Word16 *)scratchAlign(enc_pulsesA, sizeof(*enc_pulsesA) * N_SETA); /* Size = 2 * N_SETB */
495 0 : pulses_fin = (Word16 *)scratchAlign(enc_pulsesB, sizeof(*enc_pulsesB) * N_SETB); /* Size = 2 * N_SCF_SHAPES_ST2 */
496 0 : pulses_proj =
497 0 : (Word16 *)scratchAlign(pulses_fin, sizeof(*pulses_fin) * N_SCF_SHAPES_ST2); /* Size = 2 * N_SCF_SHAPES_ST2 */
498 0 : L_search_corr =
499 0 : (Word32 *)scratchAlign(pulses_proj, sizeof(*pulses_proj) * N_SCF_SHAPES_ST2); /* Size = 4 * N_SCF_SHAPES_ST2 */
500 0 : L_search_en = (Word32 *)scratchAlign(L_search_corr,
501 : sizeof(*L_search_corr) * N_SCF_SHAPES_ST2); /* Size = 4 * N_SCF_SHAPES_ST2 */
502 0 : enc_pulses_far = (Word16 *)scratchAlign(L_search_en, sizeof(*L_search_en) * N_SCF_SHAPES_ST2); /* Size = 2 * M */
503 :
504 : #ifdef ENABLE_HR_MODE
505 0 : proc_target_lp = (Word16 *)buffer_pvq_enc_find_best_submode_pre_post_fx; /* size = 2*M */
506 : #endif
507 :
508 : #ifdef WMOPS
509 : push_wmops("processQuantize_stage2ScfEncStage2_fx");
510 : #endif
511 :
512 : /* fixed setup for a given bitrate of 38 , no moves needed */
513 : /* k_far = sns_Kval[3][0]; */
514 : /* k_near = sns_Kval[2][0]; */
515 : /* kA = sns_Kval[1][0]; */ /* regular, regular_lf */
516 : /* kB is always 1 */
517 :
518 : /* NB these search indecese do not correspond exactly to specification shape_index j */
519 :
520 0 : pulses_fin[0] = sns_Kval[3][0]; /* far 6 */
521 0 : pulses_fin[1] = sns_Kval[2][0]; /* near 8 */
522 0 : pulses_fin[2] = sns_Kval[1][0]; /* section A 10 */
523 0 : pulses_fin[3] = sns_Kval[0][1]; /* section B 1 */
524 :
525 0 : pulses_proj[0] = sns_Kval[3][0];
526 0 : pulses_proj[1] = 0;
527 0 : pulses_proj[2] = 0;
528 0 : pulses_proj[3] = 0;
529 :
530 : /* pre_process */
531 : #ifdef ENABLE_HR_MODE
532 0 : dct32_fx(target_st2, proc_target); /* enc analysis */
533 0 : downshift_w32_arr(proc_target, proc_target_lp, 16, M);
534 :
535 : /* get the initial four integer shape candidate vectors, no normalization at this stage */
536 0 : pvq_enc_search_fx(proc_target_lp, enc_pulses_far, enc_pulses_near, enc_pulsesA, enc_pulsesB, L_search_corr,
537 : L_search_en, pulses_fin, pulses_proj, M, N_SETA);
538 : #else
539 : Word32 target_st2_32[M]; Word32 proc_target_32[M]; int i;
540 :
541 : FOR (i = 0; i < M; i++)
542 : {
543 : target_st2_32[i] = L_shl_pos(target_st2[i], 16);
544 : }
545 :
546 : dct32_fx(target_st2_32, proc_target_32); /* enc analysis */
547 :
548 : downshift_w32_arr(proc_target_32, proc_target, 16, M);
549 :
550 : /* get the initial four integer shape candidate vectors, no normalization at this stage */
551 : pvq_enc_search_fx(proc_target, enc_pulses_far, enc_pulses_near, enc_pulsesA, enc_pulsesB, L_search_corr,
552 : L_search_en, pulses_fin, pulses_proj, M, N_SETA);
553 : #endif
554 :
555 : /* scale with gains a after a unit energy fwd transform */
556 : /* apply transform to each candidate shape vector priot to gain-shape search loop */
557 0 : submode = submodes; /* used as input solely to debug/unit test a specific shape mode */
558 :
559 : /*target should be in a linearized residual domain target */
560 : /* search pre, synthesis post*/
561 0 : pvq_enc_find_best_submode_pre_post_fx(proc_target, enc_pulses_far, enc_pulses_near, enc_pulsesA, enc_pulsesB,
562 : &submode, &i_gain, st2_vector,
563 : buffer_pvq_enc_find_best_submode_pre_post_fx); /* Q14 tr out */
564 :
565 : /* send parameters to multiplexor as a series/vector of Long Words */
566 : /* 0 : 0..3 submode */
567 : /* 1 : 0..7 gain_ind */
568 : /* 2 : 0..1 LeadSign ind */
569 : /* 3 : 25 bit MPVQ index outl_near or A part */
570 : /* 4 : 3.7 to 21 bits MPVQ index B part OR -2 */
571 :
572 0 : L_prm_idx[0] = L_deposit_l(submode); /* complete submode fwd'ed to ari_codec as 0,1,2,3 */
573 :
574 0 : submodeMSB = shr_pos(submode, 1); /* LSB of submode , sent as main submode bit */
575 0 : submodeLSB = s_and(submode, 0x1); /* LSB of submode */ /* sent via shape param */
576 :
577 : /* gain, shape indicese , incl. calls to MPVQ indexing */
578 0 : IF (submodeMSB == 0)
579 : { /* regular modes:: j=0(reg=AB) or 1(reg_lf A) */ /* regular mode, with two or one shape indices */
580 :
581 : /* assume regular_lf part , shape_j == 1 */
582 : enc_PVQ_OA =
583 0 : mpvq_index_fx(enc_pulsesA, N_SETA, sns_Kval[submode][0]); /* o : leading_sign_index, index, size, k_val */
584 0 : L_prm_idx[2] = L_deposit_l(enc_PVQ_OA.lead_sign_ind); /*LS set A */
585 :
586 0 : ASSERT(enc_PVQ_OA.size == (UWord32)sns_MPVQ_Sz[submode][0]);
587 0 : L_prm_idx[3] = L_add(0L, (Word32)enc_PVQ_OA.index); /* MPVQ shape index set A fractional */
588 :
589 : /* section B always have low indexing dynamics and is combined into one joint single index */
590 0 : IF (submodeLSB == 0)
591 : { /* regular AB , shape_j == 0*/
592 0 : L_prm_idx[1] = L_deposit_l(i_gain); /* full established gain idx fwd'ed */ /* 2 possible values */
593 0 : enc_PVQ_B = mpvq_index_fx(enc_pulsesB, N_SETB, 1);
594 0 : ASSERT(((enc_PVQ_B.size << 1)) ==
595 : (sns_MPVQ_Sz[submode][1])); /* two lowest indeces indicate all_zero B section */
596 :
597 0 : L_tmp = L_shl_pos((Word32)enc_PVQ_B.index, 1); /* 2*section B MPVQ index */
598 0 : L_prm_idx[4] = L_add(L_tmp, enc_PVQ_B.lead_sign_ind); move32(); /* add joint section B and LS index */
599 :
600 0 : ASSERT(L_prm_idx[4] >= 0 && L_prm_idx[4] < (Word32)sns_MPVQ_Sz[submode][0]);
601 : }
602 : ELSE
603 : {
604 0 : L_prm_idx[1] = L_deposit_l(i_gain);
605 : /* MSBs of established gain idx */ /* 2 or 4 total possible values */
606 0 : L_prm_idx[4] = L_deposit_l(-2);
607 : }
608 : }
609 : ELSE
610 : {
611 : /* outlier modes shape_j= 2(near, LSB=0) or 3(far, LSB=1) */
612 :
613 0 : IF (submodeLSB == 0)
614 : {
615 0 : L_prm_idx[1] = L_deposit_l(i_gain); /* established gain idx */ /* 4 possible values */
616 0 : enc_PVQ_OA = mpvq_index_fx(enc_pulses_near, M,
617 0 : sns_Kval[submode][0]); /* o : leading_sign_index, index, size, k_val */
618 0 : ASSERT(enc_PVQ_OA.size == sns_MPVQ_Sz[submode][0]);
619 0 : L_prm_idx[3] = L_add(0L, enc_PVQ_OA.index); /* MPVQ index fractional bits */
620 0 : L_prm_idx[4] = L_deposit_l(-1); /* no gain LSBs */
621 : }
622 : ELSE
623 : {
624 0 : L_prm_idx[1] = L_deposit_l(i_gain); /* established gain idx MSBs */ /* all 4 or 8 possible values */
625 0 : enc_PVQ_OA = mpvq_index_fx(enc_pulses_far, M,
626 0 : sns_Kval[submode][0]); /* o : leading_sign_index, index, size, k_val */
627 0 : ASSERT(enc_PVQ_OA.size == sns_MPVQ_Sz[submode][0]);
628 0 : L_prm_idx[3] = L_add(0L, enc_PVQ_OA.index); /* MPVQ index fractional bits */
629 0 : L_prm_idx[4] = L_deposit_l(-2); /* */
630 : }
631 0 : L_prm_idx[2] = L_deposit_l(enc_PVQ_OA.lead_sign_ind); /* LS shape single bit */
632 : }
633 :
634 : #ifdef WMOPS
635 : pop_wmops();
636 : #endif
637 : #ifdef DYNMEM_COUNT
638 : Dyn_Mem_Out();
639 : #endif
640 0 : return;
641 : }
642 :
643 0 : static Word16 scfdec_stage2_fx( /* o: ber flag */
644 : const Word32 *L_prm_idx, /* set to -1 if not used */
645 : #ifdef ENABLE_HR_MODE
646 : Word32 * st2_vector, /*o: Q14 */
647 : #else
648 : Word16 * st2_vector, /*o: Q14 */
649 : #endif
650 : Word8 * scratchBuffer)
651 : {
652 : /* MPVQ deindexing, gainscaling transform and transform */
653 : #ifdef ENABLE_HR_MODE
654 : Dyn_Mem_Deluxe_In(
655 : Word16 submode;
656 : Word16 submodeLSB, submodeMSB;
657 : Word16 gValQ13;
658 : Word16 idxB;
659 : Word16 maxK;
660 : Word16 BER_dec;
661 : Word16 *dec_pulses;
662 : Word32 *dec_en1_vec;
663 : Word32 *dec_adj_glob_vec;
664 : );
665 : #else
666 : Dyn_Mem_Deluxe_In(
667 : Word16 submode;
668 : Word16 submodeLSB, submodeMSB;
669 : Word16 gValQ13;
670 : Word16 idxB;
671 : Word16 maxK;
672 : Word16 BER_dec;
673 : Word16 *dec_pulses;
674 : Word16 *dec_en1_vec;
675 : Word16 *dec_adj_glob_vec;
676 : );
677 : #endif
678 :
679 : #ifdef WMOPS
680 : push_wmops("scfdec_stage2_fx");
681 : #endif
682 :
683 0 : dec_pulses = (Word16 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * M = 32 bytes */
684 : #ifdef ENABLE_HR_MODE
685 0 : dec_en1_vec = (Word32 *)scratchAlign(dec_pulses, sizeof(*dec_pulses) * M); /* Size = 2 * M = 32 bytes */
686 0 : dec_adj_glob_vec = (Word32 *)scratchAlign(dec_en1_vec, sizeof(*dec_en1_vec) * M); /* Size = 2 * M = 32 bytes */
687 : #else
688 : dec_en1_vec = (Word16 *)scratchAlign(dec_pulses, sizeof(*dec_pulses) * M); /* Size = 2 * M = 32 bytes */
689 : dec_adj_glob_vec = (Word16 *)scratchAlign(dec_en1_vec, sizeof(*dec_en1_vec) * M); /* Size = 2 * M = 32 bytes */
690 : #endif
691 :
692 : /* get submode */
693 0 : submode = extract_l(L_prm_idx[0]); /* 0..3 */
694 :
695 0 : submodeLSB = s_and(submode, 0x1);
696 0 : submodeMSB = shr_pos(submode, 1);
697 :
698 : /* get initial adjustment gain vector for regular, outl_near */
699 0 : ASSERT(L_prm_idx[1] >= 0 && L_prm_idx[1] < sns_gainSz[submode]);
700 0 : gValQ13 = sns_gaintabPtr[submode][L_prm_idx[1]];
701 0 : ASSERT(gValQ13 >= 0);
702 :
703 : /* gain, shape indices, incl.calls to MPVQ deindexing */
704 0 : IF (submodeMSB != 0)
705 : {
706 : /* outlier_near or outlier_far mode decoding */
707 0 : maxK = sns_Kval[submode][0]; move16();
708 0 : BER_dec = pvq_dec_deidx_fx(dec_pulses, maxK, M, extract_l(L_prm_idx[2]), (UWord32)L_prm_idx[3]);
709 : }
710 : ELSE
711 : { /* regular mode, with potentially two shape indices */
712 :
713 0 : maxK = sns_Kval[submode][0]; move16();
714 0 : BER_dec = pvq_dec_deidx_fx(dec_pulses, maxK, N_SETA, extract_l(L_prm_idx[2]), (UWord32)L_prm_idx[3]);
715 :
716 0 : IF (submodeLSB == 0)
717 : {
718 0 : idxB = extract_l(L_prm_idx[4]); /* 0..11 */
719 0 : ASSERT(idxB >= 0 && idxB < (Word16)sns_MPVQ_Sz[0][1]);
720 0 : BER_dec |= pvq_dec_deidx_fx(&(dec_pulses[N_SETA]), sns_Kval[submode][1], N_SETB, s_and(idxB, 0x1),
721 0 : (UWord32)L_deposit_l(shr_pos(idxB, 1)));
722 : /* maxK does not need to be increased as set B is not stacked */
723 : }
724 : ELSE
725 : { /* LSB gain bit already parsed */
726 0 : ASSERT(L_prm_idx[4] < 0);
727 0 : basop_memset(&dec_pulses[N_SETA], 0, (N_SETB) * sizeof(*dec_pulses));
728 : }
729 : }
730 :
731 : /* normalize decoded integer vector , exactly as on encoder side !! */
732 0 : pvq_dec_en1_normQ14_fx(dec_en1_vec, dec_pulses, maxK, M);
733 :
734 : #ifdef ENABLE_HR_MODE
735 0 : idct32_32_fx(dec_en1_vec, dec_adj_glob_vec);
736 : #else
737 : idct16_fx(dec_en1_vec, dec_adj_glob_vec); /* fwd warping in unscaled domain */
738 : #endif
739 :
740 : /* scaling aligend with encoder search */
741 0 : pvq_dec_scale_vec_fx(dec_adj_glob_vec, gValQ13, st2_vector);
742 :
743 : #ifdef WMOPS
744 : pop_wmops();
745 : #endif
746 : Dyn_Mem_Deluxe_Out();
747 0 : return BER_dec;
748 : }
749 :
750 0 : void processSnsQuantizeScfEncoder_fx(Word16 scf[], /* i: input scf M */
751 : Word32 *L_prm_idx, /* o: indeces . negative == unused */
752 : #ifdef ENABLE_HR_MODE
753 : Word32 *scf_q, /* o: quantized scf M */
754 : #else
755 : Word16 *scf_q, /* o: quantized scf M */
756 : #endif
757 : Word8 * scratchBuffer) /* Size = 28 * M + 52 */
758 : {
759 : #ifdef ENABLE_HR_MODE
760 : Dyn_Mem_Deluxe_In(
761 : Word32 *target_st2;
762 : Word16 *st1_idx; /* stage 1 indices */
763 : Word8 * buffer_processQuantize_stage2ScfEncStage2_fx;
764 : Counter col;
765 : );
766 : #else
767 : Dyn_Mem_Deluxe_In(
768 : Word16 *target_st2;
769 : Word16 *st1_idx; /* stage 1 indices */
770 : Word8 * buffer_processQuantize_stage2ScfEncStage2_fx;
771 : Counter col;
772 : );
773 : #endif
774 :
775 : #ifdef ENABLE_HR_MODE
776 0 : target_st2 = (Word32 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * M */
777 : #else
778 : target_st2 = (Word16 *)scratchAlign(scratchBuffer, 0); /* Size = 2 * M */
779 : #endif
780 0 : st1_idx = (Word16 *)scratchAlign(target_st2, sizeof(*target_st2) * M); /* Size = 2 * 2 */
781 0 : buffer_processQuantize_stage2ScfEncStage2_fx = (Word8 *)scratchAlign(st1_idx, sizeof(*st1_idx) * M);
782 : /* Size = 26 * M + 48 */
783 :
784 : /* TBD needs update */
785 :
786 : /* 1st stage trained VQ */
787 0 : processQuantize_stage1ScfEncStage1_fx(scf, scf_q, &st1_idx[0], &st1_idx[1]);
788 0 : L_prm_idx[0] = L_deposit_l(st1_idx[0]);
789 0 : L_prm_idx[1] = L_deposit_l(st1_idx[1]);
790 :
791 : /* 2nd stage PVQ-based SCF quantizer */
792 0 : FOR (col = 0; col < M; col++)
793 : {
794 : #ifdef ENABLE_HR_MODE
795 0 : target_st2[col] = L_sub(L_deposit_h(scf[col]), scf_q[col]);
796 : #else
797 : target_st2[col] = sub(scf[col], scf_q[col]);
798 : #endif
799 : }
800 :
801 0 : processQuantize_stage2ScfEncStage2_fx(target_st2, scf_q, &L_prm_idx[2], VQMODES26, /* 0xF means all submodes */
802 : buffer_processQuantize_stage2ScfEncStage2_fx); /* PVQ in stage 2 */
803 : Dyn_Mem_Deluxe_Out();
804 0 : }
805 :
806 0 : Word16 processSnsQuantizeScfDecoder_fx( /* o: BER flag */
807 : Word32 *L_prm_idx, /* i: indeces */
808 : #ifdef ENABLE_HR_MODE
809 : Word32 scf_q[],
810 : #else
811 : Word16 scf_q[],
812 : #endif
813 : Word8 *scratchBuffer) /* o: M */
814 : {
815 : Dyn_Mem_Deluxe_In(
816 : Word16 BER_flag;
817 : );
818 :
819 : /* Decode First Stage */
820 : #ifdef ENABLE_HR_MODE
821 0 : processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q27, st1SCF8_15_base5_32x8_Q27,
822 0 : extract_l(L_prm_idx[0]), extract_l(L_prm_idx[1]), scf_q);
823 : #else
824 : processDeQuantize_stage1ScfDecStage1_fx(st1SCF0_7_base5_32x8_Q11, st1SCF8_15_base5_32x8_Q11,
825 : extract_l(L_prm_idx[0]), extract_l(L_prm_idx[1]), scf_q);
826 : #endif
827 :
828 : /* Decode Second Stage */
829 0 : BER_flag = scfdec_stage2_fx(&(L_prm_idx[2]), scf_q, scratchBuffer);
830 :
831 : Dyn_Mem_Deluxe_Out();
832 0 : return BER_flag;
833 : }
834 :
|