Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : #include <assert.h>
34 : #include <stdint.h>
35 : #include "options.h"
36 : #include <math.h>
37 : #include "ivas_cnst.h"
38 : #include "ivas_rom_com.h"
39 : #include "prot_fx.h"
40 : #include "cnst.h"
41 : #include "wmc_auto.h"
42 : #include "ivas_prot_fx.h"
43 : #include "ivas_rom_com_fx.h"
44 :
45 :
46 : /*-------------------------------------------------------------------------
47 : * ivas_qmetadata_reorder_generic()
48 : *
49 : *------------------------------------------------------------------------*/
50 0 : UWord16 ivas_qmetadata_reorder_generic_fx(
51 : const Word16 signed_value )
52 : {
53 : UWord16 unsigned_value;
54 :
55 0 : IF( signed_value < 0 )
56 : {
57 : // unsigned_value = ( ( UWord16 ) - ( signed_value + 1 ) << 1 ) + 1;
58 0 : unsigned_value = (UWord16) L_add( L_shl( negate( add( signed_value, 1 ) ), 1 ), 1 );
59 : }
60 : ELSE
61 : {
62 0 : unsigned_value = (UWord16) L_shl( signed_value, 1 );
63 : }
64 :
65 0 : return unsigned_value;
66 : }
67 :
68 :
69 : /*-------------------------------------------------------------------------
70 : * ivas_qmetadata_dereorder_generic()
71 : *
72 : * Returns the original value of the array "folded" by ReorderGeneric
73 : *------------------------------------------------------------------------*/
74 :
75 : /*! r: "Unfolded" value, positive or negative depending on the value of the input */
76 3267400 : Word16 ivas_qmetadata_dereorder_generic_fx(
77 : const UWord16 uns_value /* i : unsigned value result of ReorderGeneric */
78 : )
79 : {
80 3267400 : IF( L_and( uns_value, 1 ) != 0 )
81 : {
82 1237384 : return sub( negate( extract_l( L_shr( uns_value, 1 ) ) ), 1 );
83 : }
84 : ELSE
85 : {
86 2030016 : return extract_l( L_shr( uns_value, 1 ) );
87 : }
88 : }
89 :
90 :
91 : /*-------------------------------------------------------------------------
92 : * ivas_dirac_project_elevation_index()
93 : *
94 : *
95 : *------------------------------------------------------------------------*/
96 :
97 : /*! r: projected elevation index */
98 1329478 : Word16 ivas_dirac_project_elevation_index_fx(
99 : const Word16 el_idx, /* i : elevation index */
100 : const Word16 el_alph, /* i : number of elevation symbols */
101 : const Word16 el_alph_proj /* i : size of projected alphabet */
102 : )
103 : {
104 : Word16 el_idx_proj;
105 :
106 : /* evaluate floor((el_idx / (el_alph - 1)) * (el_alph_proj - 1) + 0.5) using only integer */
107 1329478 : el_idx_proj = idiv1616( add( imult1616( imult1616( 2, el_idx ), sub( el_alph_proj, 1 ) ), sub( el_alph, 1 ) ), imult1616( 2, sub( el_alph, 1 ) ) );
108 :
109 1329478 : return el_idx_proj;
110 : }
111 :
112 :
113 : /*-------------------------------------------------------------------------
114 : * ivas_chan_project_elevation_index()
115 : *
116 : *
117 : *------------------------------------------------------------------------*/
118 :
119 : /*! r: projected index in channel mode */
120 7563 : Word16 ivas_chan_project_elevation_index_fx(
121 : const Word16 el_idx, /* i : elevation index */
122 : const Word16 el_alph, /* i : number of elevation symbols */
123 : const Word16 el_alph_proj /* i : size of projected alphabet */
124 : )
125 : {
126 : Word16 el_idx_proj;
127 :
128 : /* evaluate floor((el_idx / (el_alph - 1)) * (el_alph_proj - 1) + 0.5) using only integer */
129 7563 : IF( EQ_16( el_idx, sub( el_alph, 1 ) ) )
130 : {
131 0 : el_idx_proj = sub( el_alph_proj, 1 );
132 : }
133 : ELSE
134 : {
135 7563 : el_idx_proj = idiv1616( add( imult1616( imult1616( 2, el_idx ), el_alph_proj ), el_alph ), imult1616( 2, el_alph ) );
136 : }
137 :
138 7563 : return el_idx_proj;
139 : }
140 :
141 :
142 : /*-------------------------------------------------------------------------
143 : * ivas_dirac_project_azimuth_index()
144 : *
145 : *
146 : *------------------------------------------------------------------------*/
147 :
148 : /*! r: projected azimuth index */
149 1593512 : Word16 ivas_dirac_project_azimuth_index_fx(
150 : const Word16 az_idx, /* i : azimuth index */
151 : const Word16 az_alph, /* i : number of azimuth symbols */
152 : const Word16 az_alph_proj /* i : size of projected alphabet */
153 : )
154 : {
155 : Word16 az_idx_proj;
156 :
157 1593512 : IF( EQ_16( az_alph_proj, 1 ) )
158 : {
159 394 : return 0;
160 : }
161 :
162 : /* evaluate floor((az_idx / az_alph) * az_alph_proj + 0.5) using only integer */
163 1593118 : az_idx_proj = idiv1616( add( imult1616( imult1616( 2, az_idx ), az_alph_proj ), az_alph ), imult1616( 2, az_alph ) );
164 :
165 1593118 : if ( EQ_16( az_idx_proj, az_alph_proj ) )
166 : {
167 6531 : az_idx_proj = 0;
168 6531 : move16();
169 : }
170 :
171 1593118 : return az_idx_proj;
172 : }
173 :
174 :
175 : /*-------------------------------------------------------------------------
176 : * small_reduction_direction()
177 : *
178 : * Compute the allocated bit reduction in spherical indexing for bit budget
179 : * is exceeded by diff. bits
180 : *------------------------------------------------------------------------*/
181 :
182 1800 : void small_reduction_direction_fx(
183 : IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */
184 : UWord16 bits_dir[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES],
185 : const Word16 raw_flag[MASA_MAXIMUM_CODING_SUBBANDS],
186 : Word16 *diff )
187 : {
188 : Word16 i, j, k;
189 :
190 1800 : test();
191 3579 : FOR( k = 0; ( k < 2 ) && ( *diff > 0 ); k++ )
192 : {
193 1779 : test();
194 1779 : test();
195 6548 : FOR( i = q_direction->cfg.start_band; ( i < q_direction->cfg.nbands ) && ( *diff > 0 ); i++ )
196 : {
197 4769 : test();
198 4769 : IF( EQ_16( raw_flag[i], 1 ) )
199 : {
200 4296 : test();
201 19955 : FOR( j = 0; ( j < q_direction->cfg.nblocks ) && ( *diff > 0 ); j++ )
202 : {
203 15659 : test();
204 15659 : IF( GT_32( bits_dir[i][j], MASA_MIN_BITS_TF ) )
205 : {
206 12527 : bits_dir[i][j] = (UWord16) L_sub( bits_dir[i][j], 1 );
207 12527 : move16();
208 12527 : ( *diff )--;
209 : }
210 : }
211 : }
212 : }
213 : }
214 :
215 1800 : return;
216 : }
217 :
218 :
219 : /*-----------------------------------------------------------------------*
220 : * quantize_phi()
221 : *
222 : * Quantize azimuth.
223 : * Input phi expected to be an angle in degree between 0 and 360.
224 : *-----------------------------------------------------------------------*/
225 : /*! r: index azimuth */
226 :
227 8376 : Word16 quantize_phi_fx(
228 : Word32 phi, /* i : azimuth value, Q22 */
229 : const Word16 flag_delta, /* i : flag indicating if the azimuth codebook is translated or not */
230 : Word32 *phi_hat, /* o : quantized azimuth, Q22 */
231 : const Word16 n /* i : azimuth codebook size */
232 : )
233 : {
234 : Word16 id_phi;
235 : Word32 dd_fx;
236 : Word32 delta_phi_fx;
237 : Word32 inv_delta_phi_fx;
238 : Word32 temp_res;
239 :
240 8376 : delta_phi_fx = delta_phi_val[n]; // Q22
241 8376 : move32();
242 8376 : inv_delta_phi_fx = inv_delta_phi_val[n]; // Q31
243 8376 : move32();
244 8376 : IF( EQ_16( n, 1 ) )
245 : {
246 0 : *phi_hat = 0;
247 0 : move32();
248 :
249 0 : return 0;
250 : }
251 :
252 8376 : test();
253 8376 : IF( EQ_16( flag_delta, 1 ) && GT_16( n, 2 ) )
254 : {
255 0 : dd_fx = dd_val[n];
256 0 : move32();
257 : }
258 : ELSE
259 : {
260 8376 : dd_fx = 0;
261 8376 : move32();
262 : }
263 :
264 8376 : temp_res = Mpy_32_32( L_sub( L_sub( phi, DEGREE_180_Q_22 ), dd_fx ), inv_delta_phi_fx ); // Q22 + Q31 - Q31 -> Q22
265 8376 : id_phi = round_fx( L_shr( temp_res, Q22 - Q16 ) ); // Q0
266 :
267 8376 : assert( L_sub( L_abs( temp_res ), abs( id_phi ) * ONE_IN_Q22 ) <= ONE_IN_Q21 );
268 :
269 :
270 8376 : IF( add( id_phi, shr( n, 1 ) ) < 0 )
271 : {
272 0 : id_phi = add( id_phi, 1 );
273 : }
274 :
275 8376 : IF( sub( id_phi, shr( n, 1 ) ) >= 0 )
276 : {
277 4 : id_phi = negate( shr( n, 1 ) );
278 : }
279 :
280 8376 : IF( EQ_16( id_phi, negate( add( shr( n, 1 ), ( n % 2 ) ) ) ) )
281 : {
282 7 : id_phi = add( id_phi, ( n % 2 ) );
283 : }
284 : ELSE{
285 8369 : IF( EQ_16( id_phi, add( shr( n, 1 ), ( n % 2 ) ) ) ){
286 0 : IF( n % 2 ){
287 0 : id_phi = sub( id_phi, 1 );
288 : }
289 : ELSE
290 : {
291 0 : id_phi = negate( id_phi );
292 : }
293 : }
294 : }
295 :
296 8376 : *phi_hat = L_add_sat( L_add_sat( imult3216( delta_phi_fx, id_phi ), dd_fx ), DEGREE_180_Q_22 ); // Q22
297 8376 : move32();
298 8376 : id_phi = add( id_phi, shr( n, 1 ) );
299 :
300 8376 : return id_phi;
301 : }
302 :
303 0 : Word16 quantize_phi_enc_fx(
304 : Word32 phi, /* i : azimuth value, Q22 */
305 : const Word16 flag_delta, /* i : flag indicating if the azimuth codebook is translated or not */
306 : Word32 *phi_hat, /* o : quantized azimuth, Q22 */
307 : const Word16 n /* i : azimuth codebook size */
308 : )
309 : {
310 : Word16 id_phi;
311 : Word32 dd_fx;
312 : Word32 delta_phi_fx;
313 : Word32 inv_delta_phi_fx;
314 : Word32 temp_res;
315 : Word16 temp_e;
316 :
317 0 : delta_phi_fx = BASOP_Util_Divide3232_Scale_newton( 360, n, &temp_e );
318 0 : delta_phi_fx = L_shl( delta_phi_fx, sub( temp_e, 9 ) );
319 0 : inv_delta_phi_fx = BASOP_Util_Divide3232_Scale_newton( n, 360, &temp_e );
320 :
321 0 : IF( EQ_16( n, 1 ) )
322 : {
323 0 : *phi_hat = 0;
324 0 : move32();
325 :
326 0 : return 0;
327 : }
328 :
329 0 : test();
330 0 : IF( EQ_16( flag_delta, 1 ) && GT_16( n, 2 ) )
331 : {
332 0 : dd_fx = dd_val[n];
333 0 : move32();
334 : }
335 : ELSE
336 : {
337 0 : dd_fx = 0;
338 0 : move32();
339 : }
340 :
341 0 : temp_res = Mpy_32_32( L_sub( L_sub( phi, DEGREE_180_Q_22 ), dd_fx ), inv_delta_phi_fx );
342 0 : temp_res = L_shl( temp_res, temp_e );
343 0 : id_phi = round_fx( L_shr( temp_res, Q22 - Q16 ) );
344 :
345 0 : assert( L_sub( L_abs( temp_res ), abs( id_phi ) * ONE_IN_Q22 ) <= ONE_IN_Q21 );
346 :
347 :
348 0 : IF( add( id_phi, shr( n, 1 ) ) < 0 )
349 : {
350 0 : id_phi = add( id_phi, 1 );
351 : }
352 :
353 0 : IF( sub( id_phi, shr( n, 1 ) ) >= 0 )
354 : {
355 0 : id_phi = negate( shr( n, 1 ) );
356 : }
357 :
358 0 : IF( EQ_16( id_phi, negate( add( shr( n, 1 ), ( n % 2 ) ) ) ) )
359 : {
360 0 : id_phi = add( id_phi, ( n % 2 ) );
361 : }
362 : ELSE{
363 0 : IF( EQ_16( id_phi, add( shr( n, 1 ), ( n % 2 ) ) ) ){
364 0 : IF( n % 2 ){
365 0 : id_phi = sub( id_phi, 1 );
366 : }
367 : ELSE
368 : {
369 0 : id_phi = negate( id_phi );
370 : }
371 : }
372 : }
373 :
374 0 : *phi_hat = L_add_sat( L_add_sat( ( imult3216( delta_phi_fx, id_phi ) ), dd_fx ), DEGREE_180_Q_22 );
375 0 : move32();
376 0 : id_phi = add( id_phi, shr( n, 1 ) );
377 :
378 0 : return id_phi;
379 : }
380 : /*-----------------------------------------------------------------------*
381 : * companding_azimuth()
382 : *
383 : * Compand azimuth based on the format
384 : *-----------------------------------------------------------------------*/
385 :
386 79875 : Word32 companding_azimuth_fx(
387 : const Word32 azi_fx, /* i : input azimuth value, Q22 */
388 : const MC_LS_SETUP mc_format, /* i : input channel format */
389 : const Word16 theta_flag, /* i : zero/non zero elevation flag */
390 : const Word16 direction /* i : direction of companding (direct or inverse)*/
391 : )
392 : {
393 79875 : const Word16 pointsA[] = { 0, 60, 110, 150, 180, 0, 50, 90, 150, 180, 0, 30, 80, 150, 180 }; // Q0
394 79875 : const Word16 pointsB[] = { 0, 90, 110, 170, 180, 0, 90, 110, 170, 180, 0, 10, 100, 170, 180 }; // Q0
395 : const Word16 *pA;
396 79875 : const Word32 pointsA_fx[] = { 0, 251658240, 461373440, 629145600, 754974720, 0, 209715200, 377487360, 629145600, 754974720, 0, 125829120, 335544320, 629145600, 754974720 }; // q=22
397 79875 : const Word32 pointsB_fx[] = { 0, 377487360, 461373440, 713031680, 754974720, 0, 377487360, 461373440, 713031680, 754974720, 0, 41943040, 419430400, 713031680, 754974720 }; // q=22
398 : const Word32 *pA_fx, *pB_fx;
399 : Word16 no_points;
400 : Word32 comp_azi_fx;
401 : Word16 i, not_done, start;
402 : Word32 abs_azi_fx;
403 79875 : move16();
404 79875 : move16();
405 79875 : move16();
406 79875 : move16();
407 79875 : move16();
408 79875 : move16();
409 79875 : move16();
410 79875 : move16();
411 79875 : move16();
412 79875 : move16();
413 79875 : move16();
414 79875 : move16();
415 79875 : move16();
416 79875 : move16();
417 79875 : move16();
418 79875 : move16();
419 79875 : move16();
420 79875 : move16();
421 79875 : move16();
422 79875 : move16();
423 79875 : move16();
424 79875 : move16();
425 79875 : move16();
426 79875 : move16();
427 79875 : move16();
428 79875 : move16();
429 79875 : move16();
430 79875 : move16();
431 79875 : move16();
432 79875 : move16();
433 79875 : move32();
434 79875 : move32();
435 79875 : move32();
436 79875 : move32();
437 79875 : move32();
438 79875 : move32();
439 79875 : move32();
440 79875 : move32();
441 79875 : move32();
442 79875 : move32();
443 79875 : move32();
444 79875 : move32();
445 79875 : move32();
446 79875 : move32();
447 79875 : move32();
448 79875 : move32();
449 79875 : move32();
450 79875 : move32();
451 79875 : move32();
452 79875 : move32();
453 79875 : move32();
454 79875 : move32();
455 79875 : move32();
456 79875 : move32();
457 79875 : move32();
458 79875 : move32();
459 79875 : move32();
460 79875 : move32();
461 79875 : move32();
462 79875 : move32();
463 :
464 79875 : test();
465 79875 : test();
466 79875 : IF( EQ_32( mc_format, MC_LS_SETUP_5_1 ) || EQ_32( mc_format, MC_LS_SETUP_5_1_2 ) || EQ_32( mc_format, MC_LS_SETUP_5_1_4 ) ) /* 5.1, 5.1+2 or 5.1+4*/
467 : {
468 64821 : start = 5;
469 64821 : move16();
470 : }
471 : ELSE
472 : {
473 15054 : start = 0;
474 15054 : move16();
475 : }
476 :
477 : /* theta flag 1 is for non zero, larger than a threshold elevation */
478 79875 : test();
479 79875 : test();
480 79875 : test();
481 79875 : IF( ( EQ_16( theta_flag, 1 ) ) && ( ( EQ_32( mc_format, MC_LS_SETUP_5_1_2 ) ) || ( EQ_32( mc_format, MC_LS_SETUP_5_1_4 ) ) || ( EQ_32( mc_format, MC_LS_SETUP_7_1_4 ) ) ) ) /* 5.1+2, 5.1+4 or 7.1+4*/
482 : {
483 7212 : start = 10;
484 7212 : move16();
485 : }
486 79875 : no_points = 5;
487 79875 : move16();
488 :
489 79875 : pA_fx = &pointsA_fx[start];
490 79875 : pB_fx = &pointsB_fx[start];
491 79875 : pA = &pointsA[start];
492 :
493 79875 : IF( EQ_16( direction, -1 ) ) /* inverse companding */
494 : {
495 79875 : pA_fx = &pointsB_fx[start];
496 79875 : pB_fx = &pointsA_fx[start];
497 79875 : pA = &pointsB[start];
498 : }
499 : ELSE
500 : {
501 0 : IF( NE_16( direction, 1 ) )
502 : {
503 0 : printf( "Wrong direction in companding" );
504 : }
505 : }
506 :
507 79875 : not_done = 1;
508 79875 : move16();
509 79875 : abs_azi_fx = L_abs( azi_fx );
510 :
511 79875 : comp_azi_fx = azi_fx;
512 79875 : move32();
513 79875 : i = 0;
514 79875 : move16();
515 174805 : WHILE( not_done && ( LT_16( i, sub( no_points, 1 ) ) ) )
516 : {
517 94930 : test();
518 94930 : IF( LE_32( abs_azi_fx, pA_fx[i + 1] ) )
519 : {
520 79875 : not_done = 0;
521 79875 : move16();
522 : /* calculate companding */
523 79875 : comp_azi_fx = Mpy_32_32( L_sub( pB_fx[i + 1], pB_fx[i] ), L_sub( abs_azi_fx, pA_fx[i] ) ); // ( Q22 + Q22 - Q31 ) -> Q13
524 79875 : SWITCH( sub( pA[i + 1], pA[i] ) )
525 : {
526 3883 : case 10:
527 : // Q13 + Q31 - Q31 -> Q13
528 3883 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 214748364 ); // 1 / 10 in 2 ^ 31
529 3883 : BREAK;
530 4318 : case 20:
531 : // Q13 + Q31 - Q31 -> Q13
532 4318 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 107374182 ); // 1 / 20 in 2 ^ 31
533 4318 : BREAK;
534 0 : case 30:
535 : // Q13 + Q31 - Q31 -> Q13
536 0 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 71582788 ); // 1 / 30 in 2 ^ 31
537 0 : BREAK;
538 0 : case 40:
539 : // Q13 + Q31 - Q31 -> Q13
540 0 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 53687091 ); // 1 / 40 in 2 ^ 31
541 0 : BREAK;
542 0 : case 50:
543 : // Q13 + Q31 - Q31 -> Q13
544 0 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 42949672 ); // 1 / 50 in 2 ^ 31
545 0 : BREAK;
546 1915 : case 60:
547 : // Q13 + Q31 - Q31 -> Q13
548 1915 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 35791394 ); // 1 / 60 in 2 ^ 31
549 1915 : BREAK;
550 1640 : case 70:
551 : // Q13 + Q31 - Q31 -> Q13
552 1640 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 30678337 ); // 1 / 70 in 2 ^ 31
553 1640 : BREAK;
554 68119 : case 90:
555 : // Q13 + Q31 - Q31 -> Q13
556 68119 : comp_azi_fx = Mpy_32_32( comp_azi_fx, 23860929 ); // 1 / 90 in 2 ^ 31
557 68119 : BREAK;
558 0 : default:
559 0 : assert( 0 );
560 : BREAK;
561 : }
562 79875 : comp_azi_fx = L_add( pB_fx[i], L_shl( comp_azi_fx, Q22 - Q13 ) ); // Q22
563 : // comp_azi = pB[i] + ( pB[i + 1] - pB[i] ) / ( pA[i + 1] - pA[i] ) * ( abs_azi - pA[i] );
564 : }
565 : ELSE
566 : {
567 15055 : i = add( i, 1 );
568 : }
569 : }
570 :
571 79875 : IF( azi_fx < 0 )
572 : {
573 30357 : comp_azi_fx = L_negate( comp_azi_fx ); // Q22
574 : }
575 :
576 79875 : IF( EQ_16( not_done, 1 ) )
577 : {
578 0 : comp_azi_fx = azi_fx; // Q22
579 0 : move32();
580 : }
581 :
582 79875 : return comp_azi_fx; // Q22
583 : }
584 :
585 : /*-----------------------------------------------------------------------*
586 : * quantize_phi_chan_lbr()
587 : *
588 : * Quantize azimuth in low-bitrate channel mode.
589 : * Input phi expected to be an angle in degree between 0 and 360.
590 : *-----------------------------------------------------------------------*/
591 :
592 : /*! r: index azimuth */
593 0 : Word16 quantize_phi_chan_lbr_fx(
594 : const Word32 phi, /* i : azimuth value, Q22 */
595 : Word32 *phi_hat, /* o : quantized azimuth, Q22 */
596 : const Word16 n /* i : azimuth codebook size */
597 : )
598 : {
599 : Word16 id_phi, phi_hat_16;
600 :
601 :
602 0 : IF( LE_16( n, 1 ) )
603 : {
604 0 : *phi_hat = 0;
605 0 : move32();
606 :
607 0 : return 0;
608 : }
609 :
610 0 : id_phi = squant_fx( round_fx( L_abs( phi ) ) /* Q6 */, &phi_hat_16 /* Q6 */, cb_azi_chan_16fx, shr( n, 1 ) );
611 0 : *phi_hat = L_deposit_h( phi_hat_16 ); // Q6 -> Q22
612 0 : move32();
613 :
614 0 : test();
615 0 : IF( phi < 0 && id_phi > 0 )
616 : {
617 0 : id_phi = sub( shl( id_phi, 1 ), 1 );
618 0 : *phi_hat = L_negate( *phi_hat ); // Q22
619 0 : move32();
620 : }
621 : ELSE
622 : {
623 : // id_phi *= 2;
624 0 : id_phi = shl( id_phi, 1 );
625 : }
626 :
627 0 : return id_phi;
628 : }
629 :
630 :
631 : /*-----------------------------------------------------------------------*
632 : * quantize_phi_chan_compand()
633 : *
634 : * Quantize azimuth.
635 : * Input phi expected to be an angle in degree between 0 and 360.
636 : *-----------------------------------------------------------------------*/
637 :
638 :
639 : /*! r: index azimuth */
640 0 : Word16 quantize_phi_chan_compand_fx(
641 : Word32 phi, /* i : azimuth value Q22 */
642 : Word32 *phi_hat, /* o : quantized azimuth Q22 */
643 : const Word16 n, /* i : azimuth codebook size */
644 : const Word16 theta_flag, /* i : flag signaling high elevation */
645 : const MC_LS_SETUP mc_format /* i : channel format if in MC-mode */
646 : )
647 : {
648 : Word16 id_phi;
649 : Word32 delta_phi; // Q22
650 : Word16 tmp_e;
651 :
652 0 : IF( LE_16( n, 1 ) )
653 : {
654 0 : *phi_hat = 0;
655 0 : move32();
656 :
657 0 : return 0;
658 : }
659 :
660 0 : phi = companding_azimuth_fx( L_sub( phi, 180 << Q22 ), mc_format, theta_flag, 1 );
661 :
662 : /* quantize companded value */
663 : // delta_phi = 360.0f / (float) n;
664 0 : delta_phi = BASOP_Util_Divide3232_Scale_newton( 360, n, &tmp_e );
665 0 : delta_phi = L_shr( delta_phi, sub( 9, tmp_e ) ); // Q22
666 : // id_phi = (int16_t) round_f( ( phi / (float) delta_phi ) );
667 0 : id_phi = BASOP_Util_Divide3232_Scale( phi, delta_phi, &tmp_e ); // Q15
668 0 : id_phi = round_fx( L_shl( id_phi, add( tmp_e, 1 ) ) ); // Q0
669 :
670 0 : IF( add( id_phi, shr( n, 1 ) ) < 0 )
671 : {
672 0 : id_phi = add( id_phi, 1 );
673 : }
674 0 : IF( sub( id_phi, shr( n, 1 ) ) >= 0 )
675 : {
676 0 : id_phi = negate( shr( n, 1 ) );
677 : }
678 :
679 0 : IF( EQ_16( id_phi, negate( add( shr( n, 1 ), ( n % 2 ) ) ) ) )
680 : {
681 0 : id_phi = add( id_phi, ( n % 2 ) );
682 : }
683 : ELSE{
684 0 : IF( EQ_16( id_phi, add( shr( n, 1 ), ( n % 2 ) ) ) ){
685 0 : IF( n % 2 ){
686 0 : id_phi = sub( id_phi, 1 );
687 : }
688 : ELSE
689 : {
690 0 : id_phi = negate( id_phi );
691 : }
692 : }
693 : }
694 : //*phi_hat = id_phi * delta_phi;
695 0 : *phi_hat = imult3216( delta_phi, id_phi ); // Q22
696 0 : move32();
697 :
698 : // id_phi += ( n >> 1 );
699 0 : id_phi = add( id_phi, shr( n, 1 ) );
700 :
701 :
702 0 : *phi_hat = L_add( companding_azimuth_fx( *phi_hat, mc_format, theta_flag, -1 ), DEGREE_180_Q_22 ); // Q22
703 0 : move32();
704 :
705 0 : return id_phi;
706 : }
|