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 "ivas_stat_enc.h"
40 : #include "wmc_auto.h"
41 : #include "prot_fx.h"
42 : #include "ivas_prot_fx.h"
43 :
44 :
45 : /*-----------------------------------------------------------------------*
46 : * Local function prototypes
47 : *-----------------------------------------------------------------------*/
48 : static Word32 quantize_theta_phi_fx( Word32 *theta_cb, const Word16 no_th, const Word16 *no_phi_loc, const Word32 abs_theta, Word16 *id_phi, Word16 *id_phi_remap, Word32 *phi_hat, const Word32 phi, const Word16 no_bits, Word16 *id_theta, Word32 *phi_q, const Word16 remap, const MC_LS_SETUP mc_format );
49 :
50 : static Word16 direction_distance_cp_fx( Word32 theta, Word32 theta_hat, Word32 theta_hat1, const Word32 phi, const Word32 phi_hat, const Word32 phi_hat1, Word16 *d1 );
51 :
52 : /*-------------------------------------------------------------------*
53 : * quantize_direction_frame()
54 : *
55 : *
56 : *----------------------------------------------------------------------*/
57 220947 : void quantize_direction_frame_fx(
58 : IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */
59 : Word32 azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], /* o : Q22 */
60 : Word32 elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], /* o : Q22 */
61 : const Word16 hrmasa_flag /* i : flag indicating high-rate MASA MD coding */
62 : )
63 : {
64 : Word16 i, j;
65 : UWord16 idx;
66 :
67 : /* Quantize directions */
68 220947 : q_direction->not_in_2D = 0;
69 220947 : move16();
70 1313371 : FOR( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ )
71 : {
72 1092424 : idx = q_direction->band_data[i].energy_ratio_index_mod[0];
73 1092424 : move16();
74 4957019 : FOR( j = 0; j < q_direction->cfg.nblocks; j++ )
75 : {
76 3864595 : if ( azimuth_orig != NULL )
77 : {
78 3864595 : azimuth_orig[i][j] = q_direction->band_data[i].azimuth_fx[j];
79 3864595 : move32();
80 : }
81 :
82 3864595 : if ( elevation_orig != NULL )
83 : {
84 3864595 : elevation_orig[i][j] = q_direction->band_data[i].elevation_fx[j];
85 3864595 : move32();
86 : }
87 :
88 : /* requantize the direction */
89 7729190 : q_direction->band_data[i].spherical_index[j] = quantize_direction_fx( q_direction->band_data[i].elevation_fx[j],
90 3864595 : q_direction->band_data[i].azimuth_fx[j],
91 3864595 : q_direction->band_data[i].bits_sph_idx[j],
92 3864595 : &q_direction->band_data[i].elevation_fx[j],
93 3864595 : &q_direction->band_data[i].azimuth_fx[j], &q_direction->band_data[i].elevation_index[j],
94 3864595 : &q_direction->band_data[i].azimuth_index[j],
95 : q_direction->cfg.mc_ls_setup );
96 3864595 : move16();
97 :
98 3864595 : q_direction->not_in_2D = add( q_direction->not_in_2D, q_direction->band_data[i].elevation_index[j] );
99 3864595 : move16();
100 :
101 3864595 : IF( hrmasa_flag )
102 : {
103 158082 : IF( NE_32( q_direction->cfg.mc_ls_setup, MC_LS_SETUP_INVALID ) )
104 : {
105 0 : q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[0] - 3];
106 0 : q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[0] - 1][q_direction->band_data[i].elevation_index[j]];
107 0 : move16();
108 0 : move16();
109 : }
110 : ELSE
111 : {
112 158082 : q_direction->band_data[i].elevation_m_alphabet[j] = sub( imult1616( no_theta_masa[bits_direction_masa[0] - 3], 2 ), 1 );
113 158082 : q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[0] - 1][( q_direction->band_data[i].elevation_index[j] + 1 ) >> 1];
114 158082 : move16();
115 158082 : move16();
116 : }
117 : }
118 : ELSE
119 : {
120 3706513 : IF( NE_32( q_direction->cfg.mc_ls_setup, MC_LS_SETUP_INVALID ) )
121 : {
122 25889 : q_direction->band_data[i].elevation_m_alphabet[j] = no_theta_masa[bits_direction_masa[idx] - 3];
123 25889 : q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][q_direction->band_data[i].elevation_index[j]];
124 25889 : move16();
125 25889 : move16();
126 : }
127 : ELSE
128 : {
129 3680624 : q_direction->band_data[i].elevation_m_alphabet[j] = sub( imult1616( no_theta_masa[bits_direction_masa[idx] - 3], 2 ), 1 );
130 3680624 : q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][( q_direction->band_data[i].elevation_index[j] + 1 ) >> 1];
131 3680624 : move16();
132 3680624 : move16();
133 : }
134 : }
135 :
136 3864595 : if ( EQ_16( q_direction->band_data[i].azimuth_index[j], MASA_NO_INDEX ) )
137 : {
138 3080 : q_direction->band_data[i].azimuth_index[j] = 0;
139 3080 : move16();
140 : }
141 :
142 3864595 : IF( LE_16( q_direction->band_data[i].bits_sph_idx[j], 2 ) )
143 : {
144 0 : q_direction->band_data[i].elevation_index[j] = 0;
145 0 : move16();
146 : }
147 : ELSE
148 : {
149 3864595 : IF( EQ_32( q_direction->cfg.mc_ls_setup, MC_LS_SETUP_INVALID ) )
150 : {
151 : /*deorder elevation indexing*/
152 3838706 : IF( s_and( q_direction->band_data[i].elevation_index[j], 1 ) != 0 )
153 : {
154 738136 : q_direction->band_data[i].elevation_index[j] = add( shr( add( q_direction->band_data[i].elevation_index[j], 1 ), 1 ), shr( q_direction->band_data[i].elevation_m_alphabet[j], 1 ) );
155 738136 : move16();
156 : }
157 : ELSE
158 : {
159 : // q_direction->band_data[i].elevation_index[j] = -( ( q_direction->band_data[i].elevation_index[j] ) >> 1 ) + ( q_direction->band_data[i].elevation_m_alphabet[j] >> 1 );
160 3100570 : q_direction->band_data[i].elevation_index[j] = sub( shr( q_direction->band_data[i].elevation_m_alphabet[j], 1 ), shr( ( q_direction->band_data[i].elevation_index[j] ), 1 ) );
161 3100570 : move16();
162 : }
163 : }
164 : }
165 : }
166 : }
167 :
168 220947 : if ( q_direction->not_in_2D > 0 )
169 : {
170 194415 : q_direction->not_in_2D = 1 + MASA_LIMIT_2D;
171 194415 : move16();
172 : }
173 :
174 220947 : return;
175 : }
176 :
177 :
178 : /*-------------------------------------------------------------------*
179 : * quantize_direction_frame2D()
180 : *
181 : *
182 : *----------------------------------------------------------------------*/
183 10150 : void quantize_direction_frame2D_fx(
184 : IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */
185 : Word32 azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], // Q22
186 : Word32 elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES] ) // Q22
187 : {
188 : Word16 i, j;
189 : UWord16 idx;
190 : /* Quantize directions */
191 10150 : q_direction->not_in_2D = 0;
192 10150 : move16();
193 54544 : FOR( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ )
194 : {
195 44394 : idx = q_direction->band_data[i].energy_ratio_index[0];
196 44394 : move16();
197 128055 : FOR( j = 0; j < q_direction->cfg.nblocks; j++ )
198 : {
199 83661 : if ( azimuth_orig != NULL )
200 : {
201 83661 : azimuth_orig[i][j] = q_direction->band_data[i].azimuth_fx[j];
202 83661 : move32();
203 : }
204 83661 : if ( elevation_orig != NULL )
205 : {
206 83661 : elevation_orig[i][j] = q_direction->band_data[i].elevation_fx[j];
207 83661 : move32();
208 : }
209 83661 : q_direction->band_data[i].azimuth_m_alphabet[j] = no_phi_masa[bits_direction_masa[idx] - 1][0];
210 83661 : move16();
211 :
212 : /* requantize the direction */
213 167322 : q_direction->band_data[i].spherical_index[j] = quantize_direction2D_fx( q_direction->band_data[i].azimuth_fx[j],
214 83661 : q_direction->band_data[i].azimuth_m_alphabet[j],
215 83661 : &q_direction->band_data[i].azimuth_fx[j],
216 83661 : &q_direction->band_data[i].azimuth_index[j],
217 : q_direction->cfg.mc_ls_setup );
218 83661 : move16();
219 :
220 83661 : q_direction->band_data[i].elevation_m_alphabet[j] = 1;
221 83661 : move16();
222 : }
223 : }
224 :
225 10150 : return;
226 : }
227 :
228 : /*-------------------------------------------------------------------*
229 : * small_requantize_direction_frame()
230 : *
231 : *
232 : *----------------------------------------------------------------------*/
233 8070 : void small_requantize_direction_frame_fx(
234 : IVAS_QDIRECTION *q_direction, /* i/o: quantized direction structure */
235 : Word32 azimuth_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], // Q22
236 : Word32 elevation_orig[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES], // Q22
237 : const Word16 raw_flag[MASA_MAXIMUM_CODING_SUBBANDS],
238 : Word16 bits_dir_bands[MASA_MAXIMUM_CODING_SUBBANDS],
239 : Word16 *diff )
240 : {
241 : Word16 i, j;
242 : UWord16 bits_dir[MASA_MAXIMUM_CODING_SUBBANDS][MAX_PARAM_SPATIAL_SUBFRAMES];
243 :
244 8070 : test();
245 8070 : IF( ( *diff > 0 ) && ( q_direction->not_in_2D > 0 ) )
246 : {
247 35082 : FOR( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ )
248 : {
249 142225 : FOR( j = 0; j < q_direction->cfg.nblocks; j++ )
250 : {
251 113780 : bits_dir[i][j] = q_direction->band_data[i].bits_sph_idx[j];
252 113780 : move16();
253 : }
254 : }
255 :
256 6637 : small_reduction_direction_fx( q_direction, bits_dir, raw_flag, diff );
257 :
258 6637 : IF( *diff <= 0 )
259 : {
260 6474 : FOR( i = q_direction->cfg.start_band; i < q_direction->cfg.nbands; i++ )
261 : {
262 5163 : IF( EQ_16( raw_flag[i], 1 ) )
263 : {
264 4456 : bits_dir_bands[i] = 0;
265 4456 : move16();
266 22280 : FOR( j = 0; j < q_direction->cfg.nblocks; j++ )
267 : {
268 17824 : bits_dir_bands[i] = add( bits_dir_bands[i], bits_dir[i][j] );
269 17824 : move16();
270 17824 : q_direction->band_data[i].bits_sph_idx[j] = bits_dir[i][j];
271 17824 : move16();
272 :
273 : /* requantize the direction */
274 35648 : q_direction->band_data[i].spherical_index[j] = quantize_direction_fx(
275 17824 : elevation_orig[i][j], azimuth_orig[i][j],
276 17824 : q_direction->band_data[i].bits_sph_idx[j],
277 17824 : &q_direction->band_data[i].elevation_fx[j], &q_direction->band_data[i].azimuth_fx[j],
278 17824 : &q_direction->band_data[i].elevation_index[j], &q_direction->band_data[i].azimuth_index[j],
279 : q_direction->cfg.mc_ls_setup );
280 17824 : move16();
281 :
282 17824 : if ( EQ_32( q_direction->band_data[i].azimuth_index[j], MASA_NO_INDEX ) )
283 : {
284 20 : q_direction->band_data[i].azimuth_index[j] = 0;
285 20 : move16();
286 : }
287 : }
288 : }
289 : }
290 : }
291 : }
292 :
293 8070 : return;
294 : }
295 :
296 : /*-------------------------------------------------------------------*
297 : * quantize_direction()
298 : *
299 : *
300 : *----------------------------------------------------------------------*/
301 : /*! r: quantized spherical index */
302 4023044 : UWord16 quantize_direction_fx(
303 : const Word32 theta, /* i : input elevation value, Q22 */
304 : Word32 phi, /* i : input azimuth value, Q22 */
305 : const Word16 no_bits, /* i : number of bits */
306 : Word32 *theta_q, /* o : quantized elevation, Q22 */
307 : Word32 *phi_q, /* o : quantized azimuth, Q22 */
308 : UWord16 *index_theta, /* o : quantized elevation index */
309 : UWord16 *index_phi, /* o : quantized azimuth index */
310 : const MC_LS_SETUP mc_format /* i : channel format if in MC-mode */
311 : )
312 : {
313 : Word32 abs_theta, theta_hat, phi_hat;
314 : Word16 i, sign_th;
315 : Word16 cum_n[500];
316 : Word16 id_th, id_phi;
317 : Word32 theta_cb[MAX_NO_THETA];
318 : Word16 no_th;
319 : UWord16 idx_sph;
320 : Word16 id_phi_remap;
321 :
322 4023044 : set32_fx( theta_cb, 0, MAX_NO_THETA );
323 :
324 4023044 : IF( no_bits == 0 )
325 : {
326 0 : *theta_q = 0;
327 0 : *phi_q = 0;
328 0 : *index_theta = MASA_NO_INDEX;
329 0 : *index_phi = MASA_NO_INDEX;
330 0 : move32();
331 0 : move32();
332 0 : move16();
333 0 : move16();
334 :
335 0 : return 0;
336 : }
337 :
338 4023044 : IF( EQ_16( no_bits, 1 ) )
339 : {
340 0 : *theta_q = 0;
341 0 : *index_theta = MASA_NO_INDEX;
342 0 : move32();
343 0 : move16();
344 :
345 0 : test();
346 0 : IF( LT_32( phi, ( -DEGREE_90_Q_22 ) ) || GT_32( phi, DEGREE_90_Q_22 ) )
347 : {
348 0 : *phi_q = -DEGREE_180_Q_22;
349 0 : *index_phi = 1;
350 0 : move32();
351 0 : move16();
352 :
353 0 : return 1;
354 : }
355 : ELSE
356 : {
357 0 : *phi_q = 0;
358 0 : *index_phi = 0;
359 0 : move32();
360 0 : move16();
361 :
362 0 : return 0;
363 : }
364 : }
365 :
366 4023044 : IF( EQ_16( no_bits, 2 ) )
367 : {
368 691 : *theta_q = 0;
369 691 : *index_theta = MASA_NO_INDEX;
370 691 : move32();
371 691 : move16();
372 691 : IF( NE_32( mc_format, MC_LS_SETUP_INVALID ) )
373 : {
374 15 : id_phi = quantize_phi_chan_lbr_fx( phi, &phi_hat, no_phi_masa[no_bits - 1][0] );
375 15 : phi_hat = L_add( phi_hat, DEGREE_180_Q_22 );
376 15 : idx_sph = id_phi;
377 15 : *phi_q = L_sub( phi_hat, DEGREE_180_Q_22 );
378 15 : id_phi_remap = id_phi;
379 15 : *index_phi = id_phi_remap;
380 15 : move16();
381 15 : move32();
382 15 : move16();
383 15 : move16();
384 : }
385 : ELSE
386 : {
387 676 : id_phi = quantize_phi_enc_fx( L_add( phi, DEGREE_180_Q_22 ), 0, &phi_hat, no_phi_masa[no_bits - 1][0] );
388 676 : idx_sph = id_phi;
389 676 : *phi_q = L_sub( phi_hat, DEGREE_180_Q_22 );
390 676 : id_phi_remap = ivas_qmetadata_reorder_generic_fx( sub( id_phi, shr( no_phi_masa[no_bits - 1][0], 1 ) ) );
391 676 : *index_phi = id_phi_remap;
392 676 : move16();
393 676 : move32();
394 676 : move16();
395 : }
396 :
397 691 : return idx_sph;
398 : }
399 :
400 4022353 : no_th = no_theta_masa[no_bits - 3];
401 4022353 : move16();
402 :
403 32387524 : FOR( i = 0; i < no_th; i++ )
404 : {
405 28365171 : theta_cb[i] = imult3216( delta_theta_masa_fx[no_bits - 3], i );
406 28365171 : move32();
407 : }
408 :
409 4022353 : if ( GT_32( theta_cb[i - 1], DEGREE_90_Q_22 ) )
410 : {
411 1739177 : theta_cb[i - 1] = DEGREE_90_Q_22;
412 1739177 : move32();
413 : }
414 :
415 4022353 : phi = L_add( phi, DEGREE_180_Q_22 );
416 :
417 4022353 : IF( theta < 0 )
418 : {
419 2032520 : abs_theta = L_negate( theta );
420 2032520 : sign_th = -1;
421 2032520 : move16();
422 : }
423 : ELSE
424 : {
425 1989833 : abs_theta = theta;
426 1989833 : sign_th = 1;
427 1989833 : move32();
428 1989833 : move16();
429 : }
430 :
431 4022353 : theta_hat = quantize_theta_phi_fx( theta_cb, no_th, no_phi_masa[no_bits - 1], abs_theta, &id_phi,
432 : &id_phi_remap, &phi_hat, phi, no_bits, &id_th, phi_q, 1, mc_format );
433 :
434 4022353 : IF( NE_32( mc_format, MC_LS_SETUP_INVALID ) )
435 : {
436 : /* indexing only for upper hemisphere */
437 33268 : cum_n[0] = no_phi_masa[no_bits - 1][0];
438 33268 : move16();
439 166595 : FOR( i = 1; i < no_th; i++ )
440 : {
441 133327 : cum_n[i] = add( cum_n[i - 1], no_phi_masa[no_bits - 1][i] );
442 133327 : move16();
443 : }
444 :
445 33268 : IF( LT_16( id_phi, MASA_NO_INDEX ) )
446 : {
447 33150 : IF( id_th == 0 )
448 : {
449 4245 : idx_sph = id_phi;
450 4245 : move16();
451 : }
452 : ELSE
453 : {
454 28905 : idx_sph = add( cum_n[id_th - 1], id_phi );
455 : }
456 : }
457 : ELSE{
458 118 : IF( id_th == 0 ){
459 0 : idx_sph = 0;
460 0 : move16();
461 : }
462 : ELSE
463 : {
464 118 : idx_sph = cum_n[id_th - 1];
465 118 : move16();
466 : }
467 : }
468 33268 : *theta_q = theta_hat;
469 33268 : move32();
470 33268 : IF( EQ_32( theta_hat, DEGREE_90_Q_22 ) )
471 : {
472 118 : *phi_q = 0;
473 118 : id_phi = MASA_NO_INDEX;
474 118 : move32();
475 118 : move16();
476 : }
477 : ELSE
478 : {
479 33150 : *phi_q = L_sub( phi_hat, DEGREE_180_Q_22 );
480 33150 : move32();
481 : }
482 33268 : *index_theta = id_th;
483 33268 : *index_phi = id_phi_remap;
484 33268 : move16();
485 33268 : move16();
486 : }
487 : ELSE
488 : {
489 : /* Starting from Equator, alternating positive and negative */
490 3989085 : cum_n[0] = no_phi_masa[no_bits - 1][0];
491 3989085 : move16();
492 28198576 : FOR( i = 1; i < no_th; i++ )
493 : {
494 24209491 : cum_n[2 * i - 1] = add( cum_n[2 * i - 2], no_phi_masa[no_bits - 1][i] );
495 24209491 : cum_n[2 * i] = add( cum_n[2 * i - 1], no_phi_masa[no_bits - 1][i] );
496 24209491 : move16();
497 24209491 : move16();
498 : }
499 :
500 3989085 : if ( no_th > 0 )
501 : {
502 3989085 : assert( abs( cum_n[2 * ( no_th - 1 )] ) < 32768 );
503 : }
504 :
505 3989085 : IF( id_th == 0 )
506 : {
507 2098548 : IF( LT_16( id_phi, MASA_NO_INDEX ) )
508 : {
509 2098548 : idx_sph = id_phi;
510 2098548 : move16();
511 : }
512 : ELSE
513 : {
514 0 : idx_sph = 0;
515 0 : move16();
516 : }
517 : }
518 : ELSE{
519 1890537 : IF( sign_th > 0 ){
520 754843 : IF( LT_16( id_phi, MASA_NO_INDEX ) ){
521 753710 : idx_sph = add( cum_n[2 * id_th - 2], id_phi );
522 : }
523 : ELSE
524 : {
525 1133 : idx_sph = cum_n[2 * id_th - 2];
526 1133 : move16();
527 : }
528 :
529 754843 : id_th = sub( shl( id_th, 1 ), 1 );
530 : }
531 : ELSE
532 : {
533 1135694 : IF( LT_16( id_phi, MASA_NO_INDEX ) )
534 : {
535 1133586 : idx_sph = add( cum_n[2 * id_th - 1], id_phi );
536 : }
537 : ELSE
538 : {
539 2108 : idx_sph = cum_n[2 * id_th - 1];
540 2108 : move16();
541 : }
542 1135694 : id_th = shl( id_th, 1 );
543 : }
544 : }
545 :
546 3989085 : *theta_q = imult3216( theta_hat, sign_th );
547 3989085 : move32();
548 3989085 : IF( EQ_32( theta_hat, DEGREE_90_Q_22 ) )
549 : {
550 3174 : *phi_q = 0;
551 3174 : id_phi = MASA_NO_INDEX;
552 3174 : move32();
553 3174 : move16();
554 : }
555 : ELSE
556 : {
557 3985911 : *phi_q = L_sub( phi_hat, DEGREE_180_Q_22 );
558 3985911 : move32();
559 : }
560 :
561 3989085 : *index_theta = id_th;
562 3989085 : *index_phi = id_phi_remap;
563 3989085 : move16();
564 3989085 : move16();
565 : }
566 :
567 4022353 : return idx_sph;
568 : }
569 :
570 : /*-------------------------------------------------------------------*
571 : * direction_distance_cp()
572 : *
573 : * quantization distortion calculated on the sphere
574 : *----------------------------------------------------------------------*/
575 : /*! r: distortion value */
576 2307619 : static Word16 direction_distance_cp_fx( // Q14
577 : Word32 theta, /* i : elevation absolute value, Q22 */
578 : Word32 theta_hat, /* i : quantized elevation value in absolute value, Q22 */
579 : Word32 theta_hat1, /* i : quantized elevation value in absolute value, Q22 */
580 : const Word32 phi, /* i : azimuth value, Q22 */
581 : const Word32 phi_hat, /* i : quantized azimuth value, Q22 */
582 : const Word32 phi_hat1, /* i : quantized azimuth value, Q22 */
583 : Word16 *d1 /* o : Q14 */
584 : )
585 : {
586 : Word16 d, ct, st, st1, st2;
587 : Word16 theta16, theta_hat16, theta_hat1_16;
588 : Word16 tmp, tmp_e, tmp_phi;
589 :
590 2307619 : theta16 = extract_l( Mpy_32_32( theta, PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
591 2307619 : theta_hat16 = extract_l( Mpy_32_32( theta_hat, PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
592 2307619 : theta_hat1_16 = extract_l( Mpy_32_32( theta_hat1, PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
593 :
594 2307619 : st = getSinWord16( theta16 ); // Q15
595 2307619 : ct = getCosWord16( theta16 ); // Q14
596 2307619 : st1 = getSinWord16( theta_hat16 ); // Q15
597 2307619 : st2 = getSinWord16( theta_hat1_16 ); // Q15
598 :
599 : // d = st * st1 + ct * ( sqrtf( 1 - st1 * st1 ) ) * cosf( ( phi - phi_hat ) * PI_OVER_180 );
600 :
601 : /*( phi - phi_hat ) * PI_OVER_180 */
602 2307619 : IF( GT_32( L_sub( phi, phi_hat ), _180_IN_Q22 ) )
603 : {
604 : // cos(360 - theta) = cos(theta)
605 202912 : tmp_phi = extract_l( Mpy_32_32( L_sub( _360_IN_Q22, L_sub( phi, phi_hat ) ), PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
606 : }
607 2104707 : ELSE IF( LT_32( L_sub( phi, phi_hat ), -_180_IN_Q22 ) )
608 : {
609 : // cos(360 + theta) = cos(theta)
610 0 : tmp_phi = extract_l( Mpy_32_32( L_add( _360_IN_Q22, L_sub( phi, phi_hat ) ), PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
611 : }
612 : ELSE
613 : {
614 2104707 : tmp_phi = extract_l( Mpy_32_32( L_sub( phi, phi_hat ), PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
615 : }
616 :
617 2307619 : tmp_e = 0;
618 2307619 : move16();
619 2307619 : tmp = Sqrt16( sub( MAX16B, mult( st1, st1 ) ), &tmp_e );
620 2307619 : tmp = shl_sat( tmp, tmp_e ); // Q15
621 :
622 2307619 : tmp = mult( tmp, shl_sat( getCosWord16( tmp_phi ), 1 ) /* Q15 */ ); // Q15
623 2307619 : tmp = mult( tmp, ct /* Q14 */ ); // Q14
624 :
625 2307619 : tmp = add_sat( tmp, shr( mult( st, st1 ), 1 ) /* Q14 */ ); // Q14
626 :
627 2307619 : d = tmp; // Q14
628 2307619 : move16();
629 :
630 : // *d1 = st * st2 + ct * ( sqrtf( 1 - st2 * st2 ) ) * cosf( ( phi - phi_hat1 ) * PI_OVER_180 );
631 :
632 : /*( phi - phi_hat1 ) * PI_OVER_180 */
633 2307619 : IF( GT_32( L_sub( phi, phi_hat1 ), _180_IN_Q22 ) )
634 : {
635 : // cos(360 - theta) = cos(theta)
636 272948 : tmp_phi = extract_l( Mpy_32_32( L_sub( _360_IN_Q22, L_sub( phi, phi_hat1 ) ), PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
637 : }
638 2034671 : ELSE IF( LT_32( L_sub( phi, phi_hat1 ), -_180_IN_Q22 ) )
639 : {
640 : // cos(360 + theta) = cos(theta)
641 0 : tmp_phi = extract_l( Mpy_32_32( L_add( _360_IN_Q22, L_sub( phi, phi_hat1 ) ), PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
642 : }
643 : ELSE
644 : {
645 2034671 : tmp_phi = extract_l( Mpy_32_32( L_sub( phi, phi_hat1 ), PI_OVER_180_Q22 ) ); // (Q22 + Q22 - 31) = Q13
646 : }
647 :
648 2307619 : tmp_e = 0;
649 2307619 : move16();
650 2307619 : tmp = Sqrt16( sub( MAX16B, mult( st2, st2 ) ), &tmp_e );
651 2307619 : tmp = shl_sat( tmp, tmp_e ); // Q15
652 :
653 2307619 : tmp = mult( tmp, shl_sat( getCosWord16( tmp_phi ), 1 ) /* Q15 */ ); // Q15
654 2307619 : tmp = mult( tmp, ct /* Q14 */ ); // Q14
655 :
656 2307619 : tmp = add_sat( tmp, shr( mult( st, st2 ), 1 ) /* Q14 */ ); // Q14
657 :
658 2307619 : *d1 = tmp;
659 2307619 : move16();
660 :
661 2307619 : return d;
662 : }
663 :
664 : /*-------------------------------------------------------------------*
665 : * quantize_theta_phi()
666 : *
667 : * joint quantization of elevation and azimuth
668 : *----------------------------------------------------------------------*/
669 : /*! r: quantized elevation value */
670 4022353 : static Word32 quantize_theta_phi_fx( // Q22
671 : Word32 *theta_cb, /* i : elevation codebook, Q22 */
672 : const Word16 no_th, /* i : elevation codebook size */
673 : const Word16 *no_phi_loc, /* i : number of azimuth values for each elevation codeword */
674 : const Word32 abs_theta, /* i : absolute value of elevation to be quantized, Q22 */
675 : Word16 *id_phi, /* o : azimuth index */
676 : Word16 *id_phi_remap, /* o : remapped azimuth index */
677 : Word32 *phi_hat, /* o : quantized azimuth value, Q22 */
678 : const Word32 phi, /* i : input azimuth value; to be quantized, Q22 */
679 : const Word16 no_bits, /* i : number of bits used for quantization */
680 : Word16 *id_theta, /* o : elevation index */
681 : Word32 *phi_q, /* o : rotated quantized azimuth, Q22 */
682 : const Word16 remap, /* i : flag for remapping */
683 : const MC_LS_SETUP mc_format /* i : channel format if in MC-mode */
684 : )
685 : {
686 : Word32 theta_hat, theta_hat1, phi_hat1;
687 : Word16 theta_hat16, theta_cb16[MAX_NO_THETA];
688 : Word16 id_th, id_th1, id_th2, id_ph, id_ph1, s;
689 : Word16 d_fx, d1_fx;
690 :
691 4022353 : set16_fx( theta_cb16, 0, MAX_NO_THETA );
692 :
693 4022353 : id_th = BASOP_Util_Divide3232_Scale( abs_theta, delta_theta_masa_fx[no_bits - 3], &s );
694 4022353 : id_th = shr( id_th, sub( 15, s ) ); // Q0
695 :
696 4022353 : IF( GE_16( id_th, no_th ) )
697 : {
698 21 : id_th = sub( no_th, 1 );
699 : }
700 4022353 : theta_hat = theta_cb[id_th];
701 4022353 : move32();
702 :
703 4022353 : IF( LT_16( id_th, sub( no_th, 1 ) ) )
704 : {
705 3790164 : Copy_Scale_sig32_16( theta_cb, theta_cb16, MAX_NO_THETA, 0 ); // Q6
706 :
707 3790164 : id_th = add( id_th, squant_fx( round_fx( abs_theta ), &theta_hat16, &theta_cb16[id_th], 2 ) );
708 :
709 3790164 : theta_hat = L_deposit_h( theta_hat16 ); // Q6 -> Q22
710 : }
711 :
712 4022353 : IF( GT_16( no_th, 1 ) )
713 : {
714 4022353 : test();
715 4022353 : IF( LT_16( no_th, 6 ) && EQ_32( mc_format, MC_LS_SETUP_INVALID ) )
716 : {
717 2337678 : IF( id_th == 0 )
718 : {
719 1289674 : id_th1 = 1;
720 1289674 : move16();
721 : }
722 1048004 : ELSE IF( EQ_16( id_th, sub( no_th, 1 ) ) )
723 : {
724 574603 : id_th1 = sub( no_th, 2 );
725 : }
726 : ELSE
727 : {
728 473401 : id_th1 = sub( id_th, 1 );
729 473401 : id_th2 = add( id_th, 1 );
730 :
731 473401 : if ( GT_32( L_abs( L_sub( abs_theta, theta_cb[id_th1] ) ), L_abs( L_sub( abs_theta, theta_cb[id_th2] ) ) ) )
732 : {
733 167904 : id_th1 = id_th2;
734 167904 : move16();
735 : }
736 : }
737 : }
738 : ELSE
739 : {
740 1684675 : id_th1 = id_th;
741 1684675 : move16();
742 : }
743 :
744 4022353 : IF( GT_16( no_phi_loc[id_th], 1 ) )
745 : {
746 : /* Note: (id_th % 2 == 1) must be equal to id_th % 2 */
747 4018994 : IF( NE_32( mc_format, MC_LS_SETUP_INVALID ) )
748 : {
749 33150 : id_ph = quantize_phi_chan_compand_fx( phi, phi_hat, no_phi_loc[id_th], (Word16) GT_32( L_shr( theta_cb[id_th], Q22 ), MC_MASA_THR_ELEVATION ), mc_format );
750 33150 : *id_phi_remap = id_ph;
751 33150 : move16();
752 : }
753 : ELSE
754 : {
755 3985844 : id_ph = quantize_phi_enc_fx( phi, s_and( id_th, 1 ), phi_hat, no_phi_loc[id_th] );
756 : }
757 : }
758 : ELSE
759 : {
760 3359 : id_ph = MASA_NO_INDEX;
761 3359 : *id_phi_remap = MASA_NO_INDEX;
762 3359 : *phi_hat = DEGREE_180_Q_22;
763 3359 : *phi_q = 0;
764 3359 : move16();
765 3359 : move16();
766 3359 : move32();
767 3359 : move32();
768 : }
769 :
770 4022353 : test();
771 4022353 : test();
772 4022353 : test();
773 4022353 : IF( GT_16( no_phi_loc[id_th1], 1 ) && LT_16( id_ph, MASA_NO_INDEX ) && LT_16( no_th, 6 ) && EQ_32( mc_format, MC_LS_SETUP_INVALID ) )
774 : {
775 2307619 : theta_hat1 = theta_cb[id_th1];
776 2307619 : move32();
777 :
778 2307619 : id_ph1 = quantize_phi_enc_fx( phi, s_and( id_th1, 1 ), &phi_hat1, no_phi_loc[id_th1] );
779 :
780 2307619 : d_fx = direction_distance_cp_fx( abs_theta, theta_hat, theta_hat1, phi, *phi_hat, phi_hat1, &d1_fx );
781 :
782 2307619 : IF( GT_16( d1_fx, d_fx ) )
783 : {
784 238739 : *phi_hat = phi_hat1;
785 238739 : id_ph = id_ph1;
786 238739 : theta_hat = theta_cb[id_th1];
787 238739 : id_th = id_th1;
788 238739 : move16();
789 238739 : move16();
790 238739 : move32();
791 238739 : move32();
792 : }
793 : }
794 : }
795 : ELSE
796 : {
797 0 : IF( NE_32( mc_format, MC_LS_SETUP_INVALID ) )
798 : {
799 0 : id_ph = quantize_phi_chan_compand_fx( phi, phi_hat, no_phi_loc[id_th], 0, mc_format );
800 0 : *id_phi_remap = id_ph;
801 0 : move16();
802 : }
803 : ELSE
804 : {
805 0 : id_ph = quantize_phi_enc_fx( phi, s_and( id_th, 1 ), phi_hat, no_phi_loc[id_th] );
806 : }
807 : }
808 :
809 4022353 : IF( remap )
810 : {
811 4022353 : IF( LT_16( id_ph, MASA_NO_INDEX ) )
812 : {
813 4018994 : *id_phi_remap = ivas_qmetadata_reorder_generic_fx( sub( id_ph, shr( no_phi_loc[id_th], 1 ) ) );
814 4018994 : move16();
815 : }
816 : }
817 : ELSE
818 : {
819 0 : *id_phi_remap = id_ph;
820 0 : move16();
821 : }
822 :
823 4022353 : *id_phi = id_ph;
824 4022353 : *id_theta = id_th;
825 4022353 : move16();
826 4022353 : move16();
827 :
828 4022353 : return theta_hat;
829 : }
|