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