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 <stdint.h>
34 : #include "options.h"
35 : #include <math.h>
36 : #include <assert.h>
37 : #include "prot_fx.h"
38 : #include "ivas_prot_rend_fx.h"
39 : #include "ivas_rom_com.h"
40 : #include "ivas_rom_rend.h"
41 : #include "wmc_auto.h"
42 : #include "ivas_prot_fx.h"
43 :
44 : #include "debug.h"
45 :
46 : /*----------------------------------------------------------------------------------*
47 : * Local constants
48 : *----------------------------------------------------------------------------------*/
49 :
50 :
51 : #define LS_OUT_CONV_SMOOTHING_FACTOR_Q31 93415539
52 : #define LS_OUT_CONV_CLIP_FACTOR_MAX_Q30 2147483647
53 : #define LS_OUT_CONV_CLIP_FACTOR_MIN_Q30 322122547
54 :
55 :
56 : /*----------------------------------------------------------------------------------*
57 : * Local functions
58 : *----------------------------------------------------------------------------------*/
59 :
60 3637445 : static void ivas_lssetupconversion_computeEQFactor_fx(
61 : Word32 *outputEnergy,
62 : Word16 output_exp,
63 : Word32 *inputEnergy,
64 : Word16 input_exp,
65 : Word32 *EQ )
66 : {
67 3637445 : test();
68 3637445 : IF( ( *outputEnergy == 0 ) && ( *inputEnergy == 0 ) )
69 : {
70 822187 : *EQ = ONE_IN_Q30; // Q30
71 822187 : move32();
72 822187 : return;
73 : }
74 : /* Compute the Equalization Gain */
75 : Word16 tmp_e;
76 2815258 : Word16 tmp = BASOP_Util_Divide3232_Scale( *outputEnergy, L_add( EPSILON_FX, *inputEnergy ), &tmp_e );
77 2815258 : tmp_e = add( tmp_e, sub( output_exp, input_exp ) );
78 2815258 : Word32 tmp_32 = L_deposit_h( tmp );
79 2815258 : tmp_32 = Sqrt32( tmp_32, &tmp_e );
80 2815258 : *EQ = L_shr_sat( tmp_32, sub( 1, tmp_e ) ); // range of EQ in float 0.3 - 2.0
81 2815258 : move32();
82 :
83 2815258 : *EQ = L_min( *EQ, LS_OUT_CONV_CLIP_FACTOR_MAX_Q30 );
84 2815258 : *EQ = L_max( *EQ, LS_OUT_CONV_CLIP_FACTOR_MIN_Q30 );
85 2815258 : move32();
86 2815258 : move32();
87 :
88 2815258 : return;
89 : }
90 :
91 :
92 69 : static void ivas_lssetupconversion_mdct_init_bands_fx(
93 : const Word16 output_frame, /* i : output frame length */
94 : const Word16 tcx_mode, /* i : tcx mode (TCX10, TCX 20) */
95 : Word16 *sfbOffset, /* o : sfb offset table */
96 : Word16 *sfbCnt /* o : number of sfbs */
97 : )
98 : {
99 : SpectrumWarping const *lpcBndsParam;
100 : Word16 i, cnt, specStartOffset, L_frameTCX;
101 : const UWord8 *sfbWidths;
102 :
103 69 : IF( EQ_16( tcx_mode, TCX_20_CORE ) )
104 : {
105 69 : L_frameTCX = output_frame;
106 69 : move16();
107 : }
108 : ELSE
109 : {
110 0 : L_frameTCX = shr( output_frame, 1 );
111 : }
112 :
113 :
114 69 : SWITCH( output_frame )
115 : {
116 69 : case L_FRAME48k:
117 : case L_FRAME32k:
118 69 : lpcBndsParam = sw32000Hz;
119 69 : BREAK;
120 0 : case L_FRAME25_6k:
121 0 : lpcBndsParam = sw25600Hz;
122 0 : BREAK;
123 0 : case L_FRAME16k:
124 0 : lpcBndsParam = sw16000Hz;
125 0 : BREAK;
126 0 : default:
127 0 : assert( !"Subband division not defined for this frame size" );
128 : return;
129 : }
130 :
131 69 : IF( EQ_16( tcx_mode, TCX_20_CORE ) )
132 : {
133 69 : sfbWidths = lpcBndsParam->bandLengthsTCX20;
134 69 : cnt = 64;
135 69 : move16();
136 : }
137 : ELSE
138 : {
139 0 : sfbWidths = lpcBndsParam->bandLengthsTCX10;
140 0 : cnt = 32;
141 0 : move16();
142 : }
143 :
144 : /* calc sfb offsets */
145 69 : specStartOffset = 0;
146 69 : move16();
147 :
148 4485 : FOR( i = 0; i < cnt; i++ )
149 : {
150 4416 : sfbOffset[i] = s_min( specStartOffset, L_frameTCX );
151 4416 : move16();
152 4416 : specStartOffset = add( specStartOffset, sfbWidths[i] );
153 :
154 4416 : IF( GE_16( sfbOffset[i], L_frameTCX ) )
155 : {
156 0 : BREAK;
157 : }
158 : }
159 :
160 69 : *sfbCnt = i;
161 69 : move16();
162 69 : sfbOffset[*sfbCnt] = s_min( specStartOffset, L_frameTCX );
163 69 : move16();
164 :
165 69 : IF( LT_16( sfbOffset[*sfbCnt], L_frameTCX ) )
166 : {
167 66 : Word16 nMissingBins = sub( L_frameTCX, sfbOffset[*sfbCnt] );
168 :
169 66 : IF( LT_16( shr( (Word16) sfbWidths[i], 1 ), nMissingBins ) )
170 : {
171 66 : ( *sfbCnt ) = add( ( *sfbCnt ), 1 );
172 66 : move16();
173 : }
174 66 : sfbOffset[*sfbCnt] = L_frameTCX;
175 66 : move16();
176 : }
177 :
178 69 : return;
179 : }
180 :
181 :
182 1 : static void get_custom_ls_conversion_matrix_fx(
183 : const EFAP_HANDLE hEFAPdata, /* i : EFAP handle */
184 : const IVAS_OUTPUT_SETUP hTransSetup, /* i : Transport channel configuration handle */
185 : const LSSETUP_CUSTOM_HANDLE hLsSetupCustom, /* i : Custom LS Setup handle */
186 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion /* o : LS Setup Conversion Handle */
187 : )
188 : {
189 : Word16 ch_in, ch_in_woLFE;
190 : Word16 ch_out, ch_out_woLFE;
191 : Word16 nchan_in, nchan_out;
192 : Word16 lfe_in_idx, lfe_out_idx;
193 :
194 : Word32 dmxCoeff_LFE;
195 : Word32 tmp_gains[MAX_OUTPUT_CHANNELS];
196 :
197 1 : lfe_in_idx = -1;
198 1 : move16();
199 1 : lfe_out_idx = -1;
200 1 : move16();
201 :
202 1 : nchan_in = add( hTransSetup.nchan_out_woLFE, hTransSetup.num_lfe );
203 1 : nchan_out = add( hLsSetupCustom->num_spk, hLsSetupCustom->num_lfe );
204 :
205 : /* The below code will need to be restructured in case additional LFEs must be supported */
206 1 : if ( hTransSetup.num_lfe > 0 )
207 : {
208 1 : lfe_in_idx = hTransSetup.index_lfe[0];
209 1 : move16();
210 : }
211 1 : if ( hLsSetupCustom->num_lfe > 0 )
212 : {
213 0 : lfe_out_idx = hLsSetupCustom->lfe_idx[0];
214 0 : move16();
215 : }
216 :
217 1 : IF( EQ_16( hTransSetup.nchan_out_woLFE, 1 ) )
218 : {
219 0 : dmxCoeff_LFE = ONE_IN_Q30;
220 0 : move32();
221 : }
222 : ELSE
223 : {
224 1 : dmxCoeff_LFE = L_shl( (Word32) div_s( 1, hTransSetup.nchan_out_woLFE ), Q15 ); // Q30
225 : }
226 :
227 7 : FOR( ( ch_in = 0, ch_in_woLFE = 0 ); ch_in < nchan_in; ( ch_in++, ch_in_woLFE++ ) )
228 : {
229 6 : IF( EQ_16( lfe_in_idx, ch_in ) )
230 : {
231 1 : IF( lfe_out_idx >= 0 )
232 : {
233 : /* re-route LFE */
234 0 : hLsSetUpConversion->dmxMtx_fx[ch_in][lfe_out_idx] = ONE_IN_Q30;
235 0 : move32();
236 : }
237 : ELSE
238 : {
239 : /* mix the LFE to all channels */
240 1 : set32_fx( hLsSetUpConversion->dmxMtx_fx[ch_in], dmxCoeff_LFE, nchan_out );
241 : }
242 :
243 1 : ch_in_woLFE = sub( ch_in_woLFE, 1 );
244 : }
245 5 : ELSE IF( NE_16( lfe_out_idx, ch_in ) )
246 : {
247 : /* Set the values of hLsSetUpConversion->dmxMtx to EFAP gains, skipping LFE */
248 5 : efap_determine_gains_fx( hEFAPdata, tmp_gains, hTransSetup.ls_azimuth_fx[ch_in_woLFE], hTransSetup.ls_elevation_fx[ch_in_woLFE], EFAP_MODE_EFAP );
249 :
250 85 : FOR( ( ch_out = 0, ch_out_woLFE = 0 ); ch_out < nchan_out; ( ch_out++, ch_out_woLFE++ ) )
251 : {
252 80 : IF( EQ_16( lfe_out_idx, ch_out ) )
253 : {
254 0 : ch_out_woLFE = sub( ch_out_woLFE, 1 );
255 : }
256 : ELSE
257 : {
258 80 : hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
259 80 : move32();
260 : }
261 : }
262 : }
263 : }
264 :
265 1 : return;
266 : }
267 :
268 125 : static ivas_error get_ls_conversion_matrix_fx(
269 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion,
270 : const AUDIO_CONFIG input_config,
271 : const AUDIO_CONFIG output_config )
272 : {
273 : Word16 i, k;
274 : Word16 ch_in, ch_out;
275 : Word16 nchan_in, nchan_out;
276 : Word16 index;
277 : Word32 value;
278 : const LS_CONVERSION_MATRIX_FX *conversion_matrix_fx;
279 : ivas_error error;
280 :
281 125 : error = IVAS_ERR_OK;
282 :
283 125 : conversion_matrix_fx = NULL;
284 :
285 125 : nchan_in = audioCfg2channels( input_config );
286 125 : nchan_out = audioCfg2channels( output_config );
287 :
288 : /* Search the table for a mapping */
289 3437 : FOR( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; i++ )
290 : {
291 3437 : test();
292 3437 : IF( ( EQ_32( input_config, ls_conversion_mapping_fx[i].input_config ) ) && ( EQ_32( output_config, ls_conversion_mapping_fx[i].output_config ) ) )
293 : {
294 : /* Special handling for MONO and STEREO downmix */
295 125 : test();
296 125 : IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( output_config, IVAS_AUDIO_CONFIG_STEREO ) )
297 : {
298 82 : FOR( ( ch_in = 0, k = 0 ); ch_in < nchan_in; ( ch_in++, k++ ) )
299 : {
300 : /* Skip two rows in the matrix for 5.1.x formats */
301 74 : test();
302 74 : test();
303 74 : IF( EQ_16( ch_in, 6 ) && ( EQ_32( input_config, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( input_config, IVAS_AUDIO_CONFIG_5_1_4 ) ) )
304 : {
305 1 : k = add( k, 2 );
306 : }
307 :
308 216 : FOR( ch_out = 0; ch_out < nchan_out; ch_out++ )
309 : {
310 142 : IF( EQ_32( output_config, IVAS_AUDIO_CONFIG_MONO ) )
311 : {
312 6 : hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = ls_conversion_cicpX_mono_fx[k][ch_out]; // Q30
313 6 : move32();
314 : }
315 : ELSE
316 : {
317 136 : hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = ls_conversion_cicpX_stereo_fx[k][ch_out]; // Q30
318 136 : move32();
319 : }
320 : }
321 : }
322 8 : return error;
323 : }
324 : ELSE
325 : {
326 117 : conversion_matrix_fx = ls_conversion_mapping_fx[i].conversion_matrix_fx;
327 :
328 : /* If a mapping is defined with a NULL matrix, 1:1 upmix of input channels */
329 117 : IF( conversion_matrix_fx == NULL )
330 : {
331 812 : FOR( k = 0; k < nchan_in; k++ )
332 : {
333 696 : hLsSetUpConversion->dmxMtx_fx[k][k] = ONE_IN_Q30;
334 696 : move32();
335 : }
336 116 : return error;
337 : }
338 : ELSE
339 : {
340 9 : FOR( k = 1; k < ( conversion_matrix_fx[0].index + 1 ); k++ )
341 : {
342 8 : index = conversion_matrix_fx[k].index;
343 8 : move16();
344 8 : value = conversion_matrix_fx[k].value; // Q30
345 8 : move16();
346 :
347 8 : IF( index != 0 )
348 : {
349 7 : ch_in = idiv1616( index, nchan_out );
350 : }
351 : ELSE
352 : {
353 1 : ch_in = 0;
354 1 : move16();
355 : }
356 8 : ch_out = index % nchan_out;
357 8 : move16();
358 :
359 8 : hLsSetUpConversion->dmxMtx_fx[ch_in][ch_out] = value; // Q30
360 8 : move32();
361 : }
362 : }
363 1 : return error;
364 : }
365 : }
366 : }
367 :
368 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "The conversion matrix between these formats is not defined!\n" );
369 : }
370 : /*-------------------------------------------------------------------------
371 : * ivas_ls_setup_conversion_open()
372 : *
373 : * Open the LS configuration Conversion Module
374 : *-------------------------------------------------------------------------*/
375 :
376 126 : ivas_error ivas_ls_setup_conversion_open_fx(
377 : Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */
378 : )
379 : {
380 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion;
381 : Word16 chIdx, inChannels, outChannels;
382 : Word16 output_frame;
383 : Word32 output_Fs;
384 : Word16 nchan_out;
385 : Word16 paramUpmixMonoStereo;
386 :
387 126 : test();
388 126 : test();
389 126 : test();
390 126 : IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) && EQ_32( st_ivas->mc_mode, MC_MODE_PARAMUPMIX ) && ( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_STEREO ) ) )
391 : {
392 1 : paramUpmixMonoStereo = TRUE;
393 1 : move16();
394 : }
395 : ELSE
396 : {
397 125 : paramUpmixMonoStereo = FALSE;
398 125 : move16();
399 : }
400 126 : output_Fs = st_ivas->hDecoderConfig->output_Fs;
401 126 : move32();
402 126 : nchan_out = st_ivas->hDecoderConfig->nchan_out;
403 126 : move16();
404 126 : output_frame = (Word16) ( output_Fs / FRAMES_PER_SEC );
405 :
406 : /* Allocate memory to the handle */
407 126 : IF( ( hLsSetUpConversion = (LSSETUP_CONVERSION_HANDLE) malloc( sizeof( LSSETUP_CONVERSION_STRUCT ) ) ) == NULL )
408 : {
409 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) );
410 : }
411 :
412 126 : assert( LE_16( nchan_out, MAX_OUTPUT_CHANNELS ) );
413 :
414 126 : outChannels = nchan_out;
415 126 : move16();
416 126 : IF( EQ_32( st_ivas->renderer_type, RENDERER_MC_PARAMMC ) )
417 : {
418 57 : inChannels = add( st_ivas->hTransSetup.nchan_out_woLFE, st_ivas->hTransSetup.num_lfe );
419 57 : hLsSetUpConversion->sfbCnt = (Word16) ( L_add( output_Fs, 400 ) / CLDFB_BANDWIDTH );
420 715 : FOR( chIdx = 0; chIdx < outChannels; chIdx++ )
421 : {
422 658 : IF( ( hLsSetUpConversion->targetEnergyPrev_fx[chIdx] = (Word32 *) malloc( hLsSetUpConversion->sfbCnt * sizeof( Word32 ) ) ) == NULL )
423 : {
424 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) );
425 : }
426 658 : IF( ( hLsSetUpConversion->dmxEnergyPrev_fx[chIdx] = (Word32 *) malloc( hLsSetUpConversion->sfbCnt * sizeof( Word32 ) ) ) == NULL )
427 : {
428 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) );
429 : }
430 658 : set32_fx( hLsSetUpConversion->targetEnergyPrev_fx[chIdx], 0, hLsSetUpConversion->sfbCnt );
431 658 : hLsSetUpConversion->te_prev_exp[chIdx] = 0;
432 658 : move16();
433 658 : set32_fx( hLsSetUpConversion->dmxEnergyPrev_fx[chIdx], 0, hLsSetUpConversion->sfbCnt );
434 658 : hLsSetUpConversion->dmx_prev_exp[chIdx] = 0;
435 658 : move16();
436 : }
437 311 : FOR( ; chIdx < MAX_CICP_CHANNELS; chIdx++ )
438 : {
439 254 : hLsSetUpConversion->targetEnergyPrev_fx[chIdx] = NULL;
440 254 : hLsSetUpConversion->dmxEnergyPrev_fx[chIdx] = NULL;
441 : }
442 : }
443 : ELSE
444 : {
445 69 : test();
446 69 : IF( EQ_32( st_ivas->ivas_format, MC_FORMAT ) && EQ_32( st_ivas->mc_mode, MC_MODE_PARAMUPMIX ) )
447 : {
448 1 : IF( EQ_16( paramUpmixMonoStereo, TRUE ) )
449 : {
450 1 : inChannels = audioCfg2channels( IVAS_AUDIO_CONFIG_5_1_2 );
451 : }
452 : ELSE
453 : {
454 0 : inChannels = add( st_ivas->hTransSetup.nchan_out_woLFE, st_ivas->hTransSetup.num_lfe );
455 : }
456 : }
457 : ELSE
458 : {
459 68 : inChannels = st_ivas->nchan_transport;
460 68 : move16();
461 : }
462 :
463 : /*Initialization of MDCT bands with TCX20 resolution */
464 69 : ivas_lssetupconversion_mdct_init_bands_fx( output_frame, TCX_20_CORE, &hLsSetUpConversion->sfbOffset[0], &hLsSetUpConversion->sfbCnt );
465 69 : IF( ( hLsSetUpConversion->targetEnergyPrev_fx[0] = (Word32 *) malloc( ( MAX_SFB + 2 ) * sizeof( Word32 ) ) ) == NULL )
466 : {
467 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) );
468 : }
469 69 : IF( ( hLsSetUpConversion->dmxEnergyPrev_fx[0] = (Word32 *) malloc( ( MAX_SFB + 2 ) * sizeof( Word32 ) ) ) == NULL )
470 : {
471 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for LS configuration Conversion Handle \n" ) );
472 : }
473 :
474 1104 : FOR( chIdx = 1; chIdx < MAX_CICP_CHANNELS; chIdx++ )
475 : {
476 1035 : hLsSetUpConversion->targetEnergyPrev_fx[chIdx] = NULL;
477 1035 : hLsSetUpConversion->dmxEnergyPrev_fx[chIdx] = NULL;
478 : }
479 69 : set32_fx( hLsSetUpConversion->targetEnergyPrev_fx[0], 0, MAX_SFB + 2 );
480 69 : set32_fx( hLsSetUpConversion->dmxEnergyPrev_fx[0], 0, MAX_SFB + 2 );
481 :
482 69 : hLsSetUpConversion->te_prev_exp[0] = 0;
483 69 : hLsSetUpConversion->dmx_prev_exp[0] = 0;
484 69 : move16();
485 69 : move16();
486 : }
487 :
488 : /* Initialize the DMX conversion matrix */
489 910 : FOR( chIdx = 0; chIdx < inChannels; chIdx++ )
490 : {
491 : /* Allocate memory depending on the number of output channels */
492 784 : IF( ( hLsSetUpConversion->dmxMtx_fx[chIdx] = (Word32 *) malloc( outChannels * sizeof( Word32 ) ) ) == NULL )
493 : {
494 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for temp dmx matrix \n" ) );
495 : }
496 784 : set32_fx( hLsSetUpConversion->dmxMtx_fx[chIdx], 0, outChannels );
497 : }
498 :
499 1358 : FOR( ; chIdx < MAX_CICP_CHANNELS; chIdx++ )
500 : {
501 1232 : hLsSetUpConversion->dmxMtx_fx[chIdx] = NULL;
502 : }
503 :
504 126 : IF( EQ_32( st_ivas->hDecoderConfig->output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
505 : {
506 1 : get_custom_ls_conversion_matrix_fx( st_ivas->hEFAPdata, st_ivas->hTransSetup, st_ivas->hLsSetupCustom, hLsSetUpConversion );
507 : }
508 : ELSE
509 : {
510 125 : IF( NE_32( st_ivas->transport_config, IVAS_AUDIO_CONFIG_INVALID ) )
511 : {
512 125 : IF( EQ_16( paramUpmixMonoStereo, TRUE ) )
513 : {
514 1 : get_ls_conversion_matrix_fx( hLsSetUpConversion, IVAS_AUDIO_CONFIG_5_1_2, st_ivas->hDecoderConfig->output_config );
515 : }
516 : ELSE
517 : {
518 124 : get_ls_conversion_matrix_fx( hLsSetUpConversion, st_ivas->transport_config, st_ivas->hDecoderConfig->output_config );
519 : }
520 : }
521 : ELSE
522 : {
523 0 : get_ls_conversion_matrix_fx( hLsSetUpConversion, st_ivas->intern_config, st_ivas->hDecoderConfig->output_config );
524 : }
525 : }
526 :
527 126 : st_ivas->hLsSetUpConversion = hLsSetUpConversion;
528 :
529 126 : return IVAS_ERR_OK;
530 : }
531 :
532 : /*-------------------------------------------------------------------------
533 : * ivas_ls_setup_conversion_close()
534 : *
535 : * Close the LS configuration Conversion Module
536 : *-------------------------------------------------------------------------*/
537 :
538 841 : void ivas_ls_setup_conversion_close_fx(
539 : LSSETUP_CONVERSION_HANDLE *hLsSetUpConversion /* i/o: LS converter handle */
540 : )
541 : {
542 : Word16 idx;
543 841 : test();
544 841 : IF( hLsSetUpConversion == NULL || *hLsSetUpConversion == NULL )
545 : {
546 715 : return;
547 : }
548 :
549 2142 : FOR( idx = 0; idx < MAX_CICP_CHANNELS; idx++ )
550 : {
551 2016 : IF( ( *hLsSetUpConversion )->dmxMtx_fx[idx] != NULL )
552 : {
553 784 : free( ( *hLsSetUpConversion )->dmxMtx_fx[idx] );
554 784 : ( *hLsSetUpConversion )->dmxMtx_fx[idx] = NULL;
555 : }
556 :
557 2016 : IF( ( *hLsSetUpConversion )->targetEnergyPrev_fx[idx] != NULL )
558 : {
559 727 : free( ( *hLsSetUpConversion )->targetEnergyPrev_fx[idx] );
560 727 : ( *hLsSetUpConversion )->targetEnergyPrev_fx[idx] = NULL;
561 : }
562 :
563 2016 : IF( ( *hLsSetUpConversion )->dmxEnergyPrev_fx[idx] != NULL )
564 : {
565 727 : free( ( *hLsSetUpConversion )->dmxEnergyPrev_fx[idx] );
566 727 : ( *hLsSetUpConversion )->dmxEnergyPrev_fx[idx] = NULL;
567 : }
568 : }
569 :
570 126 : free( *hLsSetUpConversion );
571 126 : *hLsSetUpConversion = NULL;
572 :
573 126 : return;
574 : }
575 :
576 : /*-------------------------------------------------------------------------
577 : * ivas_ls_setup_conversion()
578 : *
579 : * Convert (downmix or upmix) the input LS configuration
580 : * to output LS configuration in time domain
581 : *-------------------------------------------------------------------------*/
582 :
583 7463 : void ivas_ls_setup_conversion_fx(
584 : Decoder_Struct *st_ivas, /* i : IVAS decoder structure */
585 : const Word16 input_chans, /* i : number of input channels to the renderer */
586 : const Word16 output_frame, /* i : frame length */
587 : Word32 *input[], /* i : LS input/output synthesis signal Qx*/
588 : Word32 *output[] /* i/o: LS input/output synthesis signal Qx*/
589 : )
590 : {
591 : Word16 chInIdx, chOutIdx, idx;
592 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion;
593 : Word32 dmxCoeff, tmpVal;
594 : Word32 output_tmp[MAX_OUTPUT_CHANNELS][L_FRAME48k]; // Qx
595 :
596 7463 : push_wmops( "LS_Renderer" );
597 :
598 7463 : hLsSetUpConversion = st_ivas->hLsSetUpConversion;
599 :
600 69419 : FOR( chOutIdx = 0; chOutIdx < st_ivas->hDecoderConfig->nchan_out; chOutIdx++ )
601 : {
602 61956 : set32_fx( output_tmp[chOutIdx], 0, output_frame );
603 433972 : FOR( chInIdx = 0; chInIdx < input_chans; chInIdx++ )
604 : {
605 372016 : dmxCoeff = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx];
606 372016 : move32();
607 :
608 372016 : IF( dmxCoeff == 0 )
609 : {
610 305998 : CONTINUE;
611 : }
612 66018 : ELSE IF( EQ_32( dmxCoeff, ONE_IN_Q30 ) )
613 : {
614 21977978 : FOR( idx = 0; idx < output_frame; idx++ )
615 : {
616 21949440 : output_tmp[chOutIdx][idx] = L_add( output_tmp[chOutIdx][idx], input[chInIdx][idx] );
617 21949440 : move32();
618 : }
619 : }
620 : ELSE
621 : {
622 35864680 : FOR( idx = 0; idx < output_frame; idx++ )
623 : {
624 35827200 : tmpVal = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), input[chInIdx][idx] );
625 35827200 : output_tmp[chOutIdx][idx] = L_add( output_tmp[chOutIdx][idx], tmpVal );
626 35827200 : move32();
627 : }
628 : }
629 : }
630 : }
631 :
632 : /* Copy to output buffer */
633 69419 : FOR( chOutIdx = 0; chOutIdx < st_ivas->hDecoderConfig->nchan_out; chOutIdx++ )
634 : {
635 61956 : Copy32( output_tmp[chOutIdx], output[chOutIdx], output_frame );
636 : }
637 :
638 7463 : pop_wmops();
639 :
640 7463 : return;
641 : }
642 :
643 : /*-------------------------------------------------------------------------
644 : * ivas_ls_setup_conversion_process_mdct()
645 : *
646 : * Equalization in MDCT Domain
647 : *-------------------------------------------------------------------------*/
648 :
649 6504 : void ivas_ls_setup_conversion_process_mdct_fx(
650 : Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */
651 : Word32 *output[] /* i/o: output synthesis signal */
652 : )
653 : {
654 : /* Declaration of all required variables */
655 : Word16 i, bandIdx, chInIdx, chOutIdx, cpe_idx, subFrameIdx, binIdx, idx, j;
656 : Word16 inChannels, outChannels, num_CPE;
657 : Word16 transform_type[MAX_CICP_CHANNELS][2];
658 : Word16 frameSize;
659 : Word32 targetEnergy[MAX_SFB + 2], dmxEnergy[MAX_SFB + 2];
660 : Word16 dmxEnergy_exp[MAX_SFB + 2], dmxEnergy_exp_temp;
661 : Word32 dmxCoeff;
662 : Word32 dmxSignalReal[L_FRAME48k], dmxSignalImag[L_FRAME48k];
663 : Word32 eqGain;
664 : Word32 *sig[NB_DIV], *pTmp[NB_DIV], *x[MAX_CICP_CHANNELS][NB_DIV];
665 : Word32 mdst[L_FRAME48k];
666 : Word32 convertRes[L_FRAME48k];
667 : Word16 start, stop, start_tcx5, stop_tcx5;
668 : Word16 mct_chan_mode[MAX_CICP_CHANNELS];
669 :
670 : /* Declare all handles */
671 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion;
672 : CPE_DEC_HANDLE hCPE[MCT_MAX_BLOCKS];
673 :
674 6504 : push_wmops( "LS_Renderer_MDCT" );
675 :
676 : /* Assign all the declared variables */
677 6504 : inChannels = st_ivas->nchan_transport;
678 6504 : move16();
679 6504 : outChannels = st_ivas->hDecoderConfig->nchan_out;
680 6504 : move16();
681 6504 : num_CPE = st_ivas->nCPE;
682 6504 : move16();
683 :
684 : /* Assign output pointer to variable x */
685 :
686 : // Scale the array
687 6504 : Word16 q_output = 31;
688 6504 : move16();
689 45728 : FOR( i = 0; i < inChannels; ++i )
690 : {
691 39224 : q_output = s_min( q_output, L_norm_arr( output[i], L_FRAME48k ) );
692 : }
693 :
694 6504 : Word16 tmp_sub = sub( st_ivas->hLsSetUpConversion->sfbOffset[st_ivas->hLsSetUpConversion->sfbCnt], st_ivas->hLsSetUpConversion->sfbOffset[st_ivas->hLsSetUpConversion->sfbCnt - 1] );
695 6504 : Word16 guard_1 = shr( add( find_guarded_bits_fx( tmp_sub ), 1 ), 1 );
696 6504 : Word16 guard_2 = find_guarded_bits_fx( L_mult0( outChannels, inChannels ) );
697 6504 : q_output = sub( q_output, s_max( guard_1, guard_2 ) );
698 :
699 45728 : FOR( i = 0; i < inChannels; ++i )
700 : {
701 37694264 : FOR( j = 0; j < L_FRAME48k; ++j )
702 : {
703 37655040 : output[i][j] = L_shl( output[i][j], q_output );
704 : }
705 : }
706 :
707 45728 : FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ )
708 : {
709 39224 : x[chInIdx][0] = output[chInIdx]; // Q(q_output)
710 39224 : x[chInIdx][1] = output[chInIdx] + L_FRAME48k / 2; // Q(q_output)
711 : }
712 :
713 : /* Assign all the declared handles*/
714 6504 : hLsSetUpConversion = st_ivas->hLsSetUpConversion;
715 26116 : FOR( cpe_idx = 0; cpe_idx < num_CPE; cpe_idx++ )
716 : {
717 19612 : hCPE[cpe_idx] = st_ivas->hCPE[cpe_idx];
718 : }
719 :
720 : /* Get the core type */
721 26116 : FOR( cpe_idx = 0; cpe_idx < num_CPE; cpe_idx++ )
722 : {
723 58836 : FOR( idx = 0; idx < CPE_CHANNELS; idx++ )
724 : {
725 : /* get the channel index */
726 39224 : chInIdx = add( imult1616( cpe_idx, CPE_CHANNELS ), idx );
727 39224 : assert( LE_16( chInIdx, inChannels ) );
728 39224 : transform_type[chInIdx][0] = hCPE[cpe_idx]->hCoreCoder[idx]->transform_type[0];
729 39224 : move16();
730 39224 : transform_type[chInIdx][1] = hCPE[cpe_idx]->hCoreCoder[idx]->transform_type[1];
731 39224 : move16();
732 39224 : mct_chan_mode[chInIdx] = hCPE[cpe_idx]->hCoreCoder[idx]->mct_chan_mode;
733 39224 : move16();
734 : }
735 : }
736 :
737 : /* set overall frequency resolution of (sub)frame to maximum of (sub)frame, requires conversion if both channels are not the same */
738 6504 : frameSize = hLsSetUpConversion->sfbOffset[hLsSetUpConversion->sfbCnt];
739 6504 : move16();
740 :
741 6504 : set32_fx( targetEnergy, 0, MAX_SFB + 2 );
742 6504 : set32_fx( dmxEnergy, 0, MAX_SFB + 2 );
743 6504 : set16_fx( dmxEnergy_exp, 0, MAX_SFB + 2 );
744 6504 : dmxEnergy_exp_temp = 0;
745 6504 : move16();
746 :
747 57152 : FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ )
748 : {
749 : /* Step 0: Set the buffers to zero */
750 50648 : set32_fx( dmxSignalReal, 0, frameSize );
751 50648 : set32_fx( dmxSignalImag, 0, frameSize );
752 :
753 354936 : FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ )
754 : {
755 304288 : dmxCoeff = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx]; // Q30
756 304288 : move32();
757 :
758 304288 : test();
759 304288 : IF(
760 : NE_16( chInIdx, LFE_CHANNEL ) &&
761 : NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) )
762 : {
763 : /* Step 1: Compute the target energy and DMX signal (possible since we have all signals in TCX20 resolution) */
764 199937 : IF( dmxCoeff )
765 : {
766 : Word32 tmpDMXSig, targetEne;
767 :
768 : /* Convert the signal resolution to TCX20 */
769 : /* initially, set pointers to input; if conversion occurs in (sub)frame, set to convertRes */
770 28824 : pTmp[0] = x[chInIdx][0]; // Q(q_output)
771 28824 : sig[0] = pTmp[0];
772 28824 : pTmp[1] = x[chInIdx][1];
773 28824 : sig[1] = pTmp[1]; // Q(q_output)
774 :
775 : /* convert (sub)frames to higher frequency resolution */
776 28824 : IF( NE_16( transform_type[chInIdx][0], TCX_20 ) )
777 : {
778 1545 : FOR( subFrameIdx = 0; subFrameIdx < NB_DIV; subFrameIdx++ )
779 : {
780 1030 : IF( EQ_16( transform_type[chInIdx][subFrameIdx], TCX_5 ) )
781 : {
782 : /* subframe is TCX5, but TCX10 or TCX20 in other channel -> convert channel with TCX5 to TCX10 resolution */
783 544 : sig[subFrameIdx] = convertRes + L_shr( L_mult0( subFrameIdx, frameSize ), 1 );
784 544 : pTmp[subFrameIdx] = sig[subFrameIdx];
785 544 : convert_coeffs_to_higher_res_fx( x[chInIdx][subFrameIdx], x[chInIdx][subFrameIdx] + shr( frameSize, 2 ), pTmp[subFrameIdx], shr( frameSize, 2 ) );
786 : }
787 : }
788 :
789 : /* convert channel with TCX10 to TCX20 resolution */
790 515 : sig[0] = convertRes;
791 515 : convert_coeffs_to_higher_res_fx( pTmp[0], pTmp[1], sig[0], frameSize / 2 );
792 : }
793 :
794 : /* MDST estimate */
795 28824 : mdst[0] = mdst[frameSize - 1] = 0;
796 28824 : move32();
797 28824 : move32();
798 27514216 : FOR( i = 1; i < frameSize - 1; i++ )
799 : {
800 27485392 : mdst[i] = L_sub( sig[0][i + 1], sig[0][i - 1] ); // Q(q_output)
801 : }
802 :
803 1901984 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
804 : {
805 1873160 : start = hLsSetUpConversion->sfbOffset[bandIdx];
806 1873160 : move16();
807 1873160 : stop = hLsSetUpConversion->sfbOffset[bandIdx + 1];
808 1873160 : move16();
809 :
810 1873160 : targetEne = 0;
811 1873160 : move32();
812 :
813 : /* Loop over all the bins in the band */
814 29416200 : FOR( binIdx = start; binIdx < stop; binIdx++ )
815 : {
816 27543040 : tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), sig[0][binIdx] );
817 27543040 : dmxSignalReal[binIdx] = L_add( dmxSignalReal[binIdx], tmpDMXSig );
818 27543040 : move32();
819 27543040 : targetEne = L_add( targetEne, Mpy_32_32( tmpDMXSig, tmpDMXSig ) );
820 :
821 27543040 : tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), mdst[binIdx] );
822 27543040 : dmxSignalImag[binIdx] = L_add( dmxSignalImag[binIdx], tmpDMXSig );
823 27543040 : move32();
824 27543040 : targetEne = L_add( targetEne, Mpy_32_32( tmpDMXSig, tmpDMXSig ) );
825 : }
826 1873160 : targetEnergy[bandIdx] = L_add( targetEnergy[bandIdx], targetEne );
827 1873160 : move32();
828 : } /* end of band loop */
829 : }
830 : }
831 : } /* end of chInIdx loop */
832 :
833 3342688 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
834 : {
835 : Word32 tmpReal, tmpImag, DMXEne;
836 : Word16 DMXEne_exp;
837 :
838 3292040 : start = hLsSetUpConversion->sfbOffset[bandIdx];
839 3292040 : move16();
840 3292040 : stop = hLsSetUpConversion->sfbOffset[bandIdx + 1];
841 3292040 : move16();
842 :
843 : /* Loop over all the bins in the band */
844 3292040 : DMXEne = 0;
845 3292040 : move32();
846 3292040 : DMXEne_exp = 0;
847 3292040 : move16();
848 51888520 : FOR( binIdx = start; binIdx < stop; binIdx++ )
849 : {
850 48596480 : tmpReal = dmxSignalReal[binIdx];
851 48596480 : move32();
852 48596480 : tmpImag = dmxSignalImag[binIdx];
853 48596480 : move32();
854 :
855 48596480 : DMXEne = BASOP_Util_Add_Mant32Exp( DMXEne, DMXEne_exp, L_add( Mpy_32_32( tmpReal, tmpReal ), Mpy_32_32( tmpImag, tmpImag ) ), sub( 40, shl( q_output, 1 ) ), &DMXEne_exp );
856 : }
857 3292040 : dmxEnergy[bandIdx] = BASOP_Util_Add_Mant32Exp( dmxEnergy[bandIdx], dmxEnergy_exp[bandIdx], DMXEne, DMXEne_exp, &dmxEnergy_exp[bandIdx] );
858 3292040 : move32();
859 3292040 : dmxEnergy_exp_temp = s_max( dmxEnergy_exp_temp, dmxEnergy_exp[bandIdx] );
860 : }
861 : } /* end of out channel loop */
862 :
863 : /* Scaling to common exponent */
864 474792 : FOR( bandIdx = 0; bandIdx < MAX_SFB + 2; bandIdx++ )
865 : {
866 468288 : dmxEnergy[bandIdx] = L_shl( dmxEnergy[bandIdx], sub( dmxEnergy_exp[bandIdx], dmxEnergy_exp_temp ) );
867 468288 : move32();
868 : }
869 : /* Step 3: Peform energy smoothing */
870 :
871 6504 : Word16 te_scale = getScaleFactor32( hLsSetUpConversion->targetEnergyPrev_fx[0], hLsSetUpConversion->sfbCnt );
872 6504 : scale_sig32( hLsSetUpConversion->targetEnergyPrev_fx[0], hLsSetUpConversion->sfbCnt, te_scale );
873 6504 : Word16 dmx_sacle = getScaleFactor32( hLsSetUpConversion->dmxEnergyPrev_fx[0], hLsSetUpConversion->sfbCnt );
874 6504 : scale_sig32( hLsSetUpConversion->dmxEnergyPrev_fx[0], hLsSetUpConversion->sfbCnt, dmx_sacle );
875 :
876 6504 : Word16 te_max_e = s_max( sub( 40, shl( q_output, 1 ) ), sub( hLsSetUpConversion->te_prev_exp[0], te_scale ) );
877 6504 : Word16 dmx_max_e = s_max( dmxEnergy_exp_temp, sub( hLsSetUpConversion->dmx_prev_exp[0], dmx_sacle ) );
878 :
879 429224 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
880 : {
881 422720 : targetEnergy[bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, L_shr( targetEnergy[bandIdx], sub( te_max_e, sub( 40, shl( q_output, 1 ) ) ) ) ), Mpy_32_32( ( ONE_IN_Q31 - LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), L_shr( hLsSetUpConversion->targetEnergyPrev_fx[0][bandIdx], sub( te_max_e, sub( hLsSetUpConversion->te_prev_exp[0], te_scale ) ) ) ) );
882 422720 : move32();
883 422720 : dmxEnergy[bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, L_shr( dmxEnergy[bandIdx], sub( dmx_max_e, dmxEnergy_exp_temp ) ) ), Mpy_32_32( ( ONE_IN_Q31 - LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), L_shr( hLsSetUpConversion->dmxEnergyPrev_fx[0][bandIdx], sub( dmx_max_e, sub( hLsSetUpConversion->dmx_prev_exp[0], dmx_sacle ) ) ) ) );
884 422720 : move32();
885 422720 : hLsSetUpConversion->targetEnergyPrev_fx[0][bandIdx] = targetEnergy[bandIdx]; /* te_prev_exp = 40 - 2*q_output */
886 422720 : move32();
887 422720 : hLsSetUpConversion->dmxEnergyPrev_fx[0][bandIdx] = dmxEnergy[bandIdx]; /* dmx_prev_exp = 40 - 2*q_output */
888 422720 : move32();
889 : }
890 :
891 6504 : hLsSetUpConversion->te_prev_exp[0] = te_max_e; /* te_prev_exp = 40 - 2*q_output */
892 6504 : move16();
893 6504 : hLsSetUpConversion->dmx_prev_exp[0] = dmx_max_e; /* dmx_prev_exp = 40 - 2*q_output */
894 6504 : move16();
895 :
896 45728 : FOR( i = 0; i < inChannels; ++i )
897 : {
898 37694264 : FOR( j = 0; j < L_FRAME48k; ++j )
899 : {
900 37655040 : output[i][j] = L_shr( output[i][j], q_output );
901 37655040 : move32();
902 : }
903 : }
904 :
905 : /* Step 4: Perform equalization */
906 45728 : FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ )
907 : {
908 39224 : test();
909 39224 : IF(
910 : NE_16( chInIdx, LFE_CHANNEL ) &&
911 : NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) )
912 : {
913 25825 : IF( EQ_16( transform_type[chInIdx][0], TCX_20 ) )
914 : {
915 : /* TCX20 */
916 1671980 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
917 : {
918 1646642 : start = hLsSetUpConversion->sfbOffset[bandIdx];
919 1646642 : move16();
920 1646642 : stop = hLsSetUpConversion->sfbOffset[bandIdx + 1];
921 1646642 : move16();
922 :
923 : /* Compute Eq gains */
924 1646642 : ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy[bandIdx], hLsSetUpConversion->te_prev_exp[0], &dmxEnergy[bandIdx], hLsSetUpConversion->dmx_prev_exp[0], &eqGain ); // Q(eqGain) = 30
925 25866162 : FOR( binIdx = start; binIdx < stop; binIdx++ )
926 : {
927 24219520 : x[chInIdx][0][binIdx] = Mpy_32_32( L_shl( x[chInIdx][0][binIdx], 1 ), eqGain ); // Q - 1
928 24219520 : move32();
929 : }
930 : }
931 : }
932 : ELSE
933 : {
934 487 : stop_tcx5 = 0;
935 487 : move16();
936 32110 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
937 : {
938 31623 : start = shr( hLsSetUpConversion->sfbOffset[bandIdx], 1 );
939 31623 : move16();
940 31623 : stop = shr( hLsSetUpConversion->sfbOffset[bandIdx + 1], 1 );
941 31623 : move16();
942 :
943 : /* Compute Eq gains */
944 31623 : ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy[bandIdx], hLsSetUpConversion->te_prev_exp[0], &dmxEnergy[bandIdx], hLsSetUpConversion->dmx_prev_exp[0], &eqGain );
945 :
946 94869 : FOR( subFrameIdx = 0; subFrameIdx < NB_DIV; subFrameIdx++ )
947 : {
948 63246 : IF( EQ_16( transform_type[chInIdx][subFrameIdx], TCX_10 ) )
949 : {
950 : /* TCX10 */
951 246093 : FOR( binIdx = start; binIdx < stop; binIdx++ )
952 : {
953 216160 : x[chInIdx][subFrameIdx][binIdx] = Mpy_32_32( L_shl( x[chInIdx][subFrameIdx][binIdx], 1 ), eqGain );
954 216160 : move32();
955 : }
956 : }
957 : ELSE
958 : {
959 : /* TCX5*/
960 33313 : start_tcx5 = stop_tcx5;
961 33313 : move16();
962 33313 : stop_tcx5 = shr( add( stop, 1 ), 1 );
963 :
964 147633 : FOR( binIdx = start_tcx5; binIdx < stop_tcx5; binIdx++ )
965 : {
966 114320 : x[chInIdx][subFrameIdx][binIdx] = Mpy_32_32( L_shl( x[chInIdx][subFrameIdx][binIdx], 1 ), eqGain );
967 114320 : move32();
968 114320 : x[chInIdx][subFrameIdx][binIdx + ( frameSize >> 2 )] = Mpy_32_32( L_shl( x[chInIdx][subFrameIdx][binIdx + ( frameSize >> 2 )], 1 ), eqGain );
969 114320 : move32();
970 : }
971 : }
972 : }
973 : }
974 : }
975 : }
976 : }
977 :
978 6504 : pop_wmops();
979 6504 : return;
980 : }
981 :
982 :
983 : /*-------------------------------------------------------------------------
984 : * ivas_ls_setup_conversion_process_mdct_param_mc()
985 : *
986 : * Equalization in MDCT Domain
987 : *-------------------------------------------------------------------------*/
988 :
989 20 : void ivas_ls_setup_conversion_process_mdct_param_mc_fx(
990 : Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */
991 : Word32 *x_fx[][NB_DIV],
992 : Word16 x_e[CPE_CHANNELS][NB_DIV] /* i/o: Exponent for output synthesis signal */
993 : )
994 : {
995 : Word32 targetEnergy_fx[MAX_SFB + 2], dmxEnergy_fx[MAX_SFB + 2];
996 : Word32 eqGain_fx;
997 : Word32 *sig_fx[MAX_CICP_CHANNELS][NB_DIV], *pTmp_fx[NB_DIV];
998 : Word32 mdst_fx[MAX_CICP_CHANNELS][L_FRAME48k];
999 : Word32 convertRes_fx[MAX_CICP_CHANNELS][L_FRAME48k];
1000 : Word32 cx_fx[PARAM_MC_MAX_PARAMETER_BANDS][PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS];
1001 : Word32 cx_imag_fx[PARAM_MC_MAX_PARAMETER_BANDS][PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS];
1002 : Word32 cy_fx[MAX_CICP_CHANNELS * MAX_CICP_CHANNELS];
1003 : Word32 real_in_buffer_fx[PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * PARAM_MC_BAND_TO_MDCT_BAND_RATIO * MAX_TRANSPORT_CHANNELS];
1004 : Word32 imag_in_buffer_fx[PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * PARAM_MC_BAND_TO_MDCT_BAND_RATIO * MAX_TRANSPORT_CHANNELS];
1005 : Word32 real_buffer_fx[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS];
1006 : Word32 imag_buffer_fx[PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS];
1007 : Word32 Nrqq_fx[MAX_OUTPUT_CHANNELS];
1008 : Word32 target_ch_ener_fx[MAX_OUTPUT_CHANNELS];
1009 : Word16 *ild_q_fx;
1010 :
1011 : Word32 DMXEne_fx;
1012 : Word32 dmxCoeff_fx;
1013 : Word32 dmxSignalReal_fx[L_FRAME48k], dmxSignalImag_fx[L_FRAME48k];
1014 :
1015 : Word32 tmpReal_fx, tmpImag_fx;
1016 : Word32 tmpDMXSig_fx;
1017 :
1018 : /* Declaration of all required variables */
1019 : Word16 i;
1020 : Word16 idx;
1021 : Word16 nchan_transport, nchan_out, nchan_transport_format;
1022 : Word16 chInIdx, chOutIdx, cpe_idx, subFrameIdx, binIdx;
1023 : Word16 band, bandIdx, num_bands;
1024 :
1025 : Word16 num_CPE;
1026 : Word16 transform_type[MAX_CICP_CHANNELS][2];
1027 : Word16 frameSize;
1028 :
1029 : Word16 start, stop, start_tcx5, stop_tcx5;
1030 : Word16 mct_chan_mode[MAX_CICP_CHANNELS];
1031 :
1032 : /* Declare all handles */
1033 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion;
1034 : CPE_DEC_HANDLE hCPE[MCT_MAX_BLOCKS];
1035 : PARAM_MC_DEC_HANDLE hParamMC;
1036 :
1037 : /* Step 0: Set the buffers to zero */
1038 20 : set_zero_fx( dmxSignalReal_fx, L_FRAME48k );
1039 20 : set_zero_fx( dmxSignalImag_fx, L_FRAME48k );
1040 :
1041 : /* Assign all the declared variables */
1042 20 : nchan_transport = st_ivas->nchan_transport;
1043 20 : nchan_out = st_ivas->hDecoderConfig->nchan_out;
1044 20 : num_CPE = st_ivas->nCPE;
1045 20 : nchan_transport_format = add( st_ivas->hTransSetup.nchan_out_woLFE, st_ivas->hTransSetup.num_lfe );
1046 20 : hLsSetUpConversion = st_ivas->hLsSetUpConversion;
1047 : /* Assign all the declared handles*/
1048 60 : FOR( cpe_idx = 0; cpe_idx < num_CPE; cpe_idx++ )
1049 : {
1050 40 : hCPE[cpe_idx] = st_ivas->hCPE[cpe_idx];
1051 : }
1052 20 : hParamMC = st_ivas->hParamMC;
1053 :
1054 : /* Get the core type */
1055 60 : FOR( cpe_idx = 0; cpe_idx < num_CPE; cpe_idx++ )
1056 : {
1057 120 : FOR( idx = 0; idx < CPE_CHANNELS; idx++ )
1058 : {
1059 : /* get the channel index */
1060 80 : chInIdx = add( cpe_idx * CPE_CHANNELS, idx );
1061 80 : assert( chInIdx <= nchan_transport );
1062 80 : transform_type[chInIdx][0] = hCPE[cpe_idx]->hCoreCoder[idx]->transform_type[0];
1063 80 : move16();
1064 80 : transform_type[chInIdx][1] = hCPE[cpe_idx]->hCoreCoder[idx]->transform_type[1];
1065 80 : move16();
1066 80 : mct_chan_mode[chInIdx] = hCPE[cpe_idx]->hCoreCoder[idx]->mct_chan_mode;
1067 80 : move16();
1068 : }
1069 : }
1070 :
1071 : /* set overall frequency resolution of (sub)frame to maximum of (sub)frame, requires conversion if both channels are not the same */
1072 20 : frameSize = hLsSetUpConversion->sfbOffset[hLsSetUpConversion->sfbCnt];
1073 20 : move16();
1074 20 : set_zero_fx( targetEnergy_fx, MAX_SFB + 2 );
1075 20 : set_zero_fx( dmxEnergy_fx, MAX_SFB + 2 );
1076 :
1077 80 : FOR( chInIdx = 0; chInIdx < nchan_transport; chInIdx++ )
1078 : {
1079 60 : IF( NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) )
1080 : {
1081 : /* initially, set pointers to input; if conversion occurs in (sub)frame, set to convertRes */
1082 60 : sig_fx[chInIdx][0] = pTmp_fx[0] = x_fx[chInIdx][0]; /*Q=31-x_e[chInIdx][0]*/
1083 60 : sig_fx[chInIdx][1] = pTmp_fx[1] = x_fx[chInIdx][1]; /*Q=31-x_e[chInIdx][1]*/
1084 : /* convert (sub)frames to higher frequency resolution */
1085 60 : IF( NE_16( transform_type[chInIdx][0], TCX_20 ) )
1086 : {
1087 21 : FOR( subFrameIdx = 0; subFrameIdx < NB_DIV; subFrameIdx++ )
1088 : {
1089 14 : IF( EQ_16( transform_type[chInIdx][subFrameIdx], TCX_5 ) )
1090 : {
1091 : /* subframe is TCX5, but TCX10 or TCX20 in other channel -> convert channel with TCX5 to TCX10 resolution */
1092 7 : pTmp_fx[subFrameIdx] = sig_fx[chInIdx][subFrameIdx] = convertRes_fx[chInIdx] + L_mult0( subFrameIdx, frameSize ) / 2;
1093 7 : convert_coeffs_to_higher_res_fx( x_fx[chInIdx][subFrameIdx], x_fx[chInIdx][subFrameIdx] + frameSize / 4, pTmp_fx[subFrameIdx], frameSize / 4 ); /*Q=31-x_e[chInIdx][subFrameIdx]*/
1094 : }
1095 : }
1096 :
1097 : /* convert channel with TCX10 to TCX20 resolution */
1098 7 : sig_fx[chInIdx][0] = convertRes_fx[chInIdx];
1099 :
1100 : // Scale_sig32(pTmp_fx_1_0, frameSize / 2, x_e[chInIdx][1] - x_e[chInIdx][0] ); /*Scaling down the Q from 31-x_e[chInIdx][1] to 31-x_e[chInIdx][0]*/
1101 7 : convert_coeffs_to_higher_res_fx( pTmp_fx[0], pTmp_fx[1], sig_fx[chInIdx][0], frameSize / 2 ); /*Q=31-x_e[chInIdx][0]*/
1102 : }
1103 : }
1104 : }
1105 20 : Word16 input_exp, output_exp = 0;
1106 20 : move16();
1107 :
1108 : /* precalculate MDST estimate */
1109 80 : FOR( chInIdx = 0; chInIdx < nchan_transport; chInIdx++ )
1110 : {
1111 60 : IF( NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) )
1112 : {
1113 60 : mdst_fx[chInIdx][0] = mdst_fx[chInIdx][frameSize - 1] = 0;
1114 60 : move32();
1115 38340 : FOR( i = 1; i < frameSize - 1; i++ )
1116 : {
1117 38280 : mdst_fx[chInIdx][i] = L_sub( sig_fx[chInIdx][0][i + 1], sig_fx[chInIdx][0][i - 1] ); /*Q=31-x_e[chInIdx][0]*/
1118 38280 : move32();
1119 : }
1120 : }
1121 : }
1122 :
1123 : /* Step 1.1, calculate Cx from MDST estimate */
1124 420 : FOR( bandIdx = 0; bandIdx < PARAM_MC_MAX_PARAMETER_BANDS; bandIdx++ )
1125 : {
1126 400 : set_zero_fx( cx_fx[bandIdx], PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS );
1127 400 : set_zero_fx( cx_imag_fx[bandIdx], PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS );
1128 : }
1129 20 : set_zero_fx( Nrqq_fx, MAX_OUTPUT_CHANNELS );
1130 20 : set_zero_fx( target_ch_ener_fx, MAX_OUTPUT_CHANNELS );
1131 20 : Word16 max_e = 0;
1132 20 : move16();
1133 80 : FOR( idx = 0; idx < nchan_transport; idx++ )
1134 : {
1135 60 : IF( NE_16( mct_chan_mode[idx], MCT_CHAN_MODE_IGNORE ) )
1136 : {
1137 60 : max_e = s_max( max_e, x_e[idx][0] );
1138 : }
1139 : }
1140 280 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1141 : {
1142 260 : set_zero_fx( real_in_buffer_fx, PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * PARAM_MC_BAND_TO_MDCT_BAND_RATIO * MAX_TRANSPORT_CHANNELS );
1143 260 : set_zero_fx( imag_in_buffer_fx, PARAM_MC_MAX_BANDS_IN_PARAMETER_BAND * PARAM_MC_BAND_TO_MDCT_BAND_RATIO * MAX_TRANSPORT_CHANNELS );
1144 260 : set_zero_fx( real_buffer_fx, PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS );
1145 260 : set_zero_fx( imag_buffer_fx, PARAM_MC_MAX_TRANSPORT_CHANS * PARAM_MC_MAX_TRANSPORT_CHANS );
1146 :
1147 260 : start = hLsSetUpConversion->sfbOffset[bandIdx];
1148 260 : move16();
1149 260 : stop = hLsSetUpConversion->sfbOffset[bandIdx + 1];
1150 260 : move16();
1151 260 : num_bands = sub( stop, start );
1152 :
1153 13060 : FOR( i = 0; i < num_bands; i++ )
1154 : {
1155 12800 : band = add( start, i );
1156 51200 : FOR( idx = 0; idx < nchan_transport; idx++ )
1157 : {
1158 38400 : IF( NE_16( mct_chan_mode[idx], MCT_CHAN_MODE_IGNORE ) )
1159 : {
1160 38400 : real_in_buffer_fx[i + ( num_bands * idx )] = L_shr( sig_fx[idx][0][band], sub( max_e, x_e[idx][0] ) ); /*Setting the exponent to max_e*/
1161 38400 : imag_in_buffer_fx[i + ( num_bands * idx )] = L_shr( mdst_fx[idx][band], sub( max_e, x_e[idx][0] ) ); /*Setting the exponent to max_e*/
1162 38400 : move32();
1163 38400 : move32();
1164 : }
1165 : }
1166 : }
1167 260 : Word16 shift = 1;
1168 260 : move16();
1169 38660 : FOR( i = 0; i < num_bands * nchan_transport; ++i )
1170 : {
1171 38400 : real_in_buffer_fx[i] = L_shr( real_in_buffer_fx[i], shift );
1172 38400 : move32();
1173 38400 : imag_in_buffer_fx[i] = L_shr( imag_in_buffer_fx[i], shift );
1174 38400 : move32();
1175 : }
1176 260 : input_exp = max_e;
1177 260 : move16();
1178 260 : input_exp = add( input_exp, shift );
1179 260 : cmplx_matrix_square_fx( real_in_buffer_fx, imag_in_buffer_fx, num_bands, nchan_transport, real_buffer_fx, imag_buffer_fx, input_exp, &output_exp );
1180 260 : v_add_32( cx_fx[bandIdx], real_buffer_fx, cx_fx[bandIdx], i_mult( nchan_transport, nchan_transport ) ); /*Q=Q_real_buffer=Q_imag_buffer=output_exp*/
1181 260 : v_add_32( cx_imag_fx[bandIdx], imag_buffer_fx, cx_imag_fx[bandIdx], i_mult( nchan_transport, nchan_transport ) ); /*Q=Q_real_buffer=Q_imag_buffer=output_exp*/
1182 : }
1183 20 : Word16 exp_in = 10, exp_out = 0;
1184 20 : move16();
1185 20 : move16();
1186 280 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1187 : {
1188 260 : DMXEne_fx = 0;
1189 260 : move16();
1190 260 : set_zero_fx( cy_fx, MAX_CICP_CHANNELS * MAX_CICP_CHANNELS );
1191 260 : set_zero_fx( Nrqq_fx, MAX_OUTPUT_CHANNELS );
1192 260 : set_zero_fx( target_ch_ener_fx, MAX_OUTPUT_CHANNELS );
1193 : /* Step 1.2, get target channel energies for the transported format as in ivas_param_mc_get_mono_stereo_mixing_matrices(), Nrqq calculation */
1194 260 : ild_q_fx = hParamMC->icld_q_fx + imult1616( bandIdx, hParamMC->hMetadataPMC->ild_mapping_conf->ild_map_size_lfe );
1195 260 : move16();
1196 3380 : FOR( chInIdx = 0; chInIdx < nchan_transport_format; chInIdx++ )
1197 : {
1198 3120 : Word32 ref_ener_fx = 0;
1199 3120 : move32();
1200 : Word16 ref_channel_cnt;
1201 : Word16 ref_channel_idx;
1202 :
1203 6240 : FOR( ref_channel_cnt = 0; ref_channel_cnt < hParamMC->hMetadataPMC->ild_mapping_conf->num_ref_channels[chInIdx]; ref_channel_cnt++ )
1204 : {
1205 3120 : ref_channel_idx = hParamMC->hMetadataPMC->ild_mapping_conf->ref_channel_idx[chInIdx][ref_channel_cnt];
1206 3120 : move16();
1207 3120 : ref_ener_fx = L_add( ref_ener_fx, cx_fx[bandIdx][ref_channel_idx + ( ref_channel_idx * nchan_transport )] ); /*Exponent=output_exp*/
1208 : }
1209 : Word32 temp;
1210 3120 : temp = BASOP_util_Pow2( L_mult0( ild_q_fx[chInIdx], 2721 /*log2(10)*(2^13)/10*/ ), exp_in, &exp_out );
1211 3120 : Nrqq_fx[hParamMC->hMetadataPMC->ild_mapping_conf->ild_index[chInIdx]] = L_shr( Mpy_32_16_1( ref_ener_fx, extract_l( Mpy_32_32( temp, hParamMC->hMetadataPMC->ild_factors_fx[chInIdx] ) ) ), sub( 2, exp_out ) ); /*exp=output_exp*/
1212 3120 : move32();
1213 : }
1214 :
1215 : /* Step 1.3 get target Cy like in ivas_param_mc_get_mono_stereo_mixing_matrices() (with dmx matrix from CICPX to MONO/STEREO saved in hParamMC) */
1216 780 : FOR( chOutIdx = 0; chOutIdx < nchan_out; chOutIdx++ )
1217 : {
1218 6760 : FOR( i = 0; i < nchan_transport_format; i++ )
1219 : {
1220 6240 : target_ch_ener_fx[chOutIdx] = L_add( target_ch_ener_fx[chOutIdx], L_shl( Mpy_32_32( Nrqq_fx[i], hParamMC->ls_conv_dmx_matrix_fx[chOutIdx + ( i * nchan_out )] ), 1 ) ); /*output_exp + 2*/
1221 6240 : move32();
1222 : }
1223 520 : cy_fx[chOutIdx + ( nchan_out * chOutIdx )] = target_ch_ener_fx[chOutIdx];
1224 520 : move32();
1225 : }
1226 :
1227 : /* Step 1.4 final target energy for the band would then be the sum over the diagonal of Cy*/
1228 780 : FOR( chOutIdx = 0; chOutIdx < nchan_out; chOutIdx++ )
1229 : {
1230 520 : targetEnergy_fx[bandIdx] = L_add( targetEnergy_fx[bandIdx], cy_fx[chOutIdx + ( nchan_out * chOutIdx )] ); /*exp=output_exp+2*/
1231 520 : move32();
1232 : }
1233 :
1234 : /* Step 2: Calculate DMX ener */
1235 260 : start = hLsSetUpConversion->sfbOffset[bandIdx];
1236 260 : move16();
1237 260 : stop = hLsSetUpConversion->sfbOffset[bandIdx + 1];
1238 260 : move16();
1239 :
1240 780 : FOR( chOutIdx = 0; chOutIdx < nchan_out; chOutIdx++ )
1241 : {
1242 2080 : FOR( chInIdx = 0; chInIdx < nchan_transport; chInIdx++ )
1243 : {
1244 1560 : IF( mct_chan_mode[chInIdx] != MCT_CHAN_MODE_IGNORE )
1245 : {
1246 1560 : dmxCoeff_fx = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx];
1247 :
1248 : /* Step 1: Compute the target energy and DMX signal (possible since we have all signals in TCX20 resolution) */
1249 1560 : IF( dmxCoeff_fx )
1250 : {
1251 : /* Loop over all the bins in the band */
1252 52240 : FOR( binIdx = start; binIdx < stop; binIdx++ )
1253 : {
1254 51200 : tmpDMXSig_fx = Mult_32_32( dmxCoeff_fx, L_shr( sig_fx[chInIdx][0][binIdx], sub( max_e, x_e[chInIdx][0] ) ) ); /*max_e+1*/
1255 51200 : dmxSignalReal_fx[binIdx] = L_add( dmxSignalReal_fx[binIdx], tmpDMXSig_fx );
1256 51200 : move32();
1257 :
1258 51200 : tmpDMXSig_fx = Mult_32_32( dmxCoeff_fx, L_shr( mdst_fx[chInIdx][binIdx], sub( max_e, x_e[chInIdx][0] ) ) ); /*max_e+1*/
1259 51200 : dmxSignalImag_fx[binIdx] = L_add( dmxSignalImag_fx[binIdx], tmpDMXSig_fx );
1260 51200 : move32();
1261 : }
1262 : }
1263 : }
1264 : }
1265 : /* Loop over all the bins in the band */
1266 520 : DMXEne_fx = 0;
1267 520 : move32();
1268 26120 : FOR( binIdx = start; binIdx < stop; binIdx++ )
1269 : {
1270 25600 : tmpReal_fx = L_shr( dmxSignalReal_fx[binIdx], 1 );
1271 25600 : tmpImag_fx = L_shr( dmxSignalImag_fx[binIdx], 1 );
1272 :
1273 25600 : DMXEne_fx = L_add( DMXEne_fx, Mult_32_32( tmpReal_fx, tmpReal_fx ) + Mult_32_32( tmpImag_fx, tmpImag_fx ) ); /*2*(max_e + 2)*/
1274 : }
1275 : }
1276 :
1277 260 : dmxEnergy_fx[bandIdx] = DMXEne_fx; /*2*(max_e+2)*/
1278 260 : move32();
1279 : }
1280 :
1281 : /* Step 3: Peform energy smoothing */
1282 280 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1283 : {
1284 260 : targetEnergy_fx[bandIdx] = L_add( Mult_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, targetEnergy_fx[bandIdx] ), Mult_32_32( L_sub( MAX_32, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), L_shr( hLsSetUpConversion->targetEnergyPrev_fx[0][bandIdx], add( output_exp, sub( 2, hLsSetUpConversion->te_prev_exp[0] ) ) ) ) ); /*output_exp + 2*/
1285 260 : move32();
1286 260 : dmxEnergy_fx[bandIdx] = L_add( Mult_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, dmxEnergy_fx[bandIdx] ), Mult_32_32( L_sub( MAX_32, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), L_shr( hLsSetUpConversion->dmxEnergyPrev_fx[0][bandIdx], sub( shl( add( max_e, 2 ), 1 ), hLsSetUpConversion->dmx_prev_exp[0] ) ) ) ); /*2 * (max_e + 2)*/
1287 260 : move32();
1288 260 : hLsSetUpConversion->targetEnergyPrev_fx[0][bandIdx] = targetEnergy_fx[bandIdx];
1289 260 : move32();
1290 260 : hLsSetUpConversion->dmxEnergyPrev_fx[0][bandIdx] = dmxEnergy_fx[bandIdx];
1291 260 : move32();
1292 : }
1293 20 : hLsSetUpConversion->te_prev_exp[0] = add( output_exp, 2 );
1294 20 : move16();
1295 20 : hLsSetUpConversion->dmx_prev_exp[0] = shl( add( max_e, 2 ), 1 );
1296 20 : move16();
1297 : /* Step 4: Perform equalization */
1298 80 : FOR( chInIdx = 0; chInIdx < nchan_transport; chInIdx++ )
1299 : {
1300 60 : IF( NE_16( mct_chan_mode[chInIdx], MCT_CHAN_MODE_IGNORE ) )
1301 : {
1302 60 : IF( EQ_16( transform_type[chInIdx][0], TCX_20 ) )
1303 : {
1304 : /*TCX20*/
1305 742 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1306 : {
1307 689 : start = hLsSetUpConversion->sfbOffset[bandIdx];
1308 689 : move16();
1309 689 : stop = hLsSetUpConversion->sfbOffset[bandIdx + 1];
1310 689 : move16();
1311 :
1312 : /*Compute Eq gains */
1313 689 : ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy_fx[bandIdx], hLsSetUpConversion->te_prev_exp[0], &dmxEnergy_fx[bandIdx], hLsSetUpConversion->dmx_prev_exp[0], &eqGain_fx );
1314 :
1315 34609 : FOR( binIdx = start; binIdx < stop; binIdx++ )
1316 : {
1317 33920 : x_fx[chInIdx][0][binIdx] = L_shl( Mult_32_32( x_fx[chInIdx][0][binIdx], eqGain_fx ), 1 );
1318 : }
1319 : }
1320 : }
1321 : ELSE
1322 : {
1323 7 : stop_tcx5 = 0;
1324 7 : move16();
1325 98 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1326 : {
1327 91 : start = shr( hLsSetUpConversion->sfbOffset[bandIdx], 1 );
1328 91 : stop = shr( hLsSetUpConversion->sfbOffset[bandIdx + 1], 1 );
1329 :
1330 : /*Compute Eq gains */
1331 91 : ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy_fx[bandIdx], hLsSetUpConversion->te_prev_exp[0], &dmxEnergy_fx[bandIdx], hLsSetUpConversion->dmx_prev_exp[0], &eqGain_fx );
1332 :
1333 :
1334 273 : FOR( subFrameIdx = 0; subFrameIdx < NB_DIV; subFrameIdx++ )
1335 : {
1336 182 : IF( EQ_16( transform_type[chInIdx][subFrameIdx], TCX_10 ) )
1337 : {
1338 : /*TCX10*/
1339 2331 : FOR( binIdx = start; binIdx < stop; binIdx++ )
1340 : {
1341 2240 : x_fx[chInIdx][subFrameIdx][binIdx] = L_shl( Mult_32_32( x_fx[chInIdx][subFrameIdx][binIdx], eqGain_fx ), 1 );
1342 2240 : move32();
1343 : }
1344 : }
1345 : ELSE
1346 : {
1347 : /* TCX5*/
1348 91 : start_tcx5 = stop_tcx5;
1349 91 : move16();
1350 91 : stop_tcx5 = shr( add( stop, 1 ), 1 );
1351 1211 : FOR( binIdx = start_tcx5; binIdx < stop_tcx5; binIdx++ )
1352 : {
1353 1120 : x_fx[chInIdx][subFrameIdx][binIdx] = L_shl( Mult_32_32( x_fx[chInIdx][subFrameIdx][binIdx], eqGain_fx ), 1 );
1354 1120 : move32();
1355 : }
1356 :
1357 1211 : FOR( binIdx = start_tcx5; binIdx < stop_tcx5; binIdx++ )
1358 : {
1359 1120 : x_fx[chInIdx][subFrameIdx][binIdx + ( frameSize >> 2 )] = L_shl( Mult_32_32( x_fx[chInIdx][subFrameIdx][binIdx + ( frameSize >> 2 )], eqGain_fx ), 1 );
1360 1120 : move32();
1361 : }
1362 : }
1363 : }
1364 : }
1365 : }
1366 : }
1367 : }
1368 20 : return;
1369 : }
1370 :
1371 :
1372 : /*-------------------------------------------------------------------------
1373 : * ivas_ls_setup_conversion_process_param_mc()
1374 : *
1375 : * LS setup conversion in the CLDFB domain for Parametric MC
1376 : *-------------------------------------------------------------------------*/
1377 :
1378 1360 : void ivas_lssetupconversion_process_param_mc_fx(
1379 : Decoder_Struct *st_ivas, /* i/o: LS setup conversion renderer handle */
1380 : const Word16 num_timeslots,
1381 : Word32 Cldfb_RealBuffer_InOut[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i/o: LS signals Q6*/
1382 : Word32 Cldfb_ImagBuffer_InOut[MAX_CICP_CHANNELS][PARAM_MC_MAX_NSLOTS_IN_SUBFRAME][CLDFB_NO_CHANNELS_MAX], /* i/o: LS signals Q6*/
1383 : Word16 channel_active[MAX_CICP_CHANNELS] /* i : bitmap indicating which output channels are active */
1384 : )
1385 : {
1386 : Word16 slotIdx, chOutIdx, chInIdx, bandIdx;
1387 : Word16 inChannels, outChannels;
1388 : Word32 targetEnergy[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX];
1389 : Word32 dmxEnergy[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX];
1390 : Word32 tmpDMXSig, dmxCoeff, tmpReal, tmpImag;
1391 : Word32 EQ;
1392 : Word32 Cldfb_RealBuffer_tmp[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX];
1393 : Word32 Cldfb_ImagBuffer_tmp[MAX_CICP_CHANNELS][CLDFB_NO_CHANNELS_MAX];
1394 : LSSETUP_CONVERSION_HANDLE hLsSetUpConversion;
1395 : Word16 i, k;
1396 :
1397 1360 : push_wmops( "LS_Renderer_Process_Param_MC" );
1398 : /* inits */
1399 1360 : inChannels = add( st_ivas->hIntSetup.nchan_out_woLFE, st_ivas->hIntSetup.num_lfe );
1400 1360 : move16();
1401 1360 : outChannels = add( st_ivas->hOutSetup.nchan_out_woLFE, st_ivas->hOutSetup.num_lfe );
1402 1360 : move16();
1403 :
1404 1360 : hLsSetUpConversion = st_ivas->hLsSetUpConversion;
1405 1360 : EQ = 0;
1406 1360 : move32();
1407 :
1408 1360 : set16_fx( channel_active, 0, outChannels );
1409 :
1410 : /* Loop over each time slots and compute dmx for each time slot */
1411 6800 : FOR( slotIdx = 0; slotIdx < num_timeslots; slotIdx++ )
1412 : {
1413 : // Scale the array
1414 5440 : Word16 q_output = 31;
1415 38080 : FOR( i = 0; i < inChannels; ++i )
1416 : {
1417 32640 : q_output = s_min( q_output, L_norm_arr( Cldfb_RealBuffer_InOut[i][slotIdx], hLsSetUpConversion->sfbCnt ) );
1418 32640 : q_output = s_min( q_output, L_norm_arr( Cldfb_ImagBuffer_InOut[i][slotIdx], hLsSetUpConversion->sfbCnt ) );
1419 : }
1420 :
1421 5440 : Word16 guard_1 = find_guarded_bits_fx( inChannels );
1422 5440 : q_output = sub( q_output, guard_1 );
1423 :
1424 38080 : FOR( i = 0; i < inChannels; ++i )
1425 : {
1426 1991040 : FOR( k = 0; k < hLsSetUpConversion->sfbCnt; ++k )
1427 : {
1428 1958400 : Cldfb_RealBuffer_InOut[i][slotIdx][k] = L_shl( Cldfb_RealBuffer_InOut[i][slotIdx][k], q_output ); // Q(6 + q_output)
1429 1958400 : Cldfb_ImagBuffer_InOut[i][slotIdx][k] = L_shl( Cldfb_ImagBuffer_InOut[i][slotIdx][k], q_output ); // Q(6 + q_output)
1430 : }
1431 : }
1432 : /* copy buffers */
1433 38080 : FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ )
1434 : {
1435 32640 : Copy32( Cldfb_RealBuffer_InOut[chInIdx][slotIdx], Cldfb_RealBuffer_tmp[chInIdx], CLDFB_NO_CHANNELS_MAX ); // Q(6 + q_output)
1436 32640 : Copy32( Cldfb_ImagBuffer_InOut[chInIdx][slotIdx], Cldfb_ImagBuffer_tmp[chInIdx], CLDFB_NO_CHANNELS_MAX ); // Q(6 + q_output)
1437 : }
1438 : /* set the buffers to zero */
1439 70720 : FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ )
1440 : {
1441 65280 : set32_fx( Cldfb_RealBuffer_InOut[chOutIdx][slotIdx], 0, CLDFB_NO_CHANNELS_MAX );
1442 65280 : set32_fx( Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx], 0, CLDFB_NO_CHANNELS_MAX );
1443 :
1444 65280 : set32_fx( dmxEnergy[chOutIdx], 0, CLDFB_NO_CHANNELS_MAX );
1445 65280 : set32_fx( targetEnergy[chOutIdx], 0, CLDFB_NO_CHANNELS_MAX );
1446 : }
1447 :
1448 : /* Compute the target energy and DMX signal */
1449 70720 : FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ )
1450 : {
1451 456960 : FOR( chInIdx = 0; chInIdx < inChannels; chInIdx++ )
1452 : {
1453 391680 : dmxCoeff = hLsSetUpConversion->dmxMtx_fx[chInIdx][chOutIdx]; // Q30
1454 391680 : move32();
1455 391680 : IF( dmxCoeff == 0 )
1456 : {
1457 359040 : CONTINUE;
1458 : }
1459 : ELSE
1460 : {
1461 32640 : channel_active[chOutIdx] = s_or( 1, channel_active[chOutIdx] );
1462 32640 : move16();
1463 1991040 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1464 : {
1465 1958400 : tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), Cldfb_RealBuffer_tmp[chInIdx][bandIdx] ); // Q(6 + q_output)
1466 1958400 : Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx] = L_add( Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx], tmpDMXSig );
1467 1958400 : move32();
1468 1958400 : targetEnergy[chOutIdx][bandIdx] = L_add( targetEnergy[chOutIdx][bandIdx], Mpy_32_32( tmpDMXSig, tmpDMXSig ) ); // Q((6 + q_output)*2 - 31)
1469 1958400 : move32();
1470 :
1471 1958400 : tmpDMXSig = Mpy_32_32( L_shl_sat( dmxCoeff, 1 ), Cldfb_ImagBuffer_tmp[chInIdx][bandIdx] );
1472 1958400 : Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx] = L_add( Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx], tmpDMXSig );
1473 1958400 : move32();
1474 1958400 : targetEnergy[chOutIdx][bandIdx] = L_add( targetEnergy[chOutIdx][bandIdx], Mpy_32_32( tmpDMXSig, tmpDMXSig ) );
1475 1958400 : move32();
1476 : }
1477 : }
1478 : }
1479 : }
1480 :
1481 : /* Compute the DMX energy */
1482 70720 : FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ )
1483 : {
1484 65280 : IF( channel_active[chOutIdx] )
1485 : {
1486 1991040 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1487 : {
1488 1958400 : tmpReal = Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx]; // Q(6 + q_output)
1489 1958400 : move32();
1490 1958400 : tmpImag = Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx]; // Q(6 + q_output)
1491 1958400 : move32();
1492 :
1493 1958400 : dmxEnergy[chOutIdx][bandIdx] = L_add( Mpy_32_32( tmpReal, tmpReal ), Mpy_32_32( tmpImag, tmpImag ) ); // Q((6 + q_output)*2 - 31)
1494 1958400 : move32();
1495 : }
1496 : }
1497 : }
1498 :
1499 : /* Peform energy smoothing */
1500 70720 : FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ )
1501 : {
1502 65280 : IF( channel_active[chOutIdx] )
1503 : {
1504 32640 : Word16 te_scale = getScaleFactor32( hLsSetUpConversion->targetEnergyPrev_fx[chOutIdx], hLsSetUpConversion->sfbCnt );
1505 32640 : scale_sig32( hLsSetUpConversion->targetEnergyPrev_fx[chOutIdx], hLsSetUpConversion->sfbCnt, te_scale );
1506 32640 : Word16 dmx_sacle = getScaleFactor32( hLsSetUpConversion->dmxEnergyPrev_fx[chOutIdx], hLsSetUpConversion->sfbCnt );
1507 32640 : scale_sig32( hLsSetUpConversion->dmxEnergyPrev_fx[chOutIdx], hLsSetUpConversion->sfbCnt, dmx_sacle );
1508 :
1509 32640 : Word16 te_max_e = s_max( sub( 50, shl( q_output, 1 ) ), sub( hLsSetUpConversion->te_prev_exp[chOutIdx], te_scale ) );
1510 32640 : Word16 dmx_max_e = s_max( sub( 50, shl( q_output, 1 ) ), sub( hLsSetUpConversion->dmx_prev_exp[chOutIdx], dmx_sacle ) );
1511 :
1512 1991040 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1513 : {
1514 1958400 : targetEnergy[chOutIdx][bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, L_shr( targetEnergy[chOutIdx][bandIdx], sub( te_max_e, sub( 50, shl( q_output, 1 ) ) ) ) ), Mpy_32_32( L_sub( ONE_IN_Q31, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), L_shr( hLsSetUpConversion->targetEnergyPrev_fx[chOutIdx][bandIdx], sub( te_max_e, sub( hLsSetUpConversion->te_prev_exp[chOutIdx], te_scale ) ) ) ) );
1515 1958400 : move32();
1516 1958400 : dmxEnergy[chOutIdx][bandIdx] = L_add( Mpy_32_32( LS_OUT_CONV_SMOOTHING_FACTOR_Q31, L_shr( dmxEnergy[chOutIdx][bandIdx], sub( dmx_max_e, sub( 50, shl( q_output, 1 ) ) ) ) ), Mpy_32_32( L_sub( ONE_IN_Q31, LS_OUT_CONV_SMOOTHING_FACTOR_Q31 ), L_shr( hLsSetUpConversion->dmxEnergyPrev_fx[chOutIdx][bandIdx], sub( dmx_max_e, sub( hLsSetUpConversion->dmx_prev_exp[chOutIdx], dmx_sacle ) ) ) ) );
1517 1958400 : move32();
1518 1958400 : hLsSetUpConversion->targetEnergyPrev_fx[chOutIdx][bandIdx] = targetEnergy[chOutIdx][bandIdx]; // Q0
1519 1958400 : move32();
1520 1958400 : hLsSetUpConversion->dmxEnergyPrev_fx[chOutIdx][bandIdx] = dmxEnergy[chOutIdx][bandIdx]; // Q0
1521 1958400 : move32();
1522 : }
1523 :
1524 32640 : hLsSetUpConversion->te_prev_exp[chOutIdx] = te_max_e; /* te_prev_exp = 50 - 2*q_output */
1525 32640 : move16();
1526 32640 : hLsSetUpConversion->dmx_prev_exp[chOutIdx] = dmx_max_e; /* dmx_prev_exp = 50 - 2*q_output */
1527 32640 : move16();
1528 : }
1529 : }
1530 :
1531 70720 : FOR( i = 0; i < outChannels; ++i )
1532 : {
1533 3982080 : FOR( k = 0; k < hLsSetUpConversion->sfbCnt; ++k )
1534 : {
1535 3916800 : Cldfb_RealBuffer_InOut[i][slotIdx][k] = L_shr( Cldfb_RealBuffer_InOut[i][slotIdx][k], q_output ); // Q6
1536 3916800 : move32();
1537 3916800 : Cldfb_ImagBuffer_InOut[i][slotIdx][k] = L_shr( Cldfb_ImagBuffer_InOut[i][slotIdx][k], q_output ); // Q6
1538 3916800 : move32();
1539 : }
1540 : }
1541 :
1542 : /* Compute and perform equalization */
1543 70720 : FOR( chOutIdx = 0; chOutIdx < outChannels; chOutIdx++ )
1544 : {
1545 65280 : IF( channel_active[chOutIdx] )
1546 : {
1547 1991040 : FOR( bandIdx = 0; bandIdx < hLsSetUpConversion->sfbCnt; bandIdx++ )
1548 : {
1549 1958400 : ivas_lssetupconversion_computeEQFactor_fx( &targetEnergy[chOutIdx][bandIdx], hLsSetUpConversion->te_prev_exp[chOutIdx], &dmxEnergy[chOutIdx][bandIdx], hLsSetUpConversion->dmx_prev_exp[chOutIdx], &EQ ); // Q(EQ) = Q30
1550 1958400 : Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx] = Mpy_32_32( L_shl( Cldfb_RealBuffer_InOut[chOutIdx][slotIdx][bandIdx], 1 ), EQ );
1551 1958400 : move32();
1552 1958400 : Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx] = Mpy_32_32( L_shl( Cldfb_ImagBuffer_InOut[chOutIdx][slotIdx][bandIdx], 1 ), EQ );
1553 1958400 : move32();
1554 : }
1555 : }
1556 : }
1557 : }
1558 :
1559 1360 : pop_wmops();
1560 1360 : return;
1561 : }
|