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 : #include "basop_util.h"
33 : #include "options.h"
34 : #include "lib_rend.h"
35 : #include "prot_fx.h"
36 : #include "ivas_prot_fx.h"
37 : #include "ivas_prot_rend_fx.h"
38 : #include "ivas_cnst.h"
39 : #include "ivas_rom_com.h"
40 : #include "ivas_rom_com_fx.h"
41 : #include "ivas_rom_rend.h"
42 : #include <assert.h>
43 : #include <math.h>
44 : #include <stdbool.h>
45 : #include "wmc_auto.h"
46 : #ifdef DEBUGGING
47 : #include "debug.h"
48 : #endif
49 :
50 :
51 : /*-------------------------------------------------------------------*
52 : * Local constants
53 : *-------------------------------------------------------------------*/
54 :
55 : /* Maximum buffer length (per channel) in samples.
56 : * Keep this separate from L_FRAME48k in case we want to support different size later */
57 : #define MAX_BUFFER_LENGTH_PER_CHANNEL ( L_FRAME48k )
58 :
59 : /* Maximum buffer length (total) in samples. */
60 : /* Maximum buffer length (total) in samples. */
61 : #define MAX_BUFFER_LENGTH ( MAX_BUFFER_LENGTH_PER_CHANNEL * MAX_INPUT_CHANNELS )
62 :
63 : #define MAX_BIN_DELAY_SAMPLES 50 /* Maximum supported rendering latency for binaural IRs */
64 :
65 : /* Frame size required when rendering to binaural */
66 : #define BINAURAL_RENDERING_FRAME_SIZE_MS 5
67 :
68 :
69 : /*-------------------------------------------------------------------*
70 : * Local types
71 : *-------------------------------------------------------------------*/
72 :
73 : typedef float pan_vector[MAX_OUTPUT_CHANNELS];
74 : typedef float pan_matrix[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
75 : typedef float rotation_gains[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
76 : typedef Word32 pan_vector_fx[MAX_OUTPUT_CHANNELS];
77 : typedef Word32 pan_matrix_fx[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
78 : typedef Word16 rotation_gains_fx[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
79 : typedef Word32 rotation_gains_Word32[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
80 : typedef Word32 rotation_matrix_fx[3][3];
81 : typedef float rotation_matrix[3][3];
82 :
83 : /* EFAP wrapper to simplify writing panning gains to a vector that includes LFE channels */
84 : typedef struct
85 : {
86 : EFAP_HANDLE hEfap;
87 : AUDIO_CONFIG speakerConfig;
88 : const LSSETUP_CUSTOM_STRUCT *pCustomLsSetup; /* Pointer to main custom LS struct from renderer handle - doesn't need freeing */
89 : } EFAP_WRAPPER;
90 :
91 : /* Lightweight helper struct that gathers all information required for rendering
92 : * any config to any other config. Used to simplify signatures of rendering functions.
93 : *
94 : * This struct should store ONLY CONST POINTERS to data existing elsewhere.
95 : * Storing pointers instead of data itself ensures that no additional updates
96 : * are required when any of these are changed in the renderer. Making the pointers
97 : * const ensures that this data is only read, but not modified by the rendering functions. */
98 : typedef struct
99 : {
100 : const Word32 *pOutSampleRate;
101 : const AUDIO_CONFIG *pOutConfig;
102 : const LSSETUP_CUSTOM_STRUCT *pCustomLsOut;
103 : const EFAP_WRAPPER *pEfapOutWrapper;
104 : IVAS_REND_HeadRotData *pHeadRotData; // for now removing the const qualifier TODO: will modify later
105 : const COMBINED_ORIENTATION_HANDLE *pCombinedOrientationData;
106 : } rendering_context;
107 : /* Common base for input structs */
108 : typedef struct
109 : {
110 : AUDIO_CONFIG inConfig;
111 : IVAS_REND_InputId id;
112 : IVAS_REND_AudioBuffer inputBuffer;
113 : Word32 gain_fx; /* Linear, not in dB Q30 */
114 : rendering_context ctx;
115 : Word32 numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */
116 : } input_base;
117 : typedef struct
118 : {
119 : input_base base;
120 : IVAS_ISM_METADATA currentPos;
121 : IVAS_ISM_METADATA previousPos;
122 : TDREND_WRAPPER tdRendWrapper;
123 : CREND_WRAPPER_HANDLE crendWrapper;
124 : REVERB_HANDLE hReverb;
125 : rotation_matrix_fx rot_mat_prev;
126 : pan_vector_fx prev_pan_gains_fx;
127 : rotation_matrix_fx rot_mat_prev_fx;
128 : pan_vector prev_pan_gains;
129 : Word8 firstFrameRendered;
130 : Word32 *bufferData_fx;
131 : Word16 nonDiegeticPan;
132 : Word32 nonDiegeticPanGain_fx; /* Q31 */
133 : OMASA_ANA_HANDLE hOMasa;
134 : UWord16 total_num_objects;
135 : Word32 ism_metadata_delay_ms_fx; /* Q0 */
136 : } input_ism;
137 : typedef struct
138 : {
139 : Word16 numLfeChannels;
140 : bool pan_lfe;
141 : // float lfeInputGain;
142 : Word32 lfeInputGain_fx; /* Q31 */
143 : // float lfeOutputAzimuth;
144 : Word16 lfeOutputAzimuth_fx;
145 : // float lfeOutputElevation;
146 : Word16 lfeOutputElevation_fx;
147 : // IVAS_REND_LfePanMtx lfePanMtx;
148 : IVAS_REND_LfePanMtx_fx lfePanMtx_fx; /* Q31 */
149 : } lfe_routing;
150 : typedef struct
151 : {
152 : input_base base;
153 :
154 : /* Full panning matrix. 1st index is input channel, 2nd index is output channel.
155 : All LFE channels should be included, both for inputs and outputs */
156 : pan_matrix_fx panGains_fx; /* Q31 */
157 :
158 : LSSETUP_CUSTOM_STRUCT customLsInput;
159 : EFAP_WRAPPER efapInWrapper;
160 : TDREND_WRAPPER tdRendWrapper;
161 : CREND_WRAPPER_HANDLE crendWrapper;
162 : REVERB_HANDLE hReverb;
163 : rotation_gains_Word32 rot_gains_prev_fx;
164 : Word16 nonDiegeticPan;
165 : Word32 nonDiegeticPanGain_fx;
166 : lfe_routing lfeRouting;
167 : Word32 *bufferData_fx;
168 : Word16 binauralDelaySmp;
169 : Word32 *lfeDelayBuffer_fx;
170 : MCMASA_ANA_HANDLE hMcMasa;
171 : } input_mc;
172 : typedef struct
173 : {
174 : input_base base;
175 : // pan_matrix hoaDecMtx;
176 : pan_matrix_fx hoaDecMtx_fx;
177 : CREND_WRAPPER_HANDLE crendWrapper;
178 : rotation_gains_fx rot_gains_prev_fx;
179 : Word32 *bufferData_fx;
180 : DIRAC_ANA_HANDLE hDirAC;
181 : } input_sba;
182 :
183 :
184 : typedef struct
185 : {
186 : input_base base;
187 : MASA_METADATA_FRAME masaMetadata;
188 : bool metadataHasBeenFed;
189 : Word32 *bufferData_fx;
190 : MASA_EXT_REND_HANDLE hMasaExtRend;
191 : MASA_PREREND_HANDLE hMasaPrerend;
192 : } input_masa;
193 : struct IVAS_REND
194 : {
195 : Word32 sampleRateOut;
196 : IVAS_LIMITER_HANDLE hLimiter;
197 :
198 : input_ism inputsIsm[RENDERER_MAX_ISM_INPUTS];
199 : input_mc inputsMc[RENDERER_MAX_MC_INPUTS];
200 : input_sba inputsSba[RENDERER_MAX_SBA_INPUTS];
201 : input_masa inputsMasa[RENDERER_MAX_MASA_INPUTS];
202 :
203 : AUDIO_CONFIG inputConfig;
204 : AUDIO_CONFIG outputConfig;
205 : EFAP_WRAPPER efapOutWrapper;
206 : IVAS_LSSETUP_CUSTOM_STRUCT customLsOut;
207 :
208 : IVAS_REND_HeadRotData headRotData;
209 :
210 : EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData;
211 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData;
212 :
213 : Word8 rendererConfigEnabled;
214 : RENDER_CONFIG_DATA *hRendererConfig; /* Renderer config pointer */
215 :
216 : Word16 num_subframes;
217 : };
218 :
219 : /*-------------------------------------------------------------------*
220 : * Local function prototypes
221 : *-------------------------------------------------------------------*/
222 :
223 : static ivas_error initMasaExtRenderer( input_masa *inputMasa, const AUDIO_CONFIG outConfig );
224 : static void freeMasaExtRenderer( MASA_EXT_REND_HANDLE *hMasaExtRendOut );
225 : static void intermidiate_ext_dirac_render(
226 : MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure */
227 : Word16 to_fix );
228 : /*-------------------------------------------------------------------*
229 : * Local functions
230 : *-------------------------------------------------------------------*/
231 953 : static ivas_error allocateInputBaseBufferData_fx(
232 : Word32 **data, /* Qx */
233 : const Word16 data_size )
234 : {
235 953 : *data = (Word32 *) malloc( data_size * sizeof( Word32 ) );
236 953 : IF( *data == NULL )
237 : {
238 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for input base buffer data" );
239 : }
240 :
241 953 : return IVAS_ERR_OK;
242 : }
243 4606 : static void freeInputBaseBufferData_fx(
244 : Word32 **data /* Qx */ )
245 : {
246 4606 : IF( *data != NULL )
247 : {
248 953 : free( *data );
249 953 : *data = NULL;
250 : }
251 :
252 4606 : return;
253 : }
254 372 : static ivas_error allocateMcLfeDelayBuffer_fx(
255 : Word32 **lfeDelayBuffer, /* Qx */
256 : const Word16 data_size )
257 : {
258 372 : *lfeDelayBuffer = (Word32 *) malloc( data_size * sizeof( Word32 ) );
259 372 : IF( *lfeDelayBuffer == NULL )
260 : {
261 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" );
262 : }
263 :
264 372 : return IVAS_ERR_OK;
265 : }
266 658 : static void freeMcLfeDelayBuffer_fx(
267 : Word32 **lfeDelayBuffer /* Qx */ )
268 : {
269 658 : IF( *lfeDelayBuffer != NULL )
270 : {
271 372 : free( *lfeDelayBuffer );
272 372 : *lfeDelayBuffer = NULL;
273 : }
274 :
275 658 : return;
276 : }
277 :
278 :
279 1720 : static IVAS_QUATERNION quaternionInit_fx(
280 : void )
281 : {
282 : IVAS_QUATERNION q;
283 1720 : q.w_fx = ONE_IN_Q29;
284 1720 : move32();
285 1720 : q.x_fx = q.y_fx = q.z_fx = 0;
286 1720 : move32();
287 1720 : move32();
288 1720 : move32();
289 :
290 1720 : q.q_fact = Q29;
291 1720 : move16();
292 1720 : move16();
293 1720 : move16();
294 1720 : move16();
295 :
296 1720 : return q;
297 : }
298 :
299 221398105 : static Word32 *getSmplPtr_fx(
300 : IVAS_REND_AudioBuffer buffer,
301 : const UWord32 chnlIdx,
302 : const UWord32 smplIdx )
303 : {
304 221398105 : return buffer.data_fx + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx;
305 : }
306 645648 : static void copyBufferTo2dArray_fx(
307 : const IVAS_REND_AudioBuffer buffer,
308 : Word32 array[][L_FRAME48k] )
309 : {
310 : UWord32 smplIdx;
311 : UWord32 chnlIdx;
312 : const Word32 *readPtr;
313 :
314 645648 : readPtr = buffer.data_fx;
315 :
316 4639512 : FOR( chnlIdx = 0; chnlIdx < (UWord32) buffer.config.numChannels; ++chnlIdx )
317 : {
318 1539660264 : FOR( smplIdx = 0; smplIdx < (UWord32) buffer.config.numSamplesPerChannel; ++smplIdx )
319 : {
320 1535666400 : array[chnlIdx][smplIdx] = *readPtr++;
321 1535666400 : move32();
322 : }
323 : }
324 :
325 645648 : return;
326 : }
327 645648 : static void accumulate2dArrayToBuffer_fx(
328 : Word32 array[][L_FRAME48k],
329 : IVAS_REND_AudioBuffer *buffer )
330 : {
331 : Word16 smplIdx, chnlIdx;
332 : Word32 *writePtr;
333 :
334 645648 : writePtr = buffer->data_fx;
335 2020944 : FOR( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
336 : {
337 530200896 : FOR( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
338 : {
339 528825600 : *writePtr = L_add( *writePtr, array[chnlIdx][smplIdx] );
340 528825600 : move32();
341 528825600 : writePtr++;
342 : }
343 : }
344 :
345 645648 : return;
346 : }
347 : /*-------------------------------------------------------------------*
348 : * limitRendererOutput()
349 : *
350 : * In-place saturation control for multichannel buffers with adaptive release time
351 : *-------------------------------------------------------------------*/
352 :
353 : /*! r: number of clipped output samples */
354 1114140 : static Word32 limitRendererOutput_fx(
355 : IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */
356 : Word32 *output, /* i/o: I/O buffer Q(q_factor) */
357 : const Word16 output_frame, /* i : number of samples per channel in the buffer */
358 : const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied */
359 : Word16 q_factor ) /* i : q factor of output samples */
360 : {
361 : Word16 i;
362 : Word32 **channels;
363 : Word16 num_channels;
364 1114140 : Word32 numClipping = 0;
365 1114140 : move32();
366 :
367 : /* return early if given bad parameters */
368 1114140 : test();
369 1114140 : test();
370 1114140 : IF( hLimiter == NULL || output == NULL || output_frame <= 0 )
371 : {
372 0 : return 0;
373 : }
374 :
375 1114140 : channels = hLimiter->channel_ptrs_fx;
376 1114140 : num_channels = hLimiter->num_channels;
377 1114140 : move16();
378 :
379 7599488 : FOR( i = 0; i < num_channels; ++i )
380 : {
381 6485348 : channels[i] = output + imult1616( i, output_frame );
382 : }
383 :
384 1114140 : limiter_process_fx( hLimiter, output_frame, threshold, 0, NULL, q_factor );
385 :
386 : /* Apply clipping to buffer in case the limiter let through some samples > 1.0f */
387 2671146780 : FOR( i = 0; i < output_frame * num_channels; ++i )
388 : {
389 :
390 2670032640 : output[i] = L_min( L_max( L_shl( INT16_MIN, q_factor ), output[i] ), L_shl( INT16_MAX, q_factor ) );
391 2670032640 : move32();
392 : }
393 :
394 1114140 : return numClipping;
395 : }
396 :
397 : /*-------------------------------------------------------------------*
398 : * validateOutputAudioConfig()
399 : *
400 : *
401 : *-------------------------------------------------------------------*/
402 :
403 658 : static ivas_error validateOutputAudioConfig(
404 : const AUDIO_CONFIG outConfig )
405 : {
406 658 : SWITCH( outConfig )
407 : {
408 658 : case IVAS_AUDIO_CONFIG_MONO:
409 : case IVAS_AUDIO_CONFIG_STEREO:
410 : case IVAS_AUDIO_CONFIG_5_1:
411 : case IVAS_AUDIO_CONFIG_7_1:
412 : case IVAS_AUDIO_CONFIG_5_1_2:
413 : case IVAS_AUDIO_CONFIG_5_1_4:
414 : case IVAS_AUDIO_CONFIG_7_1_4:
415 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
416 : case IVAS_AUDIO_CONFIG_FOA:
417 : case IVAS_AUDIO_CONFIG_HOA2:
418 : case IVAS_AUDIO_CONFIG_HOA3:
419 : case IVAS_AUDIO_CONFIG_BINAURAL:
420 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
421 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
422 : case IVAS_AUDIO_CONFIG_MASA1:
423 : case IVAS_AUDIO_CONFIG_MASA2:
424 658 : return IVAS_ERR_OK;
425 0 : default:
426 0 : BREAK;
427 : }
428 :
429 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
430 : }
431 :
432 : /*-------------------------------------------------------------------*
433 : * getAudioConfigType()
434 : *
435 : *
436 : *-------------------------------------------------------------------*/
437 :
438 8381807 : IVAS_REND_AudioConfigType getAudioConfigType(
439 : const AUDIO_CONFIG config )
440 : {
441 : IVAS_REND_AudioConfigType type;
442 :
443 8381807 : SWITCH( config )
444 : {
445 4188792 : case IVAS_AUDIO_CONFIG_MONO:
446 : case IVAS_AUDIO_CONFIG_STEREO:
447 : case IVAS_AUDIO_CONFIG_5_1:
448 : case IVAS_AUDIO_CONFIG_7_1:
449 : case IVAS_AUDIO_CONFIG_5_1_2:
450 : case IVAS_AUDIO_CONFIG_5_1_4:
451 : case IVAS_AUDIO_CONFIG_7_1_4:
452 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
453 4188792 : type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
454 4188792 : move16();
455 4188792 : BREAK;
456 1433473 : case IVAS_AUDIO_CONFIG_FOA:
457 : case IVAS_AUDIO_CONFIG_HOA2:
458 : case IVAS_AUDIO_CONFIG_HOA3:
459 1433473 : type = IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS;
460 1433473 : move16();
461 1433473 : BREAK;
462 301542 : case IVAS_AUDIO_CONFIG_OBA:
463 301542 : type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
464 301542 : move16();
465 301542 : BREAK;
466 2448896 : case IVAS_AUDIO_CONFIG_BINAURAL:
467 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
468 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
469 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
470 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
471 2448896 : type = IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL;
472 2448896 : move16();
473 2448896 : BREAK;
474 9104 : case IVAS_AUDIO_CONFIG_MASA1:
475 : case IVAS_AUDIO_CONFIG_MASA2:
476 9104 : type = IVAS_REND_AUDIO_CONFIG_TYPE_MASA;
477 9104 : move16();
478 9104 : BREAK;
479 0 : default:
480 0 : type = IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
481 0 : move16();
482 0 : BREAK;
483 : }
484 :
485 8381807 : return type;
486 : }
487 :
488 : /*-------------------------------------------------------------------*
489 : * validateOutputSampleRate()
490 : *
491 : *
492 : *-------------------------------------------------------------------*/
493 :
494 658 : static ivas_error validateOutputSampleRate(
495 : const Word32 sampleRate,
496 : const AUDIO_CONFIG outConfig )
497 : {
498 658 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
499 : {
500 : /* If no binaural rendering, any sampling rate is supported */
501 470 : return IVAS_ERR_OK;
502 : }
503 :
504 : /* Otherwise rendering to binaural, support the same set as IVAS decoder */
505 188 : SWITCH( sampleRate )
506 : {
507 188 : case 8000:
508 : case 16000:
509 : case 32000:
510 : case 48000:
511 188 : return IVAS_ERR_OK;
512 : }
513 :
514 0 : return IVAS_ERR_INVALID_SAMPLING_RATE;
515 : }
516 : /*-------------------------------------------------------------------*
517 : * getAudioConfigNumChannels()
518 : *
519 : *
520 : *-------------------------------------------------------------------*/
521 :
522 5811605 : ivas_error getAudioConfigNumChannels(
523 : const AUDIO_CONFIG config,
524 : Word16 *numChannels )
525 : {
526 5811605 : SWITCH( config )
527 : {
528 1454089 : case IVAS_AUDIO_CONFIG_MONO:
529 : case IVAS_AUDIO_CONFIG_OBA:
530 : case IVAS_AUDIO_CONFIG_MASA1:
531 1454089 : *numChannels = 1;
532 1454089 : move16();
533 1454089 : BREAK;
534 1549116 : case IVAS_AUDIO_CONFIG_STEREO:
535 : case IVAS_AUDIO_CONFIG_BINAURAL:
536 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
537 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
538 : case IVAS_AUDIO_CONFIG_MASA2:
539 1549116 : *numChannels = 2;
540 1549116 : move16();
541 1549116 : BREAK;
542 335286 : case IVAS_AUDIO_CONFIG_FOA:
543 335286 : *numChannels = 4;
544 335286 : move16();
545 335286 : BREAK;
546 374274 : case IVAS_AUDIO_CONFIG_5_1:
547 374274 : *numChannels = 6;
548 374274 : move16();
549 374274 : BREAK;
550 270811 : case IVAS_AUDIO_CONFIG_7_1:
551 : case IVAS_AUDIO_CONFIG_5_1_2:
552 270811 : *numChannels = 8;
553 270811 : move16();
554 270811 : BREAK;
555 329965 : case IVAS_AUDIO_CONFIG_HOA2:
556 329965 : *numChannels = 9;
557 329965 : move16();
558 329965 : BREAK;
559 144599 : case IVAS_AUDIO_CONFIG_5_1_4:
560 144599 : *numChannels = 10;
561 144599 : move16();
562 144599 : BREAK;
563 1022599 : case IVAS_AUDIO_CONFIG_7_1_4:
564 1022599 : *numChannels = 12;
565 1022599 : move16();
566 1022599 : BREAK;
567 330866 : case IVAS_AUDIO_CONFIG_HOA3:
568 330866 : *numChannels = 16;
569 330866 : move16();
570 330866 : BREAK;
571 0 : default:
572 0 : return IVAS_ERR_NUM_CHANNELS_UNKNOWN;
573 : }
574 :
575 5811605 : move16();
576 5811605 : return IVAS_ERR_OK;
577 : }
578 : /*-------------------------------------------------------------------*
579 : * Local functions
580 : *-------------------------------------------------------------------*/
581 :
582 697 : static ivas_error initLimiter(
583 : IVAS_LIMITER_HANDLE *phLimiter,
584 : const Word16 numChannels,
585 : const Word32 sampleRate )
586 : {
587 : ivas_error error;
588 :
589 : /* If re-initializing with unchanged values, return early */
590 697 : test();
591 697 : test();
592 697 : IF( *phLimiter != NULL && EQ_16( ( *phLimiter )->num_channels, numChannels ) && EQ_32( ( *phLimiter )->sampling_rate, sampleRate ) )
593 : {
594 0 : return IVAS_ERR_OK;
595 : }
596 :
597 : /* Support re-init: close if already allocated */
598 697 : IF( *phLimiter != NULL )
599 : {
600 39 : ivas_limiter_close_fx( phLimiter );
601 : }
602 :
603 697 : IF( NE_32( ( error = ivas_limiter_open_fx( phLimiter, numChannels, sampleRate ) ), IVAS_ERR_OK ) )
604 : {
605 0 : return error;
606 : }
607 :
608 697 : return IVAS_ERR_OK;
609 : }
610 1030 : static LSSETUP_CUSTOM_STRUCT defaultCustomLs(
611 : void )
612 : {
613 : LSSETUP_CUSTOM_STRUCT ls;
614 :
615 : /* Set mono by default. This simplifies initialization,
616 : since output config is never in an undefined state. */
617 1030 : ls.is_planar_setup = 1;
618 1030 : ls.num_spk = 1;
619 1030 : move16();
620 1030 : move16();
621 1030 : set32_fx( ls.ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS );
622 1030 : set32_fx( ls.ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS );
623 1030 : ls.num_lfe = 0;
624 1030 : move16();
625 1030 : set16_fx( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
626 1030 : ls.separate_ch_found = 0;
627 1030 : move16();
628 1030 : set16_fx( ls.separate_ch_gains_fx, 0, MAX_OUTPUT_CHANNELS );
629 :
630 1030 : return ls;
631 : }
632 :
633 :
634 13071 : static ivas_error getSpeakerAzimuths_fx(
635 : AUDIO_CONFIG config,
636 : const Word32 **azimuths /* Q22 */ )
637 : {
638 13071 : SWITCH( config )
639 : {
640 63 : case IVAS_AUDIO_CONFIG_MONO:
641 63 : *azimuths = ls_azimuth_CICP1_fx;
642 63 : BREAK;
643 67 : case IVAS_AUDIO_CONFIG_STEREO:
644 67 : *azimuths = ls_azimuth_CICP2_fx;
645 67 : BREAK;
646 5063 : case IVAS_AUDIO_CONFIG_5_1:
647 5063 : *azimuths = ls_azimuth_CICP6_fx;
648 5063 : BREAK;
649 813 : case IVAS_AUDIO_CONFIG_7_1:
650 813 : *azimuths = ls_azimuth_CICP12_fx;
651 813 : BREAK;
652 2313 : case IVAS_AUDIO_CONFIG_5_1_2:
653 2313 : *azimuths = ls_azimuth_CICP14_fx;
654 2313 : BREAK;
655 2319 : case IVAS_AUDIO_CONFIG_5_1_4:
656 2319 : *azimuths = ls_azimuth_CICP16_fx;
657 2319 : BREAK;
658 2433 : case IVAS_AUDIO_CONFIG_7_1_4:
659 2433 : *azimuths = ls_azimuth_CICP19_fx;
660 2433 : BREAK;
661 0 : default:
662 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
663 : }
664 :
665 13071 : return IVAS_ERR_OK;
666 : }
667 :
668 13071 : static ivas_error getSpeakerElevations_fx(
669 : AUDIO_CONFIG config,
670 : const Word32 **elevations /* Q22 */ )
671 : {
672 13071 : SWITCH( config )
673 : {
674 63 : case IVAS_AUDIO_CONFIG_MONO:
675 63 : *elevations = ls_elevation_CICP1_fx;
676 63 : BREAK;
677 67 : case IVAS_AUDIO_CONFIG_STEREO:
678 67 : *elevations = ls_elevation_CICP2_fx;
679 67 : BREAK;
680 5063 : case IVAS_AUDIO_CONFIG_5_1:
681 5063 : *elevations = ls_elevation_CICP6_fx;
682 5063 : BREAK;
683 813 : case IVAS_AUDIO_CONFIG_7_1:
684 813 : *elevations = ls_elevation_CICP12_fx;
685 813 : BREAK;
686 2313 : case IVAS_AUDIO_CONFIG_5_1_2:
687 2313 : *elevations = ls_elevation_CICP14_fx;
688 2313 : BREAK;
689 2319 : case IVAS_AUDIO_CONFIG_5_1_4:
690 2319 : *elevations = ls_elevation_CICP16_fx;
691 2319 : BREAK;
692 2433 : case IVAS_AUDIO_CONFIG_7_1_4:
693 2433 : *elevations = ls_elevation_CICP19_fx;
694 2433 : BREAK;
695 0 : default:
696 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
697 : }
698 :
699 13071 : return IVAS_ERR_OK;
700 : }
701 :
702 273197 : static ivas_error getAmbisonicsOrder_fx(
703 : AUDIO_CONFIG config,
704 : Word16 *order )
705 : {
706 273197 : SWITCH( config )
707 : {
708 91075 : case IVAS_AUDIO_CONFIG_FOA:
709 91075 : *order = 1;
710 91075 : move16();
711 91075 : BREAK;
712 91061 : case IVAS_AUDIO_CONFIG_HOA2:
713 91061 : *order = 2;
714 91061 : move16();
715 91061 : BREAK;
716 91061 : case IVAS_AUDIO_CONFIG_HOA3:
717 91061 : *order = 3;
718 91061 : move16();
719 91061 : BREAK;
720 0 : default:
721 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" );
722 : }
723 :
724 273197 : return IVAS_ERR_OK;
725 : }
726 :
727 :
728 0 : static Word16 getNumLfeChannels(
729 : input_mc *inputMc )
730 : {
731 0 : SWITCH( inputMc->base.inConfig )
732 : {
733 0 : case IVAS_AUDIO_CONFIG_5_1:
734 : case IVAS_AUDIO_CONFIG_7_1:
735 : case IVAS_AUDIO_CONFIG_5_1_2:
736 : case IVAS_AUDIO_CONFIG_5_1_4:
737 : case IVAS_AUDIO_CONFIG_7_1_4:
738 0 : return 1;
739 0 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
740 0 : return inputMc->customLsInput.num_lfe;
741 0 : default:
742 0 : BREAK;
743 : }
744 :
745 0 : return 0;
746 : }
747 571 : static ivas_error getNumNonLfeChannelsInSpeakerLayout(
748 : AUDIO_CONFIG config,
749 : Word16 *numNonLfeChannels )
750 : {
751 571 : SWITCH( config )
752 : {
753 63 : case IVAS_AUDIO_CONFIG_MONO:
754 63 : *numNonLfeChannels = 1;
755 63 : move16();
756 63 : BREAK;
757 67 : case IVAS_AUDIO_CONFIG_STEREO:
758 67 : *numNonLfeChannels = 2;
759 67 : move16();
760 67 : BREAK;
761 63 : case IVAS_AUDIO_CONFIG_5_1:
762 63 : *numNonLfeChannels = 5;
763 63 : move16();
764 63 : BREAK;
765 126 : case IVAS_AUDIO_CONFIG_5_1_2:
766 : case IVAS_AUDIO_CONFIG_7_1:
767 126 : *numNonLfeChannels = 7;
768 126 : move16();
769 126 : BREAK;
770 69 : case IVAS_AUDIO_CONFIG_5_1_4:
771 69 : *numNonLfeChannels = 9;
772 69 : move16();
773 69 : BREAK;
774 183 : case IVAS_AUDIO_CONFIG_7_1_4:
775 183 : *numNonLfeChannels = 11;
776 183 : move16();
777 183 : BREAK;
778 0 : default:
779 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
780 : }
781 :
782 571 : return IVAS_ERR_OK;
783 : }
784 25504 : static ivas_error getMcConfigValues_fx(
785 : AUDIO_CONFIG inConfig,
786 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs,
787 : const Word32 **azimuth, /* Q22 */
788 : const Word32 **elevation, /* Q22 */
789 : Word16 *lfe_idx,
790 : Word16 *is_planar )
791 : {
792 : Word16 i;
793 : ivas_error error;
794 :
795 25504 : *lfe_idx = -1;
796 25504 : *is_planar = 1;
797 25504 : move16();
798 25504 : move16();
799 25504 : SWITCH( inConfig )
800 : {
801 13004 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
802 13004 : *azimuth = (const Word32 *) &pInCustomLs->ls_azimuth_fx;
803 13004 : *elevation = (const Word32 *) &pInCustomLs->ls_elevation_fx;
804 13004 : IF( pInCustomLs->num_lfe > 0 )
805 : {
806 0 : *lfe_idx = pInCustomLs->lfe_idx[0];
807 0 : move16();
808 : }
809 99036 : FOR( i = 0; i < pInCustomLs->num_spk; i++ )
810 : {
811 99036 : IF( pInCustomLs->ls_elevation_fx[i] != 0 )
812 : {
813 13004 : *is_planar = 0;
814 13004 : move16();
815 13004 : BREAK;
816 : }
817 : }
818 13004 : BREAK;
819 0 : case IVAS_AUDIO_CONFIG_MONO:
820 : case IVAS_AUDIO_CONFIG_STEREO:
821 0 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inConfig, azimuth ) ), IVAS_ERR_OK ) )
822 : {
823 0 : return error;
824 : }
825 0 : IF( NE_32( error = getSpeakerElevations_fx( inConfig, elevation ), IVAS_ERR_OK ) )
826 : {
827 0 : return error;
828 : }
829 0 : BREAK;
830 12500 : case IVAS_AUDIO_CONFIG_5_1:
831 : case IVAS_AUDIO_CONFIG_7_1:
832 : case IVAS_AUDIO_CONFIG_5_1_2:
833 : case IVAS_AUDIO_CONFIG_5_1_4:
834 : case IVAS_AUDIO_CONFIG_7_1_4:
835 12500 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inConfig, azimuth ) ), IVAS_ERR_OK ) )
836 : {
837 0 : return error;
838 : }
839 12500 : IF( NE_32( ( error = getSpeakerElevations_fx( inConfig, elevation ) ), IVAS_ERR_OK ) )
840 : {
841 0 : return error;
842 : }
843 12500 : *lfe_idx = LFE_CHANNEL;
844 12500 : move16();
845 :
846 12500 : test();
847 12500 : IF( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
848 : {
849 5750 : *is_planar = 1;
850 5750 : move16();
851 : }
852 : ELSE
853 : {
854 6750 : *is_planar = 0;
855 6750 : move16();
856 : }
857 12500 : BREAK;
858 0 : default:
859 0 : assert( !"Invalid speaker config" );
860 : return IVAS_ERR_WRONG_PARAMS;
861 : }
862 :
863 25504 : return IVAS_ERR_OK;
864 : }
865 862 : static ivas_error initEfap(
866 : EFAP_WRAPPER *pEfapWrapper,
867 : AUDIO_CONFIG outConfig,
868 : const LSSETUP_CUSTOM_STRUCT *pCustomLsOut )
869 : {
870 : ivas_error error;
871 : const Word32 *azimuths; /* Q22 */
872 : const Word32 *elevations; /* Q22 */
873 : Word16 numNonLfeChannels;
874 :
875 862 : test();
876 862 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
877 : {
878 120 : pEfapWrapper->speakerConfig = IVAS_AUDIO_CONFIG_7_1_4;
879 120 : move32();
880 : }
881 : ELSE
882 : {
883 742 : pEfapWrapper->speakerConfig = outConfig;
884 742 : move32();
885 : }
886 862 : pEfapWrapper->pCustomLsSetup = pCustomLsOut;
887 :
888 : /* If re-initializing, free existing EFAP handle. */
889 862 : IF( pEfapWrapper->hEfap != NULL )
890 : {
891 39 : efap_free_data_fx( &pEfapWrapper->hEfap );
892 : }
893 :
894 : /* Only initialize EFAP handle if output config is channel-based */
895 862 : IF( NE_32( getAudioConfigType( pEfapWrapper->speakerConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
896 : {
897 195 : pEfapWrapper->hEfap = NULL;
898 195 : return IVAS_ERR_OK;
899 : }
900 :
901 667 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
902 : {
903 183 : IF( NE_32( ( error = efap_init_data_fx( &pEfapWrapper->hEfap, pCustomLsOut->ls_azimuth_fx, pCustomLsOut->ls_elevation_fx, pCustomLsOut->num_spk, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) )
904 : {
905 0 : return error;
906 : }
907 : }
908 : ELSE
909 : {
910 484 : IF( NE_32( ( error = getSpeakerAzimuths_fx( pEfapWrapper->speakerConfig, &azimuths ) ), IVAS_ERR_OK ) )
911 : {
912 0 : return error;
913 : }
914 :
915 484 : IF( NE_32( ( error = getSpeakerElevations_fx( pEfapWrapper->speakerConfig, &elevations ) ), IVAS_ERR_OK ) )
916 : {
917 0 : return error;
918 : }
919 :
920 484 : IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( pEfapWrapper->speakerConfig, &numNonLfeChannels ) ), IVAS_ERR_OK ) )
921 : {
922 0 : return error;
923 : }
924 484 : IF( NE_32( ( error = efap_init_data_fx( &pEfapWrapper->hEfap, azimuths, elevations, numNonLfeChannels, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) )
925 : {
926 0 : return error;
927 : }
928 : }
929 :
930 667 : return IVAS_ERR_OK;
931 : }
932 :
933 393634 : static ivas_error getEfapGains_fx(
934 : EFAP_WRAPPER efapWrapper,
935 : const Word32 azi, /* Q22 */
936 : const Word32 ele, /* Q22 */
937 : pan_vector_fx panGains /* Q31 */ )
938 : {
939 : pan_vector_fx tmpPanGains; /* tmp pan gain buffer without LFE channels */ /* Q30 */
940 : Word32 *readPtr;
941 : Word16 i;
942 : Word16 lfeCount;
943 : Word16 numChannels;
944 : ivas_error error;
945 :
946 : /* EFAP returns an array of gains only for non-LFE speakers */
947 393634 : efap_determine_gains_fx( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
948 :
949 : /* Now copy to buffer that includes LFE channels */
950 393634 : IF( EQ_32( efapWrapper.speakerConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
951 : {
952 207 : numChannels = add( efapWrapper.pCustomLsSetup->num_spk, efapWrapper.pCustomLsSetup->num_lfe );
953 207 : readPtr = tmpPanGains;
954 207 : lfeCount = 0;
955 207 : move16();
956 2659 : FOR( i = 0; i < numChannels; ++i )
957 : {
958 2452 : test();
959 2452 : IF( LT_16( lfeCount, efapWrapper.pCustomLsSetup->num_lfe ) && EQ_16( i, efapWrapper.pCustomLsSetup->lfe_idx[lfeCount] ) )
960 : {
961 0 : panGains[i] = 0;
962 0 : move32();
963 0 : lfeCount = add( lfeCount, 1 );
964 : }
965 : ELSE
966 : {
967 2452 : IF( EQ_32( *readPtr, ONE_IN_Q30 ) )
968 : {
969 0 : panGains[i] = ONE_IN_Q31;
970 : }
971 : ELSE
972 : {
973 2452 : panGains[i] = L_shl( *readPtr, 1 );
974 : }
975 2452 : move32();
976 2452 : ++readPtr;
977 : }
978 : }
979 : }
980 : ELSE
981 : {
982 393427 : IF( NE_32( ( error = getAudioConfigNumChannels( efapWrapper.speakerConfig, &numChannels ) ), IVAS_ERR_OK ) )
983 : {
984 0 : return error;
985 : }
986 :
987 393427 : readPtr = tmpPanGains;
988 :
989 4311225 : FOR( i = 0; i < numChannels; ++i )
990 : {
991 3917798 : IF( EQ_16( i, LFE_CHANNEL ) )
992 : {
993 363625 : panGains[i] = 0;
994 363625 : move32();
995 : }
996 : ELSE
997 : {
998 3554173 : IF( GE_32( *readPtr, ONE_IN_Q30 ) )
999 : {
1000 14998 : panGains[i] = ONE_IN_Q31;
1001 : }
1002 : ELSE
1003 : {
1004 3539175 : panGains[i] = L_shl( *readPtr, 1 );
1005 : }
1006 :
1007 3554173 : move32();
1008 3554173 : ++readPtr;
1009 : }
1010 : }
1011 : }
1012 :
1013 393634 : return IVAS_ERR_OK;
1014 : }
1015 :
1016 658 : static ivas_error initHeadRotation_fx(
1017 : IVAS_REND_HANDLE hIvasRend )
1018 : {
1019 : Word16 i, crossfade_len;
1020 : Word32 tmp_fx; /* Q31 */
1021 : ivas_error error;
1022 :
1023 : /* Head rotation is enabled by default */
1024 658 : hIvasRend->headRotData.headRotEnabled = 1;
1025 658 : move16();
1026 :
1027 : /* Initialize 5ms crossfade */
1028 658 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
1029 658 : move16();
1030 658 : tmp_fx = Q31_BY_SUB_FRAME_240;
1031 658 : move16();
1032 :
1033 158578 : FOR( i = 0; i < crossfade_len; i++ )
1034 : {
1035 157920 : hIvasRend->headRotData.crossfade_fx[i] = UL_Mpy_32_32( i, tmp_fx );
1036 157920 : move32();
1037 : }
1038 :
1039 : /* Initialize with unit quaternions */
1040 2378 : FOR( i = 0; i < hIvasRend->num_subframes; ++i )
1041 : {
1042 1720 : hIvasRend->headRotData.headPositions[i] = quaternionInit_fx();
1043 : }
1044 :
1045 :
1046 658 : IF( ( hIvasRend->headRotData.hOrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ) ) == NULL )
1047 : {
1048 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Orientation tracking" );
1049 : }
1050 :
1051 658 : IF( NE_32( ( error = ivas_orient_trk_Init_fx( hIvasRend->headRotData.hOrientationTracker ) ), IVAS_ERR_OK ) )
1052 : {
1053 0 : return error;
1054 : }
1055 :
1056 658 : return IVAS_ERR_OK;
1057 : }
1058 :
1059 :
1060 658 : static void closeHeadRotation(
1061 : IVAS_REND_HANDLE hIvasRend )
1062 : {
1063 658 : test();
1064 658 : IF( ( hIvasRend != NULL ) && ( hIvasRend->headRotData.hOrientationTracker != NULL ) )
1065 : {
1066 658 : free( hIvasRend->headRotData.hOrientationTracker );
1067 : }
1068 :
1069 658 : return;
1070 : }
1071 :
1072 :
1073 406 : static void initRotMatrix_fx(
1074 : rotation_matrix_fx rot_mat )
1075 : {
1076 : Word16 i;
1077 :
1078 : /* Initialize rotation matrices */
1079 1624 : FOR( i = 0; i < 3; i++ )
1080 : {
1081 1218 : set_zero_fx( rot_mat[i], 3 );
1082 1218 : rot_mat[i][i] = ONE_IN_Q30;
1083 1218 : move32();
1084 : }
1085 :
1086 406 : return;
1087 : }
1088 :
1089 126 : static void initRotGains_fx(
1090 : rotation_gains_fx rot_gains )
1091 : {
1092 : Word16 i;
1093 :
1094 : /* Set gains to passthrough */
1095 2142 : FOR( i = 0; i < MAX_INPUT_CHANNELS; i++ )
1096 : {
1097 2016 : set16_fx( rot_gains[i], 0, MAX_INPUT_CHANNELS );
1098 2016 : rot_gains[i][i] = ONE_IN_Q14;
1099 2016 : move16();
1100 : }
1101 :
1102 126 : return;
1103 : }
1104 :
1105 372 : static void initRotGainsWord32_fx(
1106 : rotation_gains_Word32 rot_gains )
1107 : {
1108 : Word16 i;
1109 :
1110 : /* Set gains to passthrough */
1111 6324 : FOR( i = 0; i < MAX_INPUT_CHANNELS; i++ )
1112 : {
1113 5952 : set32_fx( rot_gains[i], 0, MAX_INPUT_CHANNELS );
1114 5952 : rot_gains[i][i] = ONE_IN_Q30;
1115 5952 : move16();
1116 : }
1117 :
1118 372 : return;
1119 : }
1120 10165 : static void initRendInputBase_fx(
1121 : input_base *inputBase,
1122 : const AUDIO_CONFIG inConfig,
1123 : const IVAS_REND_InputId id,
1124 : const rendering_context rendCtx,
1125 : Word32 *dataBuf,
1126 : const Word16 dataBufSize )
1127 : {
1128 10165 : inputBase->inConfig = inConfig;
1129 10165 : move32();
1130 10165 : inputBase->id = id;
1131 10165 : move16();
1132 10165 : inputBase->gain_fx = ONE_IN_Q30;
1133 10165 : move32();
1134 10165 : inputBase->ctx = rendCtx;
1135 10165 : inputBase->numNewSamplesPerChannel = 0;
1136 10165 : move32();
1137 :
1138 10165 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
1139 10165 : inputBase->inputBuffer.config.numChannels = 0;
1140 10165 : move16();
1141 10165 : move16();
1142 10165 : inputBase->inputBuffer.data_fx = dataBuf;
1143 10165 : IF( inputBase->inputBuffer.data_fx != NULL )
1144 : {
1145 953 : set32_fx( inputBase->inputBuffer.data_fx, 0, dataBufSize );
1146 : }
1147 :
1148 10165 : return;
1149 : }
1150 :
1151 300812 : static IVAS_ISM_METADATA defaultObjectPosition(
1152 : void )
1153 : {
1154 : IVAS_ISM_METADATA pos;
1155 :
1156 300812 : pos.azimuth_fx = 0;
1157 300812 : move32();
1158 300812 : pos.elevation_fx = 0;
1159 300812 : move32();
1160 300812 : pos.radius_fx = ONE_IN_Q9;
1161 300812 : move16();
1162 300812 : pos.spread_fx = 0;
1163 300812 : move32();
1164 300812 : pos.gainFactor_fx = ONE_IN_Q31;
1165 300812 : move32();
1166 300812 : pos.yaw_fx = 0;
1167 300812 : move32();
1168 300812 : pos.pitch_fx = 0;
1169 300812 : move32();
1170 300812 : return pos;
1171 : }
1172 :
1173 :
1174 917175 : static Word8 checkObjectPositionChanged_fx(
1175 : IVAS_ISM_METADATA *currentPos,
1176 : IVAS_ISM_METADATA *previousPos )
1177 : {
1178 917175 : test();
1179 1520543 : return !( LT_32( L_abs( L_sub( currentPos->azimuth_fx, previousPos->azimuth_fx ) ), EPSILLON_FX ) &&
1180 603368 : LT_32( L_abs( L_sub( currentPos->elevation_fx, previousPos->elevation_fx ) ), EPSILLON_FX ) );
1181 : }
1182 :
1183 4606 : static rendering_context getRendCtx(
1184 : IVAS_REND_HANDLE hIvasRend )
1185 : {
1186 : rendering_context ctx;
1187 :
1188 : /* Note: when refactoring this, always take the ADDRESS of a member of the
1189 : * renderer struct, so that the context stores a POINTER to the member, even
1190 : * if the member is a pointer or handle itself. */
1191 4606 : ctx.pOutConfig = &hIvasRend->outputConfig;
1192 4606 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
1193 4606 : ctx.pCustomLsOut = &hIvasRend->customLsOut;
1194 4606 : ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
1195 4606 : ctx.pHeadRotData = &hIvasRend->headRotData;
1196 4606 : ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
1197 :
1198 4606 : return ctx;
1199 : }
1200 :
1201 :
1202 778 : static TDREND_WRAPPER defaultTdRendWrapper(
1203 : void )
1204 : {
1205 : TDREND_WRAPPER w;
1206 :
1207 778 : w.binaural_latency_ns = 0;
1208 778 : move32();
1209 778 : w.hBinRendererTd = NULL;
1210 778 : w.hHrtfTD = NULL;
1211 :
1212 778 : return w;
1213 : }
1214 :
1215 :
1216 953 : static bool isIoConfigPairSupported(
1217 : const AUDIO_CONFIG inConfig,
1218 : const AUDIO_CONFIG outConfig )
1219 : {
1220 : /* Rendering mono or stereo to binaural is not supported */
1221 953 : test();
1222 953 : test();
1223 953 : IF( ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_STEREO ) ) && EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
1224 : {
1225 0 : return false;
1226 : }
1227 :
1228 : /* If not returned so far, config pair is supported */
1229 953 : return true;
1230 : }
1231 :
1232 1 : static ivas_error initIsmMasaRendering(
1233 : input_ism *inputIsm,
1234 : const Word32 inSampleRate )
1235 : {
1236 : ivas_error error;
1237 :
1238 1 : IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1239 : {
1240 0 : ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
1241 0 : inputIsm->tdRendWrapper.hHrtfTD = NULL;
1242 : }
1243 :
1244 1 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1245 :
1246 1 : ivas_reverb_close( &inputIsm->hReverb );
1247 :
1248 1 : IF( NE_32( ( error = ivas_omasa_ana_open( &inputIsm->hOMasa, inSampleRate, inputIsm->total_num_objects ) ), IVAS_ERR_OK ) )
1249 : {
1250 0 : return error;
1251 : }
1252 :
1253 1 : return IVAS_ERR_OK;
1254 : }
1255 :
1256 :
1257 406 : static ivas_error setRendInputActiveIsm(
1258 : void *input,
1259 : const AUDIO_CONFIG inConfig,
1260 : const IVAS_REND_InputId id,
1261 : RENDER_CONFIG_DATA *hRendCfg )
1262 : {
1263 : ivas_error error;
1264 : rendering_context rendCtx;
1265 : AUDIO_CONFIG outConfig;
1266 : input_ism *inputIsm;
1267 :
1268 406 : inputIsm = (input_ism *) input;
1269 406 : rendCtx = inputIsm->base.ctx;
1270 406 : outConfig = *rendCtx.pOutConfig;
1271 :
1272 406 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
1273 : {
1274 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
1275 : }
1276 :
1277 406 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputIsm->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
1278 : {
1279 0 : return error;
1280 : }
1281 406 : initRendInputBase_fx( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData_fx, MAX_BUFFER_LENGTH );
1282 :
1283 406 : inputIsm->firstFrameRendered = FALSE;
1284 406 : move16();
1285 :
1286 406 : inputIsm->currentPos = defaultObjectPosition();
1287 406 : inputIsm->previousPos = defaultObjectPosition();
1288 406 : inputIsm->crendWrapper = NULL;
1289 406 : inputIsm->hReverb = NULL;
1290 406 : inputIsm->tdRendWrapper = defaultTdRendWrapper();
1291 :
1292 406 : initRotMatrix_fx( inputIsm->rot_mat_prev );
1293 :
1294 406 : set_zero_fx( inputIsm->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
1295 :
1296 406 : inputIsm->hOMasa = NULL;
1297 :
1298 406 : error = IVAS_ERR_OK;
1299 406 : move32();
1300 :
1301 406 : test();
1302 406 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
1303 : {
1304 40 : IF( NE_32( ( error = ivas_rend_openCrend( &inputIsm->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
1305 : {
1306 0 : return error;
1307 : }
1308 : }
1309 366 : ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
1310 : {
1311 1 : IF( NE_32( ( error = initIsmMasaRendering( inputIsm, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
1312 : {
1313 0 : return error;
1314 : }
1315 : }
1316 : ELSE
1317 : {
1318 : Word16 SrcInd[MAX_NUM_TDREND_CHANNELS];
1319 : Word16 num_src;
1320 : Word16 ivas_format;
1321 365 : IF( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
1322 : {
1323 0 : ivas_format = MC_FORMAT;
1324 : }
1325 : ELSE
1326 : {
1327 365 : ivas_format = ISM_FORMAT;
1328 : }
1329 :
1330 365 : move16();
1331 365 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1332 : {
1333 0 : return error;
1334 : }
1335 :
1336 365 : Word16 nchan_rend = num_src;
1337 365 : move16();
1338 :
1339 365 : test();
1340 365 : IF( EQ_16( ivas_format, MC_FORMAT ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1341 : {
1342 0 : nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
1343 : }
1344 730 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
1345 : {
1346 365 : TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
1347 365 : IF( Src_p != NULL )
1348 : {
1349 365 : IF( Src_p->SrcSpatial_p != NULL )
1350 : {
1351 365 : Src_p->SrcSpatial_p->q_Pos_p = Q31;
1352 365 : move16();
1353 : }
1354 365 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
1355 365 : SrcSpatial_p->q_Pos_p = Q31;
1356 365 : move16();
1357 : }
1358 : }
1359 :
1360 365 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
1361 : {
1362 40 : IF( NE_32( ( error = ivas_reverb_open_fx( &( inputIsm->hReverb ), outConfig, NULL, inputIsm->tdRendWrapper.hBinRendererTd->HrFiltSet_p->lr_energy_and_iac_fx, hRendCfg, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
1363 : {
1364 0 : return error;
1365 : }
1366 : }
1367 : }
1368 :
1369 406 : return IVAS_ERR_OK;
1370 : }
1371 :
1372 2632 : static void clearInputIsm(
1373 : input_ism *inputIsm )
1374 : {
1375 : rendering_context rendCtx;
1376 :
1377 2632 : rendCtx = inputIsm->base.ctx;
1378 :
1379 2632 : freeInputBaseBufferData_fx( &inputIsm->base.inputBuffer.data_fx );
1380 :
1381 2632 : initRendInputBase_fx( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
1382 :
1383 : /* Free input's internal handles */
1384 2632 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1385 :
1386 2632 : ivas_reverb_close( &inputIsm->hReverb );
1387 :
1388 2632 : IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1389 : {
1390 365 : ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
1391 365 : inputIsm->tdRendWrapper.hHrtfTD = NULL;
1392 : }
1393 :
1394 :
1395 2632 : ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
1396 :
1397 2632 : return;
1398 : }
1399 :
1400 62 : static void copyLsConversionMatrixToPanMatrix_fx(
1401 : const LS_CONVERSION_MATRIX_FX *lsConvMatrix,
1402 : pan_matrix_fx panMatrix )
1403 : {
1404 : Word16 i;
1405 : Word16 inCh, outCh;
1406 : Word16 numNonZeroGains;
1407 : Word16 numColumns;
1408 : Word16 tmp_e, tmp;
1409 : /* Index 0 is special and describes the following values */
1410 62 : numNonZeroGains = lsConvMatrix[0].index;
1411 62 : move16();
1412 62 : numColumns = (Word16) lsConvMatrix[0].value;
1413 62 : move16();
1414 :
1415 654 : FOR( i = 1; i < numNonZeroGains + 1; ++i )
1416 : {
1417 592 : tmp = BASOP_Util_Divide1616_Scale( lsConvMatrix[i].index, numColumns, &tmp_e );
1418 592 : move16();
1419 592 : tmp = shr( tmp, add( 15, negate( tmp_e ) ) );
1420 592 : move16();
1421 592 : inCh = tmp;
1422 592 : move16();
1423 : // inCh = lsConvMatrix[i].index / numColumns;
1424 592 : outCh = lsConvMatrix[i].index % numColumns;
1425 592 : move16();
1426 :
1427 592 : IF( EQ_32( lsConvMatrix[i].value, ONE_IN_Q30 ) )
1428 : {
1429 492 : panMatrix[inCh][outCh] = ONE_IN_Q31;
1430 : }
1431 : ELSE
1432 : {
1433 100 : panMatrix[inCh][outCh] = L_shl( lsConvMatrix[i].value, 1 ); /* Q30 + Q1 = Q31 */
1434 : }
1435 592 : move32();
1436 : }
1437 :
1438 62 : return;
1439 : }
1440 :
1441 1101 : static void setZeroPanMatrix_fx(
1442 : pan_matrix_fx panMatrix )
1443 : {
1444 : Word16 i;
1445 :
1446 18717 : FOR( i = 0; i < MAX_INPUT_CHANNELS; ++i )
1447 : {
1448 17616 : set32_fx( panMatrix[i], 0, MAX_OUTPUT_CHANNELS );
1449 : }
1450 :
1451 1101 : return;
1452 : }
1453 :
1454 : /* Note: this only sets non-zero elements, call setZeroPanMatrix() to init first. */
1455 91 : static void fillIdentityPanMatrix_fx(
1456 : pan_matrix_fx panMatrix )
1457 : {
1458 : Word16 i;
1459 :
1460 1547 : FOR( i = 0; i < s_min( MAX_INPUT_CHANNELS, MAX_OUTPUT_CHANNELS ); ++i )
1461 : {
1462 1456 : panMatrix[i][i] = ONE_IN_Q31;
1463 1456 : move32();
1464 : }
1465 :
1466 91 : return;
1467 : }
1468 29 : static ivas_error initMcPanGainsWithIdentMatrix(
1469 : input_mc *inputMc )
1470 : {
1471 29 : fillIdentityPanMatrix_fx( inputMc->panGains_fx );
1472 :
1473 29 : return IVAS_ERR_OK;
1474 : }
1475 100 : static ivas_error initMcPanGainsWithConversionMapping_fx(
1476 : input_mc *inputMc,
1477 : const AUDIO_CONFIG outConfig )
1478 : {
1479 : AUDIO_CONFIG ivasConfigIn, ivasConfigOut;
1480 : Word16 i;
1481 :
1482 100 : ivasConfigIn = inputMc->base.inConfig;
1483 100 : move32();
1484 100 : ivasConfigOut = outConfig;
1485 100 : move32();
1486 :
1487 : /* Find conversion mapping for current I/O config pair.
1488 : * Stay with default panning matrix if conversion_matrix is NULL */
1489 2580 : FOR( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; ++i )
1490 : {
1491 2580 : test();
1492 2580 : IF( EQ_32( ls_conversion_mapping_fx[i].input_config, ivasConfigIn ) && EQ_32( ls_conversion_mapping_fx[i].output_config, ivasConfigOut ) )
1493 : {
1494 : /* Mapping found with valid matrix - copy */
1495 100 : IF( ls_conversion_mapping_fx[i].conversion_matrix_fx != NULL )
1496 : {
1497 62 : copyLsConversionMatrixToPanMatrix_fx( ls_conversion_mapping_fx[i].conversion_matrix_fx, inputMc->panGains_fx );
1498 : }
1499 : /* Mapping found with NULL matrix - use identity matrix */
1500 : ELSE
1501 : {
1502 38 : fillIdentityPanMatrix_fx( inputMc->panGains_fx );
1503 : }
1504 :
1505 100 : return IVAS_ERR_OK;
1506 : }
1507 : }
1508 :
1509 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" );
1510 : }
1511 180 : static ivas_error initMcPanGainsWithEfap_fx(
1512 : input_mc *inputMc,
1513 : const AUDIO_CONFIG outConfig )
1514 : {
1515 : Word16 i;
1516 : Word16 numNonLfeInChannels;
1517 : Word16 inLfeChIdx, outChIdx;
1518 : const Word32 *spkAzi, *spkEle; /* Q22 */
1519 : ivas_error error;
1520 :
1521 180 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1522 : {
1523 33 : IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ), IVAS_ERR_OK ) )
1524 : {
1525 0 : return error;
1526 : }
1527 :
1528 33 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi ) ), IVAS_ERR_OK ) )
1529 : {
1530 0 : return error;
1531 : }
1532 :
1533 33 : IF( NE_32( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle ) ), IVAS_ERR_OK ) )
1534 : {
1535 0 : return error;
1536 : }
1537 :
1538 33 : inLfeChIdx = LFE_CHANNEL;
1539 33 : move16();
1540 : }
1541 : ELSE
1542 : {
1543 147 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
1544 147 : move16();
1545 147 : spkAzi = inputMc->customLsInput.ls_azimuth_fx;
1546 147 : move32();
1547 147 : spkEle = inputMc->customLsInput.ls_elevation_fx;
1548 147 : move32();
1549 147 : inLfeChIdx = -1;
1550 147 : move16();
1551 147 : if ( inputMc->customLsInput.num_lfe > 0 )
1552 : {
1553 0 : inLfeChIdx = inputMc->customLsInput.lfe_idx[0];
1554 0 : move16();
1555 : }
1556 : }
1557 180 : outChIdx = 0;
1558 180 : move16();
1559 1257 : FOR( i = 0; i < numNonLfeInChannels; ++i )
1560 : {
1561 1077 : IF( EQ_16( i, inLfeChIdx ) )
1562 : {
1563 15 : outChIdx = add( outChIdx, 1 );
1564 : }
1565 :
1566 1077 : IF( NE_32( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains_fx[outChIdx] ) ), IVAS_ERR_OK ) )
1567 : {
1568 0 : return error;
1569 : }
1570 1077 : outChIdx = add( outChIdx, 1 );
1571 : }
1572 :
1573 180 : test();
1574 180 : test();
1575 180 : IF( NE_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && inLfeChIdx >= 0 )
1576 : {
1577 12 : inputMc->panGains_fx[inLfeChIdx][LFE_CHANNEL] = ONE_IN_Q31;
1578 12 : move32();
1579 : }
1580 168 : ELSE IF( inputMc->base.ctx.pCustomLsOut->num_lfe > 0 && inLfeChIdx >= 0 )
1581 : {
1582 0 : inputMc->panGains_fx[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = ONE_IN_Q31;
1583 0 : move32();
1584 : }
1585 180 : return IVAS_ERR_OK;
1586 : }
1587 2477511 : static ivas_error getRendInputNumChannels(
1588 : const void *rendInput,
1589 : Word16 *numInChannels )
1590 : {
1591 : /* Using a void pointer for this function to be reusable for any input type (input_ism, input_mc, input_sba).
1592 : Assumptions: - input_base is always the first member in the input struct */
1593 :
1594 : ivas_error error;
1595 : const input_base *pInputBase;
1596 : const input_mc *pInputMc;
1597 :
1598 2477511 : pInputBase = (const input_base *) rendInput;
1599 :
1600 2477511 : IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1601 : {
1602 215975 : pInputMc = (const input_mc *) rendInput;
1603 215975 : *numInChannels = add( pInputMc->customLsInput.num_spk, pInputMc->customLsInput.num_lfe );
1604 215975 : move16();
1605 : }
1606 : ELSE
1607 : {
1608 2261536 : IF( NE_32( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ), IVAS_ERR_OK ) )
1609 : {
1610 0 : return error;
1611 : }
1612 : }
1613 :
1614 2477511 : return IVAS_ERR_OK;
1615 : }
1616 16 : static ivas_error initMcPanGainsWithMonoOut_fx(
1617 : input_mc *inputMc )
1618 : {
1619 : Word16 i;
1620 : Word16 numInChannels;
1621 : Word16 readIdx;
1622 : Word16 writeIdx;
1623 : bool skipSideSpeakers;
1624 : ivas_error error;
1625 :
1626 16 : IF( NE_32( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ), IVAS_ERR_OK ) )
1627 : {
1628 0 : return error;
1629 : }
1630 :
1631 16 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1632 : {
1633 0 : FOR( i = 0; i < numInChannels; ++i )
1634 : {
1635 : /* It's OK to also set gain 1 for LFE input channels here.
1636 : * Correct LFE handling will be applied within updateMcPanGains() */
1637 0 : inputMc->panGains_fx[i][0] = ONE_IN_Q31;
1638 0 : move32();
1639 : }
1640 : }
1641 16 : ELSE IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_STEREO ) )
1642 : {
1643 : /* Special case for STEREO to MONO: Passive downmix (L+R)/2 */
1644 4 : inputMc->panGains_fx[0][0] = ONE_IN_Q30; // Q31(of 0.5)
1645 4 : move32();
1646 4 : inputMc->panGains_fx[1][0] = ONE_IN_Q30; // Q31(of 0.5)
1647 4 : move32();
1648 : }
1649 : ELSE
1650 : {
1651 : /* ls_conversion_cicpX_stereo contains gains for side speakers.
1652 : * These should be skipped with 5.1+X inputs. */
1653 12 : skipSideSpeakers = false;
1654 12 : move16();
1655 12 : test();
1656 12 : if ( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) )
1657 : {
1658 6 : skipSideSpeakers = true;
1659 6 : move16();
1660 : }
1661 12 : readIdx = 0;
1662 12 : move16();
1663 120 : FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx )
1664 : {
1665 108 : test();
1666 108 : IF( ( skipSideSpeakers ) && EQ_16( readIdx, 4 ) )
1667 : {
1668 : /* Skip gains for side speakers in lookup table */
1669 6 : readIdx = add( readIdx, 2 );
1670 : }
1671 :
1672 108 : IF( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) )
1673 : {
1674 48 : inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
1675 : }
1676 : ELSE
1677 : {
1678 60 : inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 );
1679 : }
1680 108 : move32();
1681 :
1682 108 : IF( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) )
1683 : {
1684 48 : inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
1685 : }
1686 : ELSE
1687 : {
1688 60 : inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 ); // Q31
1689 : }
1690 108 : move32();
1691 108 : readIdx = add( readIdx, 1 );
1692 : }
1693 : }
1694 :
1695 16 : return IVAS_ERR_OK;
1696 : }
1697 :
1698 12 : static ivas_error initMcPanGainsWithStereoLookup_fx(
1699 : input_mc *inputMc )
1700 : {
1701 : Word16 readIdx;
1702 : Word16 writeIdx;
1703 : bool skipSideSpeakers;
1704 : Word16 numInChannels;
1705 : ivas_error error;
1706 :
1707 : /* Special case - MONO input.
1708 : * Use gains for center CICP speaker and return early. */
1709 12 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) )
1710 : {
1711 0 : inputMc->panGains_fx[0][0] = L_shl( ls_conversion_cicpX_stereo_fx[2][0], 1 ); /* Q30 + Q1 = Q31 */
1712 0 : move32();
1713 0 : inputMc->panGains_fx[0][1] = L_shl( ls_conversion_cicpX_stereo_fx[2][1], 1 ); /* Q30 + Q1 = Q31 */
1714 0 : move32();
1715 0 : return IVAS_ERR_OK;
1716 : }
1717 :
1718 : /* ls_conversion_cicpX_stereo contains gains for side speakers.
1719 : * These should be skipped with 5.1+X inputs. */
1720 12 : skipSideSpeakers = false;
1721 12 : move16();
1722 12 : test();
1723 12 : if ( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) )
1724 : {
1725 6 : skipSideSpeakers = true;
1726 6 : move16();
1727 : }
1728 :
1729 12 : IF( NE_32( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ), IVAS_ERR_OK ) )
1730 : {
1731 0 : return error;
1732 : }
1733 12 : readIdx = 0;
1734 12 : move16();
1735 120 : FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx )
1736 : {
1737 108 : test();
1738 108 : IF( skipSideSpeakers && EQ_16( readIdx, 4 ) )
1739 : {
1740 : /* Skip gains for side speakers in lookup table */
1741 6 : readIdx = add( readIdx, 2 );
1742 : }
1743 :
1744 108 : IF( EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][0], ONE_IN_Q30 ) )
1745 : {
1746 12 : inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
1747 : }
1748 : ELSE
1749 : {
1750 96 : inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_stereo_fx[readIdx][0], 1 ); /* Q30 + Q1 = Q31 */
1751 : }
1752 108 : move32();
1753 :
1754 108 : IF( EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][1], ONE_IN_Q30 ) )
1755 : {
1756 12 : inputMc->panGains_fx[writeIdx][1] = ONE_IN_Q31;
1757 : }
1758 : ELSE
1759 : {
1760 96 : inputMc->panGains_fx[writeIdx][1] = L_shl( ls_conversion_cicpX_stereo_fx[readIdx][1], 1 ); /* Q30 + Q1 = Q31 */
1761 : }
1762 108 : move32();
1763 108 : readIdx = add( readIdx, 1 );
1764 : }
1765 :
1766 12 : return IVAS_ERR_OK;
1767 : }
1768 :
1769 :
1770 : /* Returns 1 (true) if configs A and B are equal, otherwise returns 0 (false).
1771 : * If both configs are custom LS layouts, layout details are compared to determine equality. */
1772 342 : static bool configsAreEqual(
1773 : const AUDIO_CONFIG configA,
1774 : const LSSETUP_CUSTOM_STRUCT customLsA,
1775 : const AUDIO_CONFIG configB,
1776 : const LSSETUP_CUSTOM_STRUCT customLsB )
1777 : {
1778 : Word16 i;
1779 :
1780 : /* Both input and output are custom LS - compare structs */
1781 342 : test();
1782 342 : IF( EQ_32( configA, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && EQ_32( configB, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1783 : {
1784 18 : IF( NE_16( customLsA.num_spk, customLsB.num_spk ) )
1785 : {
1786 15 : return false;
1787 : }
1788 :
1789 3 : IF( NE_16( customLsA.num_lfe, customLsB.num_lfe ) )
1790 : {
1791 0 : return false;
1792 : }
1793 :
1794 3 : IF( NE_16( customLsA.is_planar_setup, customLsB.is_planar_setup ) )
1795 : {
1796 0 : return false;
1797 : }
1798 :
1799 39 : FOR( i = 0; i < customLsA.num_spk; ++i )
1800 : {
1801 : /* Compare to nearest degree (hence the int16_t cast) */
1802 36 : test();
1803 36 : IF( NE_32( customLsA.ls_azimuth_fx[i], customLsB.ls_azimuth_fx[i] ) ||
1804 : NE_32( customLsA.ls_elevation_fx[i], customLsB.ls_elevation_fx[i] ) )
1805 : {
1806 0 : return false;
1807 : }
1808 : }
1809 3 : FOR( i = 0; i < customLsA.num_lfe; ++i )
1810 : {
1811 0 : IF( NE_16( customLsA.lfe_idx[i], customLsB.lfe_idx[i] ) )
1812 : {
1813 0 : return false;
1814 : }
1815 : }
1816 :
1817 3 : return true;
1818 : }
1819 :
1820 : /* Otherwise it's enough to compare config enums */
1821 324 : return configA == configB;
1822 : }
1823 342 : static ivas_error updateLfePanGainsForMcOut(
1824 : input_mc *inputMc,
1825 : const AUDIO_CONFIG outConfig )
1826 : {
1827 : Word16 i, numLfeIn, numOutChannels;
1828 : ivas_error error;
1829 342 : error = IVAS_ERR_OK;
1830 342 : move32();
1831 :
1832 : /* If panning is not required, simply return */
1833 342 : IF( !inputMc->lfeRouting.pan_lfe )
1834 : {
1835 342 : return error;
1836 : }
1837 :
1838 0 : numLfeIn = getNumLfeChannels( inputMc );
1839 :
1840 0 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1841 : {
1842 0 : numOutChannels = add( inputMc->base.ctx.pCustomLsOut->num_spk, inputMc->base.ctx.pCustomLsOut->num_lfe );
1843 : }
1844 : ELSE
1845 : {
1846 0 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
1847 : {
1848 0 : return error;
1849 : }
1850 : }
1851 :
1852 0 : FOR( i = 0; i < numLfeIn; i++ )
1853 : {
1854 : /* panning gains */
1855 0 : IF( NE_32( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i] ) ), IVAS_ERR_OK ) )
1856 : {
1857 0 : return error;
1858 : }
1859 :
1860 : /* linear input gain */
1861 0 : v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], numOutChannels ); /* Q31 */
1862 : }
1863 :
1864 0 : return error;
1865 : }
1866 90 : static ivas_error updateLfePanGainsForAmbiOut(
1867 : input_mc *inputMc,
1868 : const AUDIO_CONFIG outConfig )
1869 : {
1870 : Word16 i;
1871 : Word16 numLfeIn, outAmbiOrder;
1872 : ivas_error error;
1873 90 : error = IVAS_ERR_OK;
1874 90 : move32();
1875 :
1876 : /* If panning is not required, simply return */
1877 90 : IF( !inputMc->lfeRouting.pan_lfe )
1878 : {
1879 90 : return error;
1880 : }
1881 :
1882 0 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ), IVAS_ERR_OK ) )
1883 : {
1884 0 : return error;
1885 : }
1886 :
1887 0 : numLfeIn = getNumLfeChannels( inputMc );
1888 0 : move16();
1889 0 : FOR( i = 0; i < numLfeIn; i++ )
1890 : {
1891 : /* panning gains */
1892 0 : ivas_dirac_dec_get_response_fx( inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i], outAmbiOrder, Q29 );
1893 :
1894 : /* linear input gain */
1895 0 : v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS ); /* Q31 */
1896 : }
1897 :
1898 0 : return error;
1899 : }
1900 342 : static ivas_error updateMcPanGainsForMcOut(
1901 : input_mc *inputMc,
1902 : const AUDIO_CONFIG outConfig )
1903 : {
1904 : ivas_error error;
1905 :
1906 : /* "if" conditions below realize the following mapping:
1907 :
1908 : If in == out, use identity matrix, otherwise follow the table:
1909 : +-----------+-------------+---------------+-----------+--------------------+
1910 : | in\out | MONO | STEREO | custom LS | other |
1911 : +-----------+-------------+---------------+-----------+--------------------+
1912 : | MONO | mono out | EFAP | EFAP | EFAP |
1913 : | custom LS | mono out | EFAP | EFAP | EFAP |
1914 : | other | mono lookup | stereo lookup | EFAP | conversion mapping |
1915 : +-----------+-------------+---------------+-----------+--------------------+
1916 : */
1917 :
1918 342 : test();
1919 342 : test();
1920 342 : IF( configsAreEqual( inputMc->base.inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ) )
1921 : {
1922 29 : error = initMcPanGainsWithIdentMatrix( inputMc );
1923 : }
1924 313 : ELSE IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ||
1925 : EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) ||
1926 : EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1927 : {
1928 185 : test();
1929 185 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) && ( inputMc->nonDiegeticPan ) )
1930 : {
1931 5 : IF( EQ_32( inputMc->nonDiegeticPanGain_fx, ONE_IN_Q31 ) )
1932 : {
1933 1 : inputMc->panGains_fx[0][0] = ONE_IN_Q31;
1934 : }
1935 : ELSE
1936 : {
1937 4 : inputMc->panGains_fx[0][0] = L_add( L_shr( inputMc->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 /* 0.5f in Q31 */ ); /* Q31 */
1938 : }
1939 5 : move32();
1940 5 : inputMc->panGains_fx[0][1] = L_sub( ONE_IN_Q31, inputMc->panGains_fx[0][0] );
1941 5 : move32();
1942 5 : error = IVAS_ERR_OK;
1943 5 : move32();
1944 : }
1945 : ELSE
1946 : {
1947 180 : error = initMcPanGainsWithEfap_fx( inputMc, outConfig );
1948 : }
1949 : }
1950 128 : ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MONO ) )
1951 : {
1952 16 : error = initMcPanGainsWithMonoOut_fx( inputMc );
1953 : }
1954 112 : ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_STEREO ) )
1955 : {
1956 12 : error = initMcPanGainsWithStereoLookup_fx( inputMc );
1957 : }
1958 : ELSE /* default */
1959 : {
1960 100 : error = initMcPanGainsWithConversionMapping_fx( inputMc, outConfig );
1961 : }
1962 :
1963 : /* check for errors from above block */
1964 342 : IF( NE_32( error, IVAS_ERR_OK ) )
1965 : {
1966 0 : return error;
1967 : }
1968 :
1969 : /* update LFE panning */
1970 342 : error = updateLfePanGainsForMcOut( inputMc, outConfig );
1971 :
1972 342 : return error;
1973 : }
1974 90 : static ivas_error updateMcPanGainsForAmbiOut(
1975 : input_mc *inputMc,
1976 : const AUDIO_CONFIG outConfig )
1977 : {
1978 : Word16 ch_in, ch_out, lfeIdx, i;
1979 : Word16 numNonLfeInChannels, outAmbiOrder;
1980 : const Word32 *spkAzi_fx, *spkEle_fx; /* Q22 */
1981 : ivas_error error;
1982 :
1983 90 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ), IVAS_ERR_OK ) )
1984 : {
1985 0 : return error;
1986 : }
1987 :
1988 90 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1989 : {
1990 54 : IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ), IVAS_ERR_OK ) )
1991 : {
1992 0 : return error;
1993 : }
1994 :
1995 54 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi_fx ) ), IVAS_ERR_OK ) )
1996 : {
1997 0 : return error;
1998 : }
1999 :
2000 54 : IF( NE_32( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle_fx ) ), IVAS_ERR_OK ) )
2001 : {
2002 0 : return error;
2003 : }
2004 54 : ch_in = 0;
2005 54 : move16();
2006 372 : FOR( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out )
2007 : {
2008 318 : IF( EQ_16( ch_in, LFE_CHANNEL ) )
2009 : {
2010 36 : ch_out = add( ch_out, 1 );
2011 : }
2012 318 : move16();
2013 318 : move16(); // move for typecasting Word32 to Word16
2014 318 : ivas_dirac_dec_get_response_fx( (Word16) L_shr( spkAzi_fx[ch_in], 22 ), (Word16) L_shr( spkEle_fx[ch_in], 22 ), inputMc->panGains_fx[ch_out], outAmbiOrder, Q29 );
2015 5406 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
2016 : {
2017 5088 : Word32 temp = inputMc->panGains_fx[ch_out][i];
2018 5088 : move32();
2019 :
2020 5088 : IF( GE_32( L_abs( temp ), ONE_IN_Q29 ) )
2021 : {
2022 324 : IF( temp > 0 )
2023 : {
2024 318 : inputMc->panGains_fx[ch_out][i] = ONE_IN_Q31;
2025 318 : move32();
2026 : }
2027 : ELSE
2028 : {
2029 6 : inputMc->panGains_fx[ch_out][i] = L_negate( ONE_IN_Q31 );
2030 6 : move32();
2031 : }
2032 : }
2033 : ELSE
2034 : {
2035 4764 : inputMc->panGains_fx[ch_out][i] = L_shl( temp, 2 ); /* Q29 + Q2 = Q31 */
2036 4764 : move32();
2037 : }
2038 : }
2039 318 : ch_in = add( ch_in, 1 );
2040 : }
2041 : }
2042 : ELSE
2043 : {
2044 36 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
2045 36 : move16();
2046 36 : spkAzi_fx = inputMc->customLsInput.ls_azimuth_fx;
2047 36 : move32();
2048 36 : spkEle_fx = inputMc->customLsInput.ls_elevation_fx;
2049 36 : move32();
2050 36 : ch_in = 0;
2051 36 : move16();
2052 270 : FOR( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out )
2053 : {
2054 234 : FOR( lfeIdx = 0; lfeIdx < inputMc->customLsInput.num_lfe; ++lfeIdx )
2055 : {
2056 0 : IF( EQ_16( inputMc->customLsInput.lfe_idx[lfeIdx], ch_in ) )
2057 : {
2058 0 : ch_out = add( ch_out, 1 );
2059 0 : BREAK;
2060 : }
2061 : }
2062 :
2063 234 : ivas_dirac_dec_get_response_fx( (Word16) L_shr( spkAzi_fx[ch_in], 22 ), (Word16) L_shr( spkEle_fx[ch_in], 22 ), inputMc->panGains_fx[ch_out], outAmbiOrder, Q29 );
2064 3978 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
2065 : {
2066 3744 : Word32 temp = inputMc->panGains_fx[ch_out][i];
2067 3744 : move32();
2068 3744 : IF( GE_32( L_abs( temp ), ONE_IN_Q29 ) )
2069 : {
2070 240 : IF( temp > 0 )
2071 : {
2072 234 : inputMc->panGains_fx[ch_out][i] = ONE_IN_Q31;
2073 234 : move32();
2074 : }
2075 : ELSE
2076 : {
2077 6 : inputMc->panGains_fx[ch_out][i] = L_negate( ONE_IN_Q31 );
2078 6 : move32();
2079 : }
2080 : }
2081 : ELSE
2082 : {
2083 3504 : inputMc->panGains_fx[ch_out][i] = L_shl( temp, 2 ); /* Q29 + Q2 = Q31 */
2084 3504 : move32();
2085 : }
2086 : }
2087 234 : ch_in = add( ch_in, 1 );
2088 : }
2089 : }
2090 :
2091 : /* update LFE panning */
2092 90 : IF( NE_32( ( error = updateLfePanGainsForAmbiOut( inputMc, outConfig ) ), IVAS_ERR_OK ) )
2093 : {
2094 0 : return error;
2095 : }
2096 :
2097 90 : return IVAS_ERR_OK;
2098 : }
2099 477 : static ivas_error updateMcPanGains(
2100 : input_mc *inputMc,
2101 : const AUDIO_CONFIG outConfig )
2102 : {
2103 : Word16 i;
2104 : ivas_error error;
2105 :
2106 : /* Reset to all zeros - some functions below only write non-zero elements. */
2107 477 : setZeroPanMatrix_fx( inputMc->panGains_fx );
2108 :
2109 477 : error = IVAS_ERR_OK;
2110 477 : move32();
2111 477 : SWITCH( getAudioConfigType( outConfig ) )
2112 : {
2113 254 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2114 254 : error = updateMcPanGainsForMcOut( inputMc, outConfig );
2115 254 : BREAK;
2116 90 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2117 90 : error = updateMcPanGainsForAmbiOut( inputMc, outConfig );
2118 90 : BREAK;
2119 132 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2120 : SWITCH( outConfig )
2121 : {
2122 44 : case IVAS_AUDIO_CONFIG_BINAURAL:
2123 44 : BREAK; /* Do nothing */
2124 88 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2125 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2126 : /* Prepare rendering to intermediate format */
2127 88 : error = updateMcPanGainsForMcOut( inputMc, IVAS_AUDIO_CONFIG_7_1_4 );
2128 88 : BREAK;
2129 0 : default:
2130 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2131 : }
2132 132 : BREAK;
2133 1 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2134 1 : BREAK; /* Do nothing */
2135 0 : default:
2136 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2137 : }
2138 : /* Check error here to keep switch statement more compact */
2139 477 : IF( NE_32( error, IVAS_ERR_OK ) )
2140 : {
2141 0 : return error;
2142 : }
2143 :
2144 : /* Copy LFE routing to pan gains array */
2145 477 : IF( EQ_16( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2146 : {
2147 210 : FOR( i = 0; i < inputMc->customLsInput.num_lfe; ++i )
2148 : {
2149 0 : Copy32( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->panGains_fx[inputMc->customLsInput.lfe_idx[i]], IVAS_MAX_OUTPUT_CHANNELS );
2150 : }
2151 : }
2152 : ELSE
2153 : {
2154 : /* For code simplicity, always copy LFE gains. If config has no LFE, gains will be zero anyway. */
2155 267 : Copy32( inputMc->lfeRouting.lfePanMtx_fx[0], inputMc->panGains_fx[LFE_CHANNEL], IVAS_MAX_OUTPUT_CHANNELS );
2156 : }
2157 :
2158 477 : return IVAS_ERR_OK;
2159 : }
2160 :
2161 113253 : static ivas_error initMcBinauralRendering(
2162 : input_mc *inputMc,
2163 : const AUDIO_CONFIG inConfig,
2164 : const AUDIO_CONFIG outConfig,
2165 : RENDER_CONFIG_DATA *hRendCfg,
2166 : UWord8 reconfigureFlag )
2167 : {
2168 : ivas_error error;
2169 : Word32 binauralDelayNs;
2170 : Word32 outSampleRate;
2171 : Word8 useTDRend;
2172 :
2173 : /* Allocate TD binaural renderer for custom loudspeaker layouts (regardless of headrotation)
2174 : or planar MC layouts with headrotation, CREND for the rest */
2175 113253 : useTDRend = FALSE;
2176 113253 : move16();
2177 113253 : IF( NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
2178 : {
2179 75502 : test();
2180 75502 : test();
2181 75502 : test();
2182 75502 : IF( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
2183 : {
2184 16931 : useTDRend = TRUE;
2185 16931 : move16();
2186 : }
2187 58571 : ELSE IF( ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_16( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) &&
2188 : ( inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2189 : {
2190 18416 : useTDRend = TRUE;
2191 18416 : move16();
2192 : }
2193 : }
2194 :
2195 : /* if TD renderer was open and we need to use CREND, close it */
2196 113253 : test();
2197 113253 : IF( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) )
2198 : {
2199 140 : ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
2200 140 : inputMc->tdRendWrapper.hHrtfTD = NULL;
2201 : }
2202 :
2203 :
2204 : /* if we need to use TD renderer and CREND was open, close it */
2205 113253 : IF( useTDRend )
2206 : {
2207 35347 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2208 : }
2209 :
2210 113253 : test();
2211 113253 : test();
2212 113253 : IF( !reconfigureFlag || ( !useTDRend && NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && inputMc->hReverb != NULL ) )
2213 : {
2214 132 : ivas_reverb_close( &inputMc->hReverb );
2215 : }
2216 :
2217 113253 : test();
2218 113253 : test();
2219 113253 : IF( !reconfigureFlag || ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && !inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2220 : {
2221 19638 : IF( inputMc->efapInWrapper.hEfap != NULL )
2222 : {
2223 36 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2224 : }
2225 : }
2226 :
2227 113253 : outSampleRate = *inputMc->base.ctx.pOutSampleRate;
2228 113253 : move32();
2229 :
2230 113253 : test();
2231 113253 : test();
2232 113253 : IF( useTDRend && inputMc->tdRendWrapper.hBinRendererTd == NULL )
2233 40 : {
2234 : Word16 SrcInd[MAX_NUM_TDREND_CHANNELS];
2235 : Word16 num_src;
2236 40 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
2237 : {
2238 0 : return error;
2239 : }
2240 40 : Word16 nchan_rend = num_src;
2241 40 : move16();
2242 :
2243 40 : test();
2244 40 : IF( ( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ) && NE_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2245 : {
2246 16 : nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
2247 : }
2248 292 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
2249 : {
2250 252 : TDREND_SRC_t *Src_p = inputMc->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
2251 252 : IF( Src_p != NULL )
2252 : {
2253 252 : IF( Src_p->SrcSpatial_p != NULL )
2254 : {
2255 252 : Src_p->SrcSpatial_p->q_Pos_p = 31;
2256 252 : move16();
2257 : }
2258 252 : IF( inputMc->tdRendWrapper.hBinRendererTd->Sources[nS] != NULL )
2259 : {
2260 252 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputMc->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
2261 252 : SrcSpatial_p->q_Pos_p = 31;
2262 252 : move16();
2263 : }
2264 : }
2265 : }
2266 40 : test();
2267 40 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && inputMc->hReverb == NULL )
2268 : {
2269 8 : IF( NE_32( ( error = ivas_reverb_open_fx( &( inputMc->hReverb ), outConfig, NULL, inputMc->tdRendWrapper.hBinRendererTd->HrFiltSet_p->lr_energy_and_iac_fx, hRendCfg, outSampleRate ) ), IVAS_ERR_OK ) )
2270 : {
2271 0 : return error;
2272 : }
2273 : }
2274 : }
2275 113213 : ELSE IF( !useTDRend && inputMc->crendWrapper == NULL )
2276 : {
2277 : /* open CREND */
2278 76 : IF( NE_32( ( error = ivas_rend_openCrend( &inputMc->crendWrapper, ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) ? IVAS_AUDIO_CONFIG_7_1_4 : inConfig, outConfig, hRendCfg, NULL, outSampleRate ) ), IVAS_ERR_OK ) )
2279 : {
2280 0 : return error;
2281 : }
2282 : }
2283 :
2284 : /* Initialise the EFAP handle for rotation on input layout */
2285 113253 : test();
2286 113253 : test();
2287 113253 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && inputMc->base.ctx.pHeadRotData->headRotEnabled && inputMc->efapInWrapper.hEfap == NULL )
2288 : {
2289 60 : IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inConfig, NULL ) ), IVAS_ERR_OK ) )
2290 : {
2291 0 : return error;
2292 : }
2293 : }
2294 :
2295 : /* determine binaural delay ( used for aligning LFE to output signal ) */
2296 :
2297 113253 : IF( ( inputMc->crendWrapper != NULL ) )
2298 : {
2299 77906 : binauralDelayNs = inputMc->crendWrapper->binaural_latency_ns;
2300 : }
2301 : ELSE
2302 : {
2303 35347 : binauralDelayNs = 0;
2304 : }
2305 113253 : move32();
2306 :
2307 113253 : binauralDelayNs = L_max( binauralDelayNs, inputMc->tdRendWrapper.binaural_latency_ns );
2308 113253 : Word16 exp = 0;
2309 113253 : move16();
2310 113253 : Word16 var1 = BASOP_Util_Divide3232_Scale( *inputMc->base.ctx.pOutSampleRate, 1000000000, &exp );
2311 113253 : Word32 var2 = L_shr_r( Mpy_32_32( binauralDelayNs, L_deposit_h( var1 ) ), negate( exp ) ); /* Q0 */
2312 113253 : inputMc->binauralDelaySmp = extract_l( var2 );
2313 113253 : move16();
2314 : // inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f );
2315 :
2316 113253 : IF( GT_16( inputMc->binauralDelaySmp, MAX_BIN_DELAY_SAMPLES ) )
2317 : {
2318 0 : return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid delay for LFE binaural rendering!)" );
2319 : }
2320 :
2321 113253 : return IVAS_ERR_OK;
2322 : }
2323 :
2324 1 : static ivas_error initMcMasaRendering(
2325 : input_mc *inputMc,
2326 : const AUDIO_CONFIG inConfig,
2327 : const Word32 inSampleRate )
2328 : {
2329 : ivas_error error;
2330 :
2331 1 : IF( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2332 : {
2333 0 : ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
2334 0 : inputMc->tdRendWrapper.hHrtfTD = NULL;
2335 : }
2336 :
2337 1 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2338 :
2339 1 : ivas_reverb_close( &inputMc->hReverb );
2340 :
2341 1 : IF( inputMc->efapInWrapper.hEfap != NULL )
2342 : {
2343 0 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2344 : }
2345 :
2346 1 : IF( NE_32( ( error = ivas_mcmasa_ana_open( &inputMc->hMcMasa, inConfig, inSampleRate ) ), IVAS_ERR_OK ) )
2347 : {
2348 0 : return error;
2349 : }
2350 :
2351 1 : return IVAS_ERR_OK;
2352 : }
2353 477 : static lfe_routing defaultLfeRouting(
2354 : const AUDIO_CONFIG inConfig,
2355 : const LSSETUP_CUSTOM_STRUCT customLsIn,
2356 : const AUDIO_CONFIG outConfig,
2357 : const LSSETUP_CUSTOM_STRUCT customLsOut )
2358 : {
2359 : Word16 i;
2360 : lfe_routing routing;
2361 :
2362 : /* Set all output gains to zero, then route each input LFE consecutively to the next available output LFE. */
2363 :
2364 2385 : FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i )
2365 : {
2366 1908 : set32_fx( routing.lfePanMtx_fx[i], 0, IVAS_MAX_OUTPUT_CHANNELS );
2367 : }
2368 477 : routing.pan_lfe = false;
2369 477 : move16();
2370 477 : routing.lfeInputGain_fx = ONE_IN_Q31;
2371 477 : move32();
2372 :
2373 477 : SWITCH( inConfig )
2374 : {
2375 196 : case IVAS_AUDIO_CONFIG_5_1:
2376 : case IVAS_AUDIO_CONFIG_5_1_2:
2377 : case IVAS_AUDIO_CONFIG_5_1_4:
2378 : case IVAS_AUDIO_CONFIG_7_1:
2379 : case IVAS_AUDIO_CONFIG_7_1_4:
2380 196 : routing.numLfeChannels = 1;
2381 196 : move16();
2382 196 : BREAK;
2383 210 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2384 210 : routing.numLfeChannels = customLsIn.num_lfe;
2385 210 : move16();
2386 210 : BREAK;
2387 71 : default:
2388 71 : routing.numLfeChannels = 0;
2389 71 : move16();
2390 : }
2391 :
2392 477 : SWITCH( outConfig )
2393 : {
2394 150 : case IVAS_AUDIO_CONFIG_5_1:
2395 : case IVAS_AUDIO_CONFIG_5_1_2:
2396 : case IVAS_AUDIO_CONFIG_5_1_4:
2397 : case IVAS_AUDIO_CONFIG_7_1:
2398 : case IVAS_AUDIO_CONFIG_7_1_4:
2399 150 : routing.lfePanMtx_fx[0][LFE_CHANNEL] = ONE_IN_Q31;
2400 150 : move32();
2401 150 : BREAK;
2402 39 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2403 39 : FOR( i = 0; i < routing.numLfeChannels && i < customLsOut.num_lfe; ++i )
2404 : {
2405 0 : test();
2406 0 : routing.lfePanMtx_fx[i][customLsOut.lfe_idx[i]] = ONE_IN_Q31;
2407 0 : move32();
2408 : }
2409 39 : BREAK;
2410 288 : default:
2411 : /* Do nothing */
2412 288 : BREAK;
2413 : }
2414 :
2415 477 : return routing;
2416 : }
2417 372 : static ivas_error setRendInputActiveMc(
2418 : void *input,
2419 : const AUDIO_CONFIG inConfig,
2420 : const IVAS_REND_InputId id,
2421 : RENDER_CONFIG_DATA *hRendCfg )
2422 : {
2423 : ivas_error error;
2424 : rendering_context rendCtx;
2425 : AUDIO_CONFIG outConfig;
2426 : input_mc *inputMc;
2427 :
2428 372 : inputMc = (input_mc *) input;
2429 372 : rendCtx = inputMc->base.ctx;
2430 372 : outConfig = *rendCtx.pOutConfig;
2431 :
2432 372 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
2433 : {
2434 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2435 : }
2436 372 : IF( NE_32( ( error = allocateMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx, MAX_BIN_DELAY_SAMPLES ) ), IVAS_ERR_OK ) )
2437 : {
2438 0 : return error;
2439 : }
2440 :
2441 372 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMc->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
2442 : {
2443 0 : return error;
2444 : }
2445 372 : initRendInputBase_fx( &inputMc->base, inConfig, id, rendCtx, inputMc->bufferData_fx, MAX_BUFFER_LENGTH );
2446 :
2447 372 : setZeroPanMatrix_fx( inputMc->panGains_fx );
2448 :
2449 372 : inputMc->customLsInput = defaultCustomLs();
2450 372 : inputMc->tdRendWrapper = defaultTdRendWrapper();
2451 372 : inputMc->crendWrapper = NULL;
2452 372 : inputMc->hReverb = NULL;
2453 372 : inputMc->hMcMasa = NULL;
2454 :
2455 372 : initRotGainsWord32_fx( inputMc->rot_gains_prev_fx );
2456 372 : inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut );
2457 372 : set32_fx( inputMc->lfeDelayBuffer_fx, 0, MAX_BIN_DELAY_SAMPLES );
2458 372 : inputMc->binauralDelaySmp = 0;
2459 372 : move16();
2460 :
2461 372 : test();
2462 372 : test();
2463 372 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
2464 : {
2465 96 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg, FALSE ) ), IVAS_ERR_OK ) )
2466 : {
2467 0 : return error;
2468 : }
2469 : }
2470 :
2471 372 : test();
2472 372 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
2473 : {
2474 1 : IF( NE_32( ( error = initMcMasaRendering( inputMc, inConfig, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
2475 : {
2476 0 : return error;
2477 : }
2478 : }
2479 :
2480 372 : IF( NE_32( ( error = updateMcPanGains( inputMc, outConfig ) ), IVAS_ERR_OK ) )
2481 : {
2482 0 : return error;
2483 : }
2484 :
2485 372 : return IVAS_ERR_OK;
2486 : }
2487 658 : static void clearInputMc(
2488 : input_mc *inputMc )
2489 : {
2490 : rendering_context rendCtx;
2491 :
2492 658 : rendCtx = inputMc->base.ctx;
2493 658 : freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx );
2494 658 : freeInputBaseBufferData_fx( &inputMc->bufferData_fx );
2495 658 : initRendInputBase_fx( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2496 :
2497 : /* Free input's internal handles */
2498 658 : IF( inputMc->efapInWrapper.hEfap != NULL )
2499 : {
2500 129 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2501 : }
2502 :
2503 658 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2504 :
2505 658 : ivas_reverb_close( &inputMc->hReverb );
2506 :
2507 658 : IF( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2508 : {
2509 20 : ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
2510 20 : inputMc->tdRendWrapper.hHrtfTD = NULL;
2511 : }
2512 :
2513 :
2514 658 : ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
2515 :
2516 658 : return;
2517 : }
2518 89 : static ivas_error initSbaPanGainsForMcOut(
2519 : input_sba *inputSba,
2520 : const AUDIO_CONFIG outConfig,
2521 : const LSSETUP_CUSTOM_STRUCT *outSetupCustom )
2522 : {
2523 : Word16 ambiOrderIn;
2524 : Word16 chInIdx, chOutIdx;
2525 : Word32 *tmpDecMtx, *readPtr;
2526 : IVAS_OUTPUT_SETUP hOutSetup;
2527 : ivas_error error;
2528 :
2529 89 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inputSba->base.inConfig, &ambiOrderIn ) ), IVAS_ERR_OK ) )
2530 : {
2531 0 : return error;
2532 : }
2533 :
2534 89 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
2535 : {
2536 0 : assert( !"Invalid configuration" );
2537 : return IVAS_ERR_WRONG_PARAMS;
2538 : }
2539 :
2540 89 : SWITCH( outConfig )
2541 : {
2542 8 : case IVAS_AUDIO_CONFIG_MONO:
2543 8 : hOutSetup.ls_azimuth_fx = ls_azimuth_CICP1_fx;
2544 8 : hOutSetup.ls_elevation_fx = ls_elevation_CICP1_fx;
2545 8 : ivas_output_init( &hOutSetup, outConfig );
2546 8 : BREAK;
2547 72 : case IVAS_AUDIO_CONFIG_STEREO:
2548 : case IVAS_AUDIO_CONFIG_5_1:
2549 : case IVAS_AUDIO_CONFIG_7_1:
2550 : case IVAS_AUDIO_CONFIG_5_1_2:
2551 : case IVAS_AUDIO_CONFIG_5_1_4:
2552 : case IVAS_AUDIO_CONFIG_7_1_4:
2553 72 : ivas_output_init( &hOutSetup, outConfig );
2554 72 : BREAK;
2555 9 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2556 : // ivas_ls_custom_setup( &hOutSetup, (LSSETUP_CUSTOM_STRUCT *)outSetupCustom );
2557 9 : ivas_ls_custom_setup_fx( &hOutSetup, outSetupCustom );
2558 9 : BREAK;
2559 0 : default:
2560 0 : assert( !"Invalid speaker config" );
2561 : return IVAS_ERR_WRONG_PARAMS;
2562 : }
2563 :
2564 : /* obtain and copy over HOA decoding matrix */
2565 89 : tmpDecMtx = NULL;
2566 89 : IF( NE_32( ( error = ivas_sba_get_hoa_dec_matrix_fx( hOutSetup, &tmpDecMtx, ambiOrderIn ) ), IVAS_ERR_OK ) )
2567 : {
2568 0 : return error;
2569 : }
2570 :
2571 89 : readPtr = &tmpDecMtx[0];
2572 861 : FOR( chOutIdx = 0; chOutIdx < hOutSetup.nchan_out_woLFE + hOutSetup.num_lfe; ++chOutIdx )
2573 : {
2574 13124 : FOR( chInIdx = 0; chInIdx < SBA_NHARM_HOA3; ++chInIdx )
2575 : {
2576 12352 : test();
2577 12352 : IF( hOutSetup.num_lfe > 0 && EQ_16( chOutIdx, hOutSetup.index_lfe[0] ) )
2578 : {
2579 1024 : CONTINUE; /* nothing to be rendered to LFE */
2580 : }
2581 11328 : inputSba->hoaDecMtx_fx[chInIdx][chOutIdx] = L_shl_sat( *readPtr++, Q2 ); /* Q29 + Q2 = Q31 */
2582 11328 : move32();
2583 : }
2584 : }
2585 89 : free( tmpDecMtx );
2586 :
2587 89 : return IVAS_ERR_OK;
2588 : }
2589 :
2590 24 : static ivas_error initSbaPanGainsForSbaOut(
2591 : input_sba *inputSba,
2592 : const AUDIO_CONFIG outConfig )
2593 : {
2594 : ivas_error error;
2595 24 : error = IVAS_ERR_OK;
2596 24 : move32();
2597 :
2598 24 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
2599 : {
2600 0 : assert( !"Invalid configuration" );
2601 : return IVAS_ERR_WRONG_PARAMS;
2602 : }
2603 :
2604 24 : fillIdentityPanMatrix_fx( inputSba->hoaDecMtx_fx );
2605 :
2606 24 : return error;
2607 : }
2608 126 : static ivas_error updateSbaPanGains(
2609 : input_sba *inputSba,
2610 : const AUDIO_CONFIG outConfig,
2611 : RENDER_CONFIG_DATA *hRendCfg )
2612 : {
2613 : ivas_error error;
2614 : AUDIO_CONFIG inConfig;
2615 : rendering_context rendCtx;
2616 :
2617 : /* Reset to all zeros - some functions below only write non-zero elements. */
2618 126 : setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
2619 :
2620 126 : inConfig = inputSba->base.inConfig;
2621 126 : rendCtx = inputSba->base.ctx;
2622 :
2623 126 : SWITCH( getAudioConfigType( outConfig ) )
2624 : {
2625 65 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2626 65 : error = initSbaPanGainsForMcOut( inputSba, outConfig, inputSba->base.ctx.pCustomLsOut );
2627 65 : BREAK;
2628 24 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2629 24 : error = initSbaPanGainsForSbaOut( inputSba, outConfig );
2630 24 : BREAK;
2631 36 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2632 : SWITCH( outConfig )
2633 : {
2634 12 : case IVAS_AUDIO_CONFIG_BINAURAL:
2635 : {
2636 12 : IF( NE_32( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, inConfig, outConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
2637 :
2638 : {
2639 0 : return error;
2640 : }
2641 : }
2642 12 : BREAK;
2643 24 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2644 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2645 24 : IF( NE_32( ( error = initSbaPanGainsForMcOut( inputSba, IVAS_AUDIO_CONFIG_7_1_4, NULL ) ), IVAS_ERR_OK ) )
2646 : {
2647 0 : return error;
2648 : }
2649 :
2650 24 : IF( NE_32( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
2651 : {
2652 0 : return error;
2653 : }
2654 24 : BREAK;
2655 0 : default:
2656 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2657 : }
2658 36 : BREAK;
2659 1 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2660 1 : error = IVAS_ERR_OK;
2661 1 : move32();
2662 1 : BREAK; /* Do nothing */
2663 0 : default:
2664 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2665 : }
2666 :
2667 : /* Check error here to keep switch statement more compact */
2668 126 : IF( NE_32( error, IVAS_ERR_OK ) )
2669 : {
2670 0 : return error;
2671 : }
2672 :
2673 126 : return IVAS_ERR_OK;
2674 : }
2675 :
2676 1 : static ivas_error initSbaMasaRendering(
2677 : input_sba *inputSba,
2678 : Word32 inSampleRate )
2679 : {
2680 : ivas_error error;
2681 :
2682 1 : ivas_rend_closeCrend( &inputSba->crendWrapper );
2683 :
2684 1 : IF( NE_32( ( error = ivas_dirac_ana_open_fx( &inputSba->hDirAC, inSampleRate ) ), IVAS_ERR_OK ) )
2685 : {
2686 0 : return error;
2687 : }
2688 :
2689 1 : return IVAS_ERR_OK;
2690 : }
2691 :
2692 126 : static ivas_error setRendInputActiveSba(
2693 : void *input,
2694 : const AUDIO_CONFIG inConfig,
2695 : const IVAS_REND_InputId id,
2696 : RENDER_CONFIG_DATA *hRendCfg )
2697 : {
2698 : ivas_error error;
2699 : rendering_context rendCtx;
2700 : AUDIO_CONFIG outConfig;
2701 : input_sba *inputSba;
2702 :
2703 126 : inputSba = (input_sba *) input;
2704 126 : rendCtx = inputSba->base.ctx;
2705 126 : outConfig = *rendCtx.pOutConfig;
2706 126 : move32();
2707 :
2708 126 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
2709 : {
2710 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2711 : }
2712 :
2713 126 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputSba->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
2714 : {
2715 0 : return error;
2716 : }
2717 126 : initRendInputBase_fx( &inputSba->base, inConfig, id, rendCtx, inputSba->bufferData_fx, MAX_BUFFER_LENGTH );
2718 :
2719 126 : setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
2720 :
2721 126 : inputSba->crendWrapper = NULL;
2722 126 : inputSba->hDirAC = NULL;
2723 126 : initRotGains_fx( inputSba->rot_gains_prev_fx );
2724 :
2725 126 : test();
2726 126 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
2727 : {
2728 1 : IF( NE_32( ( error = initSbaMasaRendering( inputSba, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
2729 : {
2730 0 : return error;
2731 : }
2732 : }
2733 :
2734 126 : IF( NE_32( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg ) ), IVAS_ERR_OK ) )
2735 : {
2736 0 : return error;
2737 : }
2738 :
2739 126 : return error;
2740 : }
2741 658 : static void clearInputSba(
2742 : input_sba *inputSba )
2743 : {
2744 : rendering_context rendCtx;
2745 :
2746 658 : rendCtx = inputSba->base.ctx;
2747 :
2748 658 : freeInputBaseBufferData_fx( &inputSba->bufferData_fx );
2749 :
2750 658 : initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2751 :
2752 : /* Free input's internal handles */
2753 658 : ivas_rend_closeCrend( &inputSba->crendWrapper );
2754 :
2755 658 : ivas_dirac_ana_close_fx( &( inputSba->hDirAC ) );
2756 :
2757 658 : return;
2758 : }
2759 :
2760 49 : static ivas_error setRendInputActiveMasa(
2761 : void *input,
2762 : const AUDIO_CONFIG inConfig,
2763 : const IVAS_REND_InputId id,
2764 : RENDER_CONFIG_DATA *hRendCfg ) /* Todo: This is not used at all within MASA. Support might be better to do after refactoring. */
2765 : {
2766 : ivas_error error;
2767 : rendering_context rendCtx;
2768 : AUDIO_CONFIG outConfig;
2769 : input_masa *inputMasa;
2770 : Word16 numInChannels;
2771 :
2772 49 : inputMasa = (input_masa *) input;
2773 49 : rendCtx = inputMasa->base.ctx;
2774 49 : outConfig = *rendCtx.pOutConfig;
2775 49 : move32();
2776 : (void) hRendCfg; /* Suppress warning */
2777 :
2778 49 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
2779 : {
2780 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2781 : }
2782 :
2783 49 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMasa->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
2784 : {
2785 0 : return error;
2786 : }
2787 49 : initRendInputBase_fx( &inputMasa->base, inConfig, id, rendCtx, inputMasa->bufferData_fx, MAX_BUFFER_LENGTH );
2788 :
2789 49 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &numInChannels ) ), IVAS_ERR_OK ) )
2790 : {
2791 0 : return error;
2792 : }
2793 :
2794 49 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
2795 : {
2796 1 : inputMasa->metadataHasBeenFed = false;
2797 1 : move16();
2798 : Word16 temp;
2799 1 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
2800 : {
2801 0 : temp = 1;
2802 : }
2803 : ELSE
2804 : {
2805 1 : temp = 2;
2806 : }
2807 1 : move16();
2808 1 : IF( NE_32( ( error = masaPrerendOpen_fx( &inputMasa->hMasaPrerend, temp, *( inputMasa->base.ctx.pOutSampleRate ) ) ), IVAS_ERR_OK ) )
2809 : {
2810 0 : return error;
2811 : }
2812 : }
2813 : ELSE
2814 : {
2815 48 : IF( NE_32( ( error = initMasaExtRenderer( inputMasa, outConfig ) ), IVAS_ERR_OK ) )
2816 : {
2817 0 : return error;
2818 : }
2819 48 : inputMasa->metadataHasBeenFed = false;
2820 48 : move16();
2821 : }
2822 :
2823 49 : return IVAS_ERR_OK;
2824 : }
2825 :
2826 658 : static void clearInputMasa(
2827 : input_masa *inputMasa )
2828 : {
2829 : rendering_context rendCtx;
2830 :
2831 658 : rendCtx = inputMasa->base.ctx;
2832 :
2833 658 : freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
2834 :
2835 658 : masaPrerendClose_fx( &inputMasa->hMasaPrerend );
2836 :
2837 658 : freeMasaExtRenderer( &inputMasa->hMasaExtRend );
2838 :
2839 658 : initRendInputBase_fx( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2840 :
2841 658 : return;
2842 : }
2843 :
2844 :
2845 : /*-------------------------------------------------------------------------
2846 : * IVAS_REND_Open()
2847 : *
2848 : *
2849 : *------------------------------------------------------------------------*/
2850 :
2851 658 : ivas_error IVAS_REND_Open(
2852 : IVAS_REND_HANDLE *phIvasRend,
2853 : const Word32 outputSampleRate,
2854 : const AUDIO_CONFIG outConfig,
2855 : const Word16 nonDiegeticPan,
2856 : const Word32 nonDiegeticPanGain, /* Q31 */
2857 : const Word16 num_subframes )
2858 : {
2859 : Word16 i;
2860 : IVAS_REND_HANDLE hIvasRend;
2861 : ivas_error error;
2862 : Word16 numOutChannels;
2863 :
2864 : /* Validate function arguments */
2865 658 : IF( phIvasRend == NULL )
2866 : {
2867 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
2868 : }
2869 :
2870 658 : IF( NE_32( ( error = validateOutputAudioConfig( outConfig ) ), IVAS_ERR_OK ) )
2871 : {
2872 0 : return error;
2873 : }
2874 :
2875 658 : IF( NE_32( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ), IVAS_ERR_OK ) )
2876 : {
2877 0 : return error;
2878 : }
2879 :
2880 658 : *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
2881 658 : IF( *phIvasRend == NULL )
2882 : {
2883 0 : return IVAS_ERR_FAILED_ALLOC;
2884 : }
2885 :
2886 658 : hIvasRend = *phIvasRend;
2887 658 : hIvasRend->sampleRateOut = outputSampleRate;
2888 658 : hIvasRend->outputConfig = outConfig;
2889 658 : hIvasRend->customLsOut = defaultCustomLs();
2890 658 : hIvasRend->hLimiter = NULL;
2891 658 : hIvasRend->efapOutWrapper.hEfap = NULL;
2892 658 : hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
2893 658 : hIvasRend->num_subframes = num_subframes;
2894 :
2895 : /* Initialize limiter */
2896 658 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
2897 : {
2898 0 : return error;
2899 : }
2900 :
2901 658 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ), IVAS_ERR_OK ) )
2902 : {
2903 0 : return error;
2904 : }
2905 :
2906 : /* Initialize headrotation data */
2907 658 : IF( NE_32( ( error = initHeadRotation_fx( hIvasRend ) ), IVAS_ERR_OK ) )
2908 : {
2909 0 : return error;
2910 : }
2911 :
2912 : /* Initialize external orientation data */
2913 658 : IF( NE_32( ( error = ivas_external_orientation_open( &( hIvasRend->hExternalOrientationData ), num_subframes ) ), IVAS_ERR_OK ) )
2914 : {
2915 0 : return error;
2916 : }
2917 : /* Initilize combined orientation data */
2918 658 : IF( NE_32( ( error = ivas_combined_orientation_open( &( hIvasRend->hCombinedOrientationData ), outputSampleRate, num_subframes ) ), IVAS_ERR_OK ) )
2919 : {
2920 0 : return error;
2921 : }
2922 : /* Initialize EFAP */
2923 658 : IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
2924 : {
2925 0 : return error;
2926 : }
2927 :
2928 : /* Initialize inputs */
2929 :
2930 3290 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
2931 : {
2932 2632 : initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2933 2632 : hIvasRend->inputsIsm[i].crendWrapper = NULL;
2934 2632 : hIvasRend->inputsIsm[i].hReverb = NULL;
2935 2632 : hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
2936 2632 : hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
2937 2632 : move16();
2938 2632 : hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
2939 2632 : move32();
2940 2632 : hIvasRend->inputsIsm[i].hOMasa = NULL;
2941 2632 : hIvasRend->inputsIsm[i].bufferData_fx = NULL;
2942 : }
2943 :
2944 1316 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
2945 : {
2946 658 : initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2947 :
2948 658 : hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
2949 658 : hIvasRend->inputsMc[i].crendWrapper = NULL;
2950 658 : hIvasRend->inputsMc[i].hReverb = NULL;
2951 658 : hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
2952 658 : hIvasRend->inputsMc[i].bufferData_fx = NULL;
2953 658 : hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL;
2954 658 : hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
2955 658 : move16();
2956 658 : hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
2957 658 : move32();
2958 658 : hIvasRend->inputsMc[i].hMcMasa = NULL;
2959 : }
2960 :
2961 1316 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
2962 : {
2963 658 : initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2964 :
2965 658 : hIvasRend->inputsSba[i].crendWrapper = NULL;
2966 658 : hIvasRend->inputsSba[i].bufferData_fx = NULL;
2967 658 : hIvasRend->inputsSba[i].hDirAC = NULL;
2968 : }
2969 :
2970 1316 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
2971 : {
2972 658 : initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2973 :
2974 658 : hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
2975 658 : hIvasRend->inputsMasa[i].bufferData_fx = NULL;
2976 658 : hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
2977 658 : hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
2978 658 : move16();
2979 : }
2980 :
2981 :
2982 658 : return IVAS_ERR_OK;
2983 : }
2984 144 : static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup(
2985 : const IVAS_CUSTOM_LS_DATA rendCustomLsLayout )
2986 : {
2987 : Word16 i;
2988 : LSSETUP_CUSTOM_STRUCT customLs;
2989 :
2990 : /* Copy layout description */
2991 144 : customLs.num_spk = rendCustomLsLayout.num_spk;
2992 144 : move16();
2993 144 : Copy32( rendCustomLsLayout.azimuth_fx, customLs.ls_azimuth_fx, rendCustomLsLayout.num_spk );
2994 144 : Copy32( rendCustomLsLayout.elevation_fx, customLs.ls_elevation_fx, rendCustomLsLayout.num_spk );
2995 144 : customLs.is_planar_setup = 1;
2996 144 : move16();
2997 720 : FOR( i = 0; i < rendCustomLsLayout.num_spk; ++i )
2998 : {
2999 720 : IF( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
3000 : {
3001 144 : customLs.is_planar_setup = 0;
3002 144 : move16();
3003 144 : BREAK;
3004 : }
3005 : }
3006 :
3007 144 : customLs.num_lfe = rendCustomLsLayout.num_lfe;
3008 144 : move16();
3009 144 : Copy( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
3010 :
3011 144 : return customLs;
3012 : }
3013 :
3014 :
3015 144 : static ivas_error validateCustomLsLayout_fx(
3016 : const IVAS_CUSTOM_LS_DATA layout )
3017 : {
3018 : Word16 i;
3019 :
3020 : /* Negative number of speakers or LFEs makes no sense */
3021 144 : test();
3022 144 : IF( layout.num_spk < 0 || layout.num_lfe < 0 )
3023 : {
3024 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3025 : }
3026 :
3027 : /* There must be at least one speaker or LFE in the layout */
3028 144 : IF( add( layout.num_spk, layout.num_lfe ) <= 0 )
3029 : {
3030 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3031 : }
3032 :
3033 : /* LFE indices must be positive */
3034 144 : FOR( i = 0; i < layout.num_lfe; ++i )
3035 : {
3036 0 : IF( layout.lfe_idx[i] < 0 )
3037 : {
3038 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3039 : }
3040 : }
3041 :
3042 144 : return IVAS_ERR_OK;
3043 : }
3044 :
3045 :
3046 : /*-------------------------------------------------------------------*
3047 : * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
3048 : *
3049 : *
3050 : *-------------------------------------------------------------------*/
3051 :
3052 39 : ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
3053 : IVAS_REND_HANDLE hIvasRend,
3054 : const IVAS_CUSTOM_LS_DATA layout )
3055 : {
3056 : Word16 i, numOutChannels;
3057 : ivas_error error;
3058 : input_mc *inputMc;
3059 : input_sba *inputSba;
3060 :
3061 : /* Validate function arguments */
3062 39 : IF( hIvasRend == NULL )
3063 : {
3064 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3065 : }
3066 :
3067 39 : IF( NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
3068 : {
3069 : /* Specifying details of custom speaker layout only makes sense if output config is set to custom speaker layout */
3070 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3071 : }
3072 :
3073 39 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
3074 : {
3075 0 : return error;
3076 : }
3077 :
3078 39 : hIvasRend->customLsOut = makeCustomLsSetup( layout );
3079 :
3080 : /* Re-initialize limiter - number of output channels may have changed */
3081 39 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
3082 : {
3083 0 : return error;
3084 : }
3085 :
3086 39 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
3087 : {
3088 0 : return error;
3089 : }
3090 :
3091 : /* Re-initialize EFAP - output layout has changed or has been fully defined for the first time */
3092 39 : IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, hIvasRend->outputConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
3093 : {
3094 0 : return error;
3095 : }
3096 :
3097 : /* Re-initialize panning gains for each active MC input, This includes re-initializing
3098 : * LFE handling for the new output layout, which means custom LFE handling is overwritten,
3099 : * if previously set for any MC input. */
3100 78 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3101 : {
3102 39 : inputMc = &hIvasRend->inputsMc[i];
3103 39 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3104 : {
3105 : /* Input inactive, skip. */
3106 39 : CONTINUE;
3107 : }
3108 :
3109 0 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
3110 :
3111 0 : IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
3112 : {
3113 0 : return error;
3114 : }
3115 : }
3116 :
3117 : /* Re-initialize panning gains for each active SBA input */
3118 78 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3119 : {
3120 39 : inputSba = &hIvasRend->inputsSba[i];
3121 :
3122 39 : IF( EQ_32( inputSba->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3123 : {
3124 : /* Input inactive, skip. */
3125 39 : CONTINUE;
3126 : }
3127 0 : IF( NE_32( ( error = updateSbaPanGains( inputSba, hIvasRend->outputConfig, hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
3128 : {
3129 0 : return error;
3130 : }
3131 : }
3132 :
3133 39 : return IVAS_ERR_OK;
3134 : }
3135 :
3136 : /*-------------------------------------------------------------------*
3137 : * IVAS_REND_NumOutChannels()
3138 : *
3139 : *
3140 : *-------------------------------------------------------------------*/
3141 :
3142 1115495 : ivas_error IVAS_REND_NumOutChannels(
3143 : IVAS_REND_CONST_HANDLE hIvasRend,
3144 : Word16 *numOutChannels )
3145 : {
3146 : ivas_error error;
3147 :
3148 : /* Validate function arguments */
3149 1115495 : test();
3150 1115495 : IF( hIvasRend == NULL || numOutChannels == NULL )
3151 : {
3152 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3153 : }
3154 :
3155 : /* Handle special cases where additional info is needed from the renderer, otherwise use getAudioConfigNumChannels() */
3156 1115495 : SWITCH( hIvasRend->outputConfig )
3157 : {
3158 23979 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3159 23979 : *numOutChannels = add( hIvasRend->customLsOut.num_spk, hIvasRend->customLsOut.num_lfe );
3160 23979 : move16();
3161 23979 : BREAK;
3162 1091516 : default:
3163 1091516 : IF( NE_32( ( error = getAudioConfigNumChannels( hIvasRend->outputConfig, numOutChannels ) ), IVAS_ERR_OK ) )
3164 : {
3165 0 : return error;
3166 : }
3167 1091516 : BREAK;
3168 : }
3169 :
3170 1115495 : return IVAS_ERR_OK;
3171 : }
3172 :
3173 :
3174 953 : static IVAS_REND_InputId makeInputId(
3175 : AUDIO_CONFIG config,
3176 : const Word32 inputIndex )
3177 : {
3178 : /* Put config type in second byte (from LSB), put index + 1 in first byte
3179 : *
3180 : * Index is incremented here so that a valid ID can never be 0. */
3181 953 : return (IVAS_REND_InputId) UL_or( UL_lshl( ( (UWord32) getAudioConfigType( config ) ), 8 ), L_add( inputIndex, 1 ) );
3182 : }
3183 :
3184 :
3185 3072998 : static ivas_error getInputById(
3186 : IVAS_REND_HANDLE hIvasRend,
3187 : IVAS_REND_InputId inputId,
3188 : void **ppInput )
3189 : {
3190 : Word32 inputIndex;
3191 : IVAS_REND_AudioConfigType configType;
3192 : input_base *pInputBase;
3193 :
3194 : /* Reverse makeInputId() */
3195 3072998 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3196 3072998 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3197 :
3198 : /* Validate values derived from input ID */
3199 3072998 : IF( inputIndex < 0 )
3200 : {
3201 0 : return IVAS_ERR_INVALID_INPUT_ID;
3202 : }
3203 3072998 : SWITCH( configType )
3204 : {
3205 2435556 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3206 2435556 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3207 : {
3208 0 : return IVAS_ERR_INVALID_INPUT_ID;
3209 : }
3210 2435556 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3211 2435556 : BREAK;
3212 360012 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3213 360012 : IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
3214 : {
3215 0 : return IVAS_ERR_INVALID_INPUT_ID;
3216 : }
3217 360012 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3218 360012 : BREAK;
3219 251881 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3220 251881 : IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
3221 : {
3222 0 : return IVAS_ERR_INVALID_INPUT_ID;
3223 : }
3224 251881 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3225 251881 : BREAK;
3226 25549 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3227 25549 : IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
3228 : {
3229 0 : return IVAS_ERR_INVALID_INPUT_ID;
3230 : }
3231 25549 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3232 25549 : BREAK;
3233 0 : default:
3234 0 : return IVAS_ERR_INVALID_INPUT_ID;
3235 : }
3236 :
3237 : /* Ensure input ID matches and that input is active */
3238 3072998 : test();
3239 3072998 : IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3240 : {
3241 0 : return IVAS_ERR_INVALID_INPUT_ID;
3242 : }
3243 :
3244 : /* Validation done, set value via output parameter */
3245 3072998 : *ppInput = pInputBase;
3246 :
3247 3072998 : return IVAS_ERR_OK;
3248 : }
3249 :
3250 :
3251 630393 : static ivas_error getConstInputById(
3252 : IVAS_REND_CONST_HANDLE hIvasRend,
3253 : const IVAS_REND_InputId inputId,
3254 : const void **ppInput )
3255 : {
3256 : Word32 inputIndex;
3257 : IVAS_REND_AudioConfigType configType;
3258 : const input_base *pInputBase;
3259 :
3260 : /* Reverse makeInputId() */
3261 630393 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3262 630393 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3263 :
3264 : /* Validate values derived from input ID */
3265 630393 : IF( inputIndex < 0 )
3266 : {
3267 0 : return IVAS_ERR_INVALID_INPUT_ID;
3268 : }
3269 630393 : SWITCH( configType )
3270 : {
3271 406 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3272 406 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3273 : {
3274 0 : return IVAS_ERR_INVALID_INPUT_ID;
3275 : }
3276 406 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3277 406 : BREAK;
3278 359907 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3279 359907 : IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
3280 : {
3281 0 : return IVAS_ERR_INVALID_INPUT_ID;
3282 : }
3283 359907 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3284 359907 : BREAK;
3285 251881 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3286 251881 : IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
3287 : {
3288 0 : return IVAS_ERR_INVALID_INPUT_ID;
3289 : }
3290 251881 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3291 251881 : BREAK;
3292 18199 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3293 18199 : IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
3294 : {
3295 0 : return IVAS_ERR_INVALID_INPUT_ID;
3296 : }
3297 18199 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3298 18199 : BREAK;
3299 0 : default:
3300 0 : return IVAS_ERR_INVALID_INPUT_ID;
3301 : }
3302 :
3303 : /* Ensure input ID matches and that input is active */
3304 630393 : test();
3305 630393 : IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3306 : {
3307 0 : return IVAS_ERR_INVALID_INPUT_ID;
3308 : }
3309 :
3310 : /* Validation done, set value via output parameter */
3311 630393 : *ppInput = pInputBase;
3312 :
3313 630393 : return IVAS_ERR_OK;
3314 : }
3315 :
3316 953 : static ivas_error findFreeInputSlot_fx(
3317 : const void *inputs,
3318 : const Word32 inputStructSize,
3319 : const Word32 maxInputs,
3320 : Word32 *inputIndex )
3321 : {
3322 : /* Using a void pointer and a separately provided size is a hack for this function
3323 : to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
3324 : Assumptions:
3325 : - input_base is always the first member in the input struct
3326 : - provided size is correct
3327 : */
3328 :
3329 : Word32 i;
3330 : bool canAddInput;
3331 : const UWord8 *pByte;
3332 : const input_base *pInputBase;
3333 :
3334 953 : canAddInput = false;
3335 953 : move16();
3336 :
3337 : /* Find first unused input in array */
3338 1313 : FOR( ( i = 0, pByte = inputs ); i < maxInputs; ( ++i, pByte += inputStructSize ) )
3339 : {
3340 1313 : pInputBase = (const input_base *) pByte;
3341 :
3342 1313 : IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3343 : {
3344 953 : *inputIndex = i;
3345 953 : move32();
3346 953 : canAddInput = true;
3347 953 : move16();
3348 953 : BREAK;
3349 : }
3350 : }
3351 :
3352 953 : IF( !canAddInput )
3353 : {
3354 0 : return IVAS_ERR_TOO_MANY_INPUTS;
3355 : }
3356 :
3357 953 : return IVAS_ERR_OK;
3358 : }
3359 :
3360 :
3361 : /*-------------------------------------------------------------------*
3362 : * IVAS_REND_AddInput()
3363 : *
3364 : *
3365 : *-------------------------------------------------------------------*/
3366 953 : ivas_error IVAS_REND_AddInput_fx(
3367 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3368 : const AUDIO_CONFIG inConfig, /* i : audio config for a new input */
3369 : IVAS_REND_InputId *inputId /* o : ID of the new input */
3370 : )
3371 : {
3372 : ivas_error error;
3373 : Word32 maxNumInputsOfType;
3374 : void *inputsArray;
3375 : Word32 inputStructSize;
3376 : ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA * );
3377 : Word32 inputIndex;
3378 :
3379 : /* Validate function arguments */
3380 953 : test();
3381 953 : IF( hIvasRend == NULL || inputId == NULL )
3382 : {
3383 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3384 : }
3385 :
3386 :
3387 953 : SWITCH( getAudioConfigType( inConfig ) )
3388 : {
3389 406 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3390 406 : maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
3391 406 : inputsArray = hIvasRend->inputsIsm;
3392 406 : inputStructSize = sizeof( *hIvasRend->inputsIsm );
3393 406 : activateInput = setRendInputActiveIsm;
3394 406 : move32();
3395 406 : move32();
3396 406 : BREAK;
3397 372 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3398 372 : maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
3399 372 : inputsArray = hIvasRend->inputsMc;
3400 372 : inputStructSize = sizeof( *hIvasRend->inputsMc );
3401 372 : activateInput = setRendInputActiveMc;
3402 372 : move32();
3403 372 : move32();
3404 372 : BREAK;
3405 126 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3406 126 : maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
3407 126 : inputsArray = hIvasRend->inputsSba;
3408 126 : inputStructSize = sizeof( *hIvasRend->inputsSba );
3409 126 : activateInput = setRendInputActiveSba;
3410 126 : move32();
3411 126 : move32();
3412 126 : BREAK;
3413 49 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3414 49 : maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
3415 49 : inputsArray = hIvasRend->inputsMasa;
3416 49 : inputStructSize = sizeof( *hIvasRend->inputsMasa );
3417 49 : activateInput = setRendInputActiveMasa;
3418 49 : move32();
3419 49 : move32();
3420 49 : BREAK;
3421 0 : default:
3422 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
3423 : }
3424 :
3425 : /* Find first free input in array corresponding to input type */
3426 953 : IF( NE_32( ( error = findFreeInputSlot_fx( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ), IVAS_ERR_OK ) )
3427 : {
3428 0 : return error;
3429 : }
3430 :
3431 953 : *inputId = makeInputId( inConfig, inputIndex );
3432 953 : move16();
3433 :
3434 953 : IF( NE_32( ( error = activateInput( (UWord8 *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
3435 : {
3436 0 : return error;
3437 : }
3438 :
3439 953 : return IVAS_ERR_OK;
3440 : }
3441 :
3442 :
3443 : /*-------------------------------------------------------------------*
3444 : * IVAS_REND_ConfigureCustomInputLoudspeakerLayout()
3445 : *
3446 : *
3447 : * Note: this will reset any custom LFE routing set for the input
3448 : *-------------------------------------------------------------------*/
3449 105 : ivas_error IVAS_REND_ConfigureCustomInputLoudspeakerLayout(
3450 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3451 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3452 : const IVAS_CUSTOM_LS_DATA layout /* i : custom loudspeaker layout for input */
3453 : )
3454 : {
3455 : input_mc *inputMc;
3456 : ivas_error error;
3457 :
3458 : /* Validate function arguments */
3459 105 : IF( hIvasRend == NULL )
3460 : {
3461 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3462 : }
3463 :
3464 105 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
3465 : {
3466 0 : return error;
3467 : }
3468 :
3469 105 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputMc ) ), IVAS_ERR_OK ) )
3470 : {
3471 0 : return error;
3472 : }
3473 :
3474 105 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
3475 : {
3476 : /* Specifying details of custom speaker layout only makes sense if input config is set to custom speaker layout */
3477 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
3478 : }
3479 :
3480 : /* Re-initialize panning gains for the MC input, This includes re-initializing LFE handling
3481 : * for the new input layout, which means custom LFE handling is overwritten, if previously
3482 : * set for the MC input. */
3483 105 : inputMc->customLsInput = makeCustomLsSetup( layout );
3484 :
3485 105 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
3486 :
3487 105 : IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inputMc->base.inConfig, &inputMc->customLsInput ) ), IVAS_ERR_OK ) )
3488 : {
3489 0 : return error;
3490 : }
3491 :
3492 105 : test();
3493 105 : test();
3494 105 : IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) || EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) || EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
3495 : {
3496 36 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inputMc->base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, FALSE ) ), IVAS_ERR_OK ) )
3497 : {
3498 0 : return error;
3499 : }
3500 : }
3501 :
3502 105 : IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
3503 : {
3504 0 : return error;
3505 : }
3506 :
3507 105 : return IVAS_ERR_OK;
3508 : }
3509 :
3510 : /*-------------------------------------------------------------------*
3511 : * IVAS_REND_SetInputGain()
3512 : *
3513 : *
3514 : *-------------------------------------------------------------------*/
3515 953 : ivas_error IVAS_REND_SetInputGain_fx(
3516 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3517 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3518 : const Word32 gain /* i : linear gain (not in dB) Q30 */
3519 : )
3520 : {
3521 : input_base *inputBase;
3522 : ivas_error error;
3523 :
3524 : /* Validate function arguments */
3525 953 : IF( hIvasRend == NULL )
3526 : {
3527 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3528 : }
3529 :
3530 953 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3531 : {
3532 0 : return error;
3533 : }
3534 :
3535 953 : inputBase->gain_fx = gain;
3536 953 : move32();
3537 :
3538 953 : return IVAS_ERR_OK;
3539 : }
3540 :
3541 : /*-------------------------------------------------------------------*
3542 : * IVAS_REND_SetInputLfeMtx()
3543 : *
3544 : *
3545 : *-------------------------------------------------------------------*/
3546 0 : ivas_error IVAS_REND_SetInputLfeMtx_fx(
3547 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3548 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3549 : const IVAS_REND_LfePanMtx_fx *lfePanMtx /* i : LFE panning matrix */
3550 : )
3551 : {
3552 : Word16 i;
3553 : input_base *pInputBase;
3554 : input_mc *pInputMc;
3555 : ivas_error error;
3556 :
3557 : /* Validate function arguments */
3558 0 : IF( hIvasRend == NULL )
3559 : {
3560 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3561 : }
3562 :
3563 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
3564 : {
3565 0 : return error;
3566 : }
3567 :
3568 0 : IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
3569 : {
3570 : /* Custom LFE panning matrix only makes sense with channel-based input */
3571 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
3572 : }
3573 0 : pInputMc = (input_mc *) pInputBase;
3574 :
3575 : /* copy LFE panning matrix */
3576 0 : FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; i++ )
3577 : {
3578 0 : Copy32( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS );
3579 : }
3580 :
3581 0 : IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
3582 : {
3583 0 : return error;
3584 : }
3585 :
3586 0 : return IVAS_ERR_OK;
3587 : }
3588 :
3589 : /*-------------------------------------------------------------------*
3590 : * IVAS_REND_SetInputLfePos()
3591 : *
3592 : *
3593 : *-------------------------------------------------------------------*/
3594 :
3595 0 : ivas_error IVAS_REND_SetInputLfePos_fx(
3596 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3597 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3598 : const Word32 inputGain, /* i : Input gain to be applied to the LFE channel(s) Q31 */
3599 : const Word16 outputAzimuth, /* i : Output azimuth position Q0 */
3600 : const Word16 outputElevation /* i : Output elevation position Q0 */
3601 : )
3602 : {
3603 : input_base *pInputBase;
3604 : input_mc *pInputMc;
3605 : ivas_error error;
3606 :
3607 : /* Validate function arguments */
3608 0 : IF( hIvasRend == NULL )
3609 : {
3610 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3611 : }
3612 :
3613 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
3614 : {
3615 0 : return error;
3616 : }
3617 :
3618 0 : IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
3619 : {
3620 : /* Custom LFE routing only makes sense with channel-based input */
3621 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
3622 : }
3623 0 : pInputMc = (input_mc *) pInputBase;
3624 :
3625 0 : pInputMc->lfeRouting.pan_lfe = true;
3626 0 : move16();
3627 0 : pInputMc->lfeRouting.lfeInputGain_fx = inputGain; /* Q31 */
3628 0 : move32();
3629 0 : pInputMc->lfeRouting.lfeOutputAzimuth_fx = outputAzimuth; /* Q0 */
3630 0 : move16();
3631 0 : pInputMc->lfeRouting.lfeOutputElevation_fx = outputElevation; /* Q0 */
3632 0 : move16();
3633 :
3634 0 : IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
3635 : {
3636 0 : return error;
3637 : }
3638 :
3639 0 : return IVAS_ERR_OK;
3640 : }
3641 :
3642 : /*-------------------------------------------------------------------*
3643 : * IVAS_REND_RemoveInput()
3644 : *
3645 : *
3646 : *-------------------------------------------------------------------*/
3647 : /* ToDo; unused function */
3648 0 : ivas_error IVAS_REND_RemoveInput(
3649 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3650 : const IVAS_REND_InputId inputId /* i : ID of the input */
3651 : )
3652 : {
3653 : ivas_error error;
3654 : input_base *inputBase;
3655 :
3656 : /* Validate function arguments */
3657 0 : IF( hIvasRend == NULL )
3658 : {
3659 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3660 : }
3661 :
3662 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3663 : {
3664 0 : return error;
3665 : }
3666 :
3667 0 : SWITCH( getAudioConfigType( inputBase->inConfig ) )
3668 : {
3669 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3670 0 : clearInputIsm( (input_ism *) inputBase );
3671 0 : BREAK;
3672 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3673 0 : clearInputMc( (input_mc *) inputBase );
3674 0 : BREAK;
3675 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3676 0 : clearInputSba( (input_sba *) inputBase );
3677 0 : BREAK;
3678 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3679 0 : clearInputMasa( (input_masa *) inputBase );
3680 0 : BREAK;
3681 0 : default:
3682 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
3683 : }
3684 :
3685 0 : return IVAS_ERR_OK;
3686 : }
3687 :
3688 :
3689 : /*-------------------------------------------------------------------*
3690 : * IVAS_REND_GetInputNumChannels()
3691 : *
3692 : *
3693 : *-------------------------------------------------------------------*/
3694 630393 : ivas_error IVAS_REND_GetInputNumChannels(
3695 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
3696 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3697 : Word16 *numChannels /* o : number of channels of the input */
3698 : )
3699 : {
3700 : ivas_error error;
3701 : const input_base *pInput;
3702 :
3703 : /* Validate function arguments */
3704 630393 : test();
3705 630393 : IF( hIvasRend == NULL || numChannels == NULL )
3706 : {
3707 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3708 : }
3709 :
3710 630393 : IF( NE_32( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ), IVAS_ERR_OK ) )
3711 : {
3712 0 : return error;
3713 : }
3714 :
3715 630393 : IF( NE_32( ( error = getRendInputNumChannels( pInput, numChannels ) ), IVAS_ERR_OK ) )
3716 : {
3717 0 : return error;
3718 : }
3719 :
3720 630393 : return IVAS_ERR_OK;
3721 : }
3722 :
3723 : /*-------------------------------------------------------------------*
3724 : * IVAS_REND_GetNumAllObjects()
3725 : *
3726 : *
3727 : *-------------------------------------------------------------------*/
3728 406 : ivas_error IVAS_REND_GetNumAllObjects(
3729 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
3730 : Word16 *numChannels /* o : number of all objects */
3731 : )
3732 : {
3733 406 : test();
3734 406 : IF( hIvasRend == NULL || numChannels == NULL )
3735 : {
3736 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3737 : }
3738 :
3739 406 : test();
3740 406 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
3741 : {
3742 1 : *numChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
3743 1 : move16();
3744 : }
3745 :
3746 406 : return IVAS_ERR_OK;
3747 : }
3748 :
3749 : /*-------------------------------------------------------------------*
3750 : * IVAS_REND_GetDelay()
3751 : *
3752 : *
3753 : *-------------------------------------------------------------------*/
3754 0 : ivas_error IVAS_REND_GetDelay_fx(
3755 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
3756 : Word16 *nSamples, /* o : Renderer delay in samples */
3757 : Word32 *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
3758 : )
3759 : {
3760 : /* TODO tmu : this function only returns the maximum delay across all inputs
3761 : * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform)
3762 : */
3763 : Word16 i;
3764 : Word32 latency_ns;
3765 : Word32 max_latency_ns;
3766 :
3767 0 : Word32 timescale_by_ns[7] = { 0, 17180, 34360, 0, 68719, 0, 103079 };
3768 0 : move32();
3769 0 : move32();
3770 0 : move32();
3771 0 : move32();
3772 0 : move32();
3773 0 : move32();
3774 0 : move32();
3775 :
3776 : /* Validate function arguments */
3777 0 : test();
3778 0 : test();
3779 0 : IF( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
3780 : {
3781 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3782 : }
3783 :
3784 0 : *timeScale = hIvasRend->sampleRateOut;
3785 0 : move32();
3786 0 : assert( *timeScale == 8000 || *timeScale == 16000 || *timeScale == 32000 || *timeScale == 48000 );
3787 0 : *nSamples = 0;
3788 0 : move16();
3789 0 : max_latency_ns = 0;
3790 0 : move32();
3791 :
3792 : /* Compute the maximum delay across all inputs */
3793 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
3794 : {
3795 0 : IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3796 : {
3797 0 : IF( hIvasRend->inputsIsm[i].crendWrapper != NULL )
3798 : {
3799 0 : latency_ns = hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns;
3800 : }
3801 : ELSE
3802 : {
3803 0 : latency_ns = 0;
3804 : }
3805 0 : move32();
3806 :
3807 0 : latency_ns = L_max( latency_ns, hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns );
3808 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
3809 : }
3810 : }
3811 :
3812 0 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
3813 : {
3814 0 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3815 : {
3816 0 : IF( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) )
3817 : {
3818 0 : latency_ns = hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns;
3819 : }
3820 : ELSE
3821 : {
3822 0 : latency_ns = 0;
3823 : }
3824 :
3825 0 : move32();
3826 :
3827 0 : latency_ns = L_max( latency_ns, hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns );
3828 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
3829 : }
3830 : }
3831 :
3832 0 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
3833 : {
3834 0 : IF( NE_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3835 : {
3836 : {
3837 0 : IF( hIvasRend->inputsSba[i].crendWrapper != NULL )
3838 : {
3839 0 : latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
3840 : }
3841 : ELSE
3842 : {
3843 0 : latency_ns = 0;
3844 : }
3845 0 : move32();
3846 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
3847 : }
3848 : }
3849 : }
3850 :
3851 :
3852 0 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
3853 : {
3854 0 : IF( NE_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3855 : {
3856 0 : latency_ns = (Word32) ( IVAS_FB_DEC_DELAY_NS );
3857 0 : move32();
3858 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
3859 : }
3860 : }
3861 :
3862 :
3863 : //*nSamples = (Word16) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
3864 0 : Word32 temp = Mpy_32_32( *timeScale, 268436 ); // Q0 + Q31 - Q31 -> Q0, ( 1 / 8000 ) * 2 ^ 31
3865 0 : *nSamples = extract_l( Mpy_32_32_r( max_latency_ns, timescale_by_ns[temp] ) );
3866 0 : move16();
3867 :
3868 0 : return IVAS_ERR_OK;
3869 : }
3870 :
3871 : /*-------------------------------------------------------------------*
3872 : * IVAS_REND_FeedInputAudio()
3873 : *
3874 : *
3875 : *-------------------------------------------------------------------*/
3876 :
3877 1847090 : ivas_error IVAS_REND_FeedInputAudio_fx(
3878 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3879 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3880 : const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */
3881 : )
3882 : {
3883 : ivas_error error;
3884 : input_base *inputBase;
3885 : Word16 numInputChannels;
3886 :
3887 : /* Validate function arguments */
3888 1847090 : test();
3889 1847090 : IF( hIvasRend == NULL || inputAudio.data_fx == NULL )
3890 : {
3891 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3892 : }
3893 :
3894 1847090 : test();
3895 1847090 : IF( inputAudio.config.numSamplesPerChannel <= 0 || LT_16( MAX_BUFFER_LENGTH_PER_CHANNEL, inputAudio.config.numSamplesPerChannel ) )
3896 : {
3897 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
3898 : }
3899 :
3900 1847090 : test();
3901 1847090 : IF( inputAudio.config.numChannels <= 0 || LT_16( MAX_INPUT_CHANNELS, inputAudio.config.numChannels ) )
3902 : {
3903 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
3904 : }
3905 :
3906 1847090 : test();
3907 1847090 : move32(); // move added for typecasting
3908 1847090 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
3909 : NE_32( L_mult0( inputAudio.config.numSamplesPerChannel, 1000 ), (Word32) W_mult0_32_32( L_mult0( BINAURAL_RENDERING_FRAME_SIZE_MS, hIvasRend->num_subframes ), hIvasRend->sampleRateOut ) ) )
3910 : {
3911 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
3912 : }
3913 :
3914 1847090 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3915 : {
3916 0 : return error;
3917 : }
3918 :
3919 1847090 : IF( NE_32( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ), IVAS_ERR_OK ) )
3920 : {
3921 0 : return error;
3922 : }
3923 1847090 : test();
3924 1847090 : test();
3925 1847090 : IF( ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) ) && EQ_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
3926 : {
3927 150 : numInputChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
3928 150 : move16();
3929 : }
3930 :
3931 1847090 : IF( NE_16( numInputChannels, inputAudio.config.numChannels ) )
3932 : {
3933 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
3934 : }
3935 :
3936 1847090 : inputBase->inputBuffer.config = inputAudio.config;
3937 :
3938 1847090 : MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
3939 :
3940 1847090 : inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel;
3941 1847090 : move32();
3942 :
3943 1847090 : return IVAS_ERR_OK;
3944 : }
3945 :
3946 :
3947 : /*-------------------------------------------------------------------*
3948 : * IVAS_REND_FeedInputObjectMetadata()
3949 : *
3950 : *
3951 : *-------------------------------------------------------------------*/
3952 :
3953 1217500 : ivas_error IVAS_REND_FeedInputObjectMetadata(
3954 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3955 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3956 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
3957 : )
3958 : {
3959 : input_base *inputBase;
3960 : input_ism *inputIsm;
3961 : ivas_error error;
3962 :
3963 : /* Validate function arguments */
3964 1217500 : IF( hIvasRend == NULL )
3965 : {
3966 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3967 : }
3968 :
3969 1217500 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3970 : {
3971 0 : return error;
3972 : }
3973 :
3974 1217500 : IF( NE_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
3975 : {
3976 : /* Object metadata should only be fed for object inputs */
3977 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
3978 : }
3979 :
3980 1217500 : inputIsm = (input_ism *) inputBase;
3981 1217500 : inputIsm->previousPos = inputIsm->currentPos;
3982 1217500 : inputIsm->currentPos = objectPosition;
3983 :
3984 1217500 : return IVAS_ERR_OK;
3985 : }
3986 :
3987 :
3988 : /*-------------------------------------------------------------------*
3989 : * IVAS_REND_FeedInputObjectMetadataToOMasa()
3990 : *
3991 : *
3992 : *-------------------------------------------------------------------*/
3993 600 : ivas_error IVAS_REND_FeedInputObjectMetadataToOMasa(
3994 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3995 : const Word16 inputIndex, /* i : Index of the input */
3996 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
3997 : )
3998 : {
3999 : /* Validate function arguments */
4000 600 : IF( hIvasRend == NULL )
4001 : {
4002 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4003 : }
4004 :
4005 : /* Set position to OMasa struct */
4006 600 : hIvasRend->inputsIsm->hOMasa->ism_azimuth_fx[inputIndex] = objectPosition.azimuth_fx;
4007 600 : move32();
4008 600 : hIvasRend->inputsIsm->hOMasa->ism_elevation_fx[inputIndex] = objectPosition.elevation_fx;
4009 600 : move32();
4010 :
4011 600 : return IVAS_ERR_OK;
4012 : }
4013 :
4014 : /*-------------------------------------------------------------------*
4015 : * IVAS_REND_FeedInputMasaMetadata()
4016 : *
4017 : *
4018 : *-------------------------------------------------------------------*/
4019 :
4020 7350 : ivas_error IVAS_REND_FeedInputMasaMetadata(
4021 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4022 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4023 : IVAS_MASA_METADATA_HANDLE masaMetadata /* i : MASA metadata frame */
4024 : )
4025 : {
4026 : ivas_error error;
4027 : input_base *inputBase;
4028 : input_masa *inputMasa;
4029 :
4030 : /* Validate function arguments */
4031 7350 : IF( hIvasRend == NULL )
4032 : {
4033 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4034 : }
4035 :
4036 7350 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4037 : {
4038 0 : return error;
4039 : }
4040 :
4041 7350 : IF( NE_32( getAudioConfigType( inputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
4042 : {
4043 : /* MASA metadata should only be fed for MASA inputs */
4044 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4045 : }
4046 :
4047 7350 : inputMasa = (input_masa *) inputBase;
4048 7350 : inputMasa->masaMetadata = *masaMetadata;
4049 7350 : inputMasa->metadataHasBeenFed = true;
4050 7350 : move16();
4051 :
4052 7350 : return IVAS_ERR_OK;
4053 : }
4054 :
4055 :
4056 : /*-------------------------------------------------------------------*
4057 : * IVAS_REND_InitConfig()
4058 : *
4059 : *
4060 : *-------------------------------------------------------------------*/
4061 658 : ivas_error IVAS_REND_InitConfig(
4062 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4063 : const AUDIO_CONFIG outAudioConfig /* i : output audioConfig */
4064 : )
4065 : {
4066 : ivas_error error;
4067 : bool rendererConfigEnabled;
4068 :
4069 658 : rendererConfigEnabled = EQ_32( getAudioConfigType( outAudioConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
4070 :
4071 658 : IF( rendererConfigEnabled )
4072 : {
4073 188 : hIvasRend->rendererConfigEnabled = 1;
4074 188 : move16();
4075 : }
4076 : ELSE
4077 : {
4078 470 : hIvasRend->rendererConfigEnabled = 0;
4079 470 : move16();
4080 : }
4081 :
4082 658 : IF( rendererConfigEnabled )
4083 : {
4084 188 : IF( NE_32( ( error = ivas_render_config_open( &( hIvasRend->hRendererConfig ) ) ), IVAS_ERR_OK ) )
4085 : {
4086 0 : return error;
4087 : }
4088 188 : IF( NE_32( ( error = ivas_render_config_init_from_rom_fx( &hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
4089 : {
4090 0 : return error;
4091 : }
4092 : }
4093 : ELSE
4094 : {
4095 470 : hIvasRend->hRendererConfig = NULL;
4096 : }
4097 :
4098 658 : return IVAS_ERR_OK;
4099 : }
4100 :
4101 : /*-------------------------------------------------------------------*
4102 : * IVAS_REND_GetRenderConfig()
4103 : *
4104 : *
4105 : *-------------------------------------------------------------------*/
4106 :
4107 0 : Word16 IVAS_REND_GetRenderConfig(
4108 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS decoder handle */
4109 : const IVAS_RENDER_CONFIG_HANDLE hRCout /* o : Render configuration handle */
4110 : )
4111 : {
4112 : RENDER_CONFIG_HANDLE hRCin;
4113 :
4114 0 : test();
4115 0 : test();
4116 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL || hRCout == NULL )
4117 : {
4118 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4119 : }
4120 :
4121 0 : hRCin = hIvasRend->hRendererConfig;
4122 0 : hRCout->roomAcoustics.override = hRCin->roomAcoustics.override;
4123 0 : hRCout->roomAcoustics.nBands = hRCin->roomAcoustics.nBands;
4124 0 : hRCout->roomAcoustics.acousticPreDelay_fx = hRCin->roomAcoustics.acousticPreDelay_fx;
4125 0 : hRCout->roomAcoustics.inputPreDelay_fx = hRCin->roomAcoustics.inputPreDelay_fx;
4126 0 : Copy( hRCin->directivity_fx, hRCout->directivity_fx, 3 * MAX_NUM_OBJECTS );
4127 0 : move16();
4128 0 : move16();
4129 0 : move32();
4130 0 : move32();
4131 :
4132 0 : Copy32( hRCin->roomAcoustics.pFc_input_fx, hRCout->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
4133 0 : Copy32( hRCin->roomAcoustics.pAcoustic_rt60_fx, hRCout->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
4134 0 : Copy32( hRCin->roomAcoustics.pAcoustic_dsr_fx, hRCout->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
4135 :
4136 :
4137 0 : hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er;
4138 0 : hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
4139 0 : move16();
4140 0 : move32();
4141 :
4142 0 : return IVAS_ERR_OK;
4143 : }
4144 :
4145 :
4146 : /*-------------------------------------------------------------------*
4147 : * IVAS_REND_FeedRenderConfig()
4148 : *
4149 : *
4150 : *-------------------------------------------------------------------*/
4151 :
4152 0 : Word16 IVAS_REND_FeedRenderConfig(
4153 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS decoder handle */
4154 : const IVAS_RENDER_CONFIG_DATA renderConfig /* i : Render configuration struct */
4155 : )
4156 : {
4157 : RENDER_CONFIG_HANDLE hRenderConfig;
4158 :
4159 0 : test();
4160 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
4161 : {
4162 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4163 : }
4164 0 : hRenderConfig = hIvasRend->hRendererConfig;
4165 :
4166 0 : hRenderConfig->roomAcoustics.override = renderConfig.roomAcoustics.override;
4167 0 : move16();
4168 0 : hRenderConfig->roomAcoustics.nBands = renderConfig.roomAcoustics.nBands;
4169 0 : move16();
4170 0 : hRenderConfig->roomAcoustics.acousticPreDelay_fx = renderConfig.roomAcoustics.acousticPreDelay_fx;
4171 0 : move32();
4172 0 : hRenderConfig->roomAcoustics.inputPreDelay_fx = renderConfig.roomAcoustics.inputPreDelay_fx;
4173 0 : move32();
4174 0 : Copy32( renderConfig.roomAcoustics.pFc_input_fx, hRenderConfig->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
4175 0 : Copy32( renderConfig.roomAcoustics.pAcoustic_rt60_fx, hRenderConfig->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
4176 0 : Copy32( renderConfig.roomAcoustics.pAcoustic_dsr_fx, hRenderConfig->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
4177 0 : Copy( renderConfig.directivity_fx, hRenderConfig->directivity_fx, 3 * MAX_NUM_OBJECTS );
4178 :
4179 0 : hRenderConfig->roomAcoustics.use_er = 0;
4180 0 : move16();
4181 0 : IF( EQ_16( renderConfig.roomAcoustics.use_er, 1 ) )
4182 : {
4183 0 : hRenderConfig->roomAcoustics.use_er = renderConfig.roomAcoustics.use_er;
4184 0 : move16();
4185 0 : hRenderConfig->roomAcoustics.lowComplexity = renderConfig.roomAcoustics.lowComplexity;
4186 0 : move32();
4187 0 : hRenderConfig->roomAcoustics.dimensions = renderConfig.roomAcoustics.dimensions;
4188 0 : hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.roomAcoustics.ListenerOrigin;
4189 :
4190 0 : Copy32( renderConfig.roomAcoustics.AbsCoeff_fx, hRenderConfig->roomAcoustics.AbsCoeff_fx, IVAS_ROOM_ABS_COEFF );
4191 : }
4192 :
4193 :
4194 0 : return IVAS_ERR_OK;
4195 : }
4196 :
4197 : /*-------------------------------------------------------------------*
4198 : * IVAS_REND_SetHeadRotation()
4199 : *
4200 : *
4201 : *-------------------------------------------------------------------*/
4202 288060 : ivas_error IVAS_REND_SetHeadRotation(
4203 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4204 : const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */
4205 : const IVAS_VECTOR3 Pos, /* i : listener positions for next rendering call */
4206 : const Word16 sf_idx /* i : subframe index */
4207 : )
4208 : {
4209 : Word16 i;
4210 : IVAS_QUATERNION rotQuat;
4211 : ivas_error error;
4212 :
4213 : /* Validate function arguments */
4214 288060 : IF( hIvasRend == NULL )
4215 : {
4216 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4217 : }
4218 :
4219 288060 : IF( NE_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
4220 : {
4221 : /* Head rotation can be set only with binaural output */
4222 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
4223 : }
4224 :
4225 288060 : hIvasRend->headRotData.headRotEnabled = 1;
4226 288060 : move16();
4227 :
4228 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
4229 576120 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
4230 : {
4231 288060 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4232 : {
4233 69615 : IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, TRUE ) ), IVAS_ERR_OK ) )
4234 : {
4235 0 : return error;
4236 : }
4237 : }
4238 : }
4239 :
4240 : /* check for Euler angle signaling */
4241 288060 : IF( EQ_32( headRot.w_fx, -1610612736 /* -3.0f in Q29 */ ) )
4242 : {
4243 0 : Euler2Quat_fx( deg2rad_fx( headRot.x_fx ), deg2rad_fx( headRot.y_fx ), deg2rad_fx( headRot.z_fx ), &rotQuat );
4244 : }
4245 : ELSE
4246 : {
4247 288060 : rotQuat = headRot;
4248 : }
4249 :
4250 288060 : Word32 updateRate_fx = 1677721600; // value is 200 in Q23
4251 288060 : rotQuat.w_fx = L_shl( rotQuat.w_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
4252 288060 : rotQuat.x_fx = L_shl( rotQuat.x_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
4253 288060 : rotQuat.y_fx = L_shl( rotQuat.y_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
4254 288060 : rotQuat.z_fx = L_shl( rotQuat.z_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
4255 :
4256 288060 : move32();
4257 288060 : move32();
4258 288060 : move32();
4259 288060 : move32();
4260 :
4261 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
4262 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
4263 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
4264 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
4265 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
4266 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
4267 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
4268 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
4269 :
4270 288060 : move32();
4271 288060 : move32();
4272 288060 : move32();
4273 288060 : move32();
4274 288060 : move32();
4275 288060 : move32();
4276 288060 : move32();
4277 288060 : move32();
4278 :
4279 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.q_fact = Q29;
4280 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact = Q29;
4281 288060 : move16();
4282 288060 : move16();
4283 288060 : rotQuat.q_fact = Q29;
4284 :
4285 288060 : move16();
4286 288060 : IF( NE_32( ( error = ivas_orient_trk_Process_fx( hIvasRend->headRotData.hOrientationTracker, rotQuat, updateRate_fx, &hIvasRend->headRotData.headPositions[sf_idx] ) ), IVAS_ERR_OK ) )
4287 : {
4288 0 : return error;
4289 : }
4290 :
4291 288060 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
4292 :
4293 288060 : return IVAS_ERR_OK;
4294 : }
4295 :
4296 : /*-------------------------------------------------------------------*
4297 : * IVAS_REND_DisableHeadRotation()
4298 : *
4299 : *
4300 : *-------------------------------------------------------------------*/
4301 934116 : ivas_error IVAS_REND_DisableHeadRotation(
4302 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
4303 : )
4304 : {
4305 : Word16 i;
4306 : ivas_error error;
4307 :
4308 : /* Validate function arguments */
4309 934116 : IF( hIvasRend == NULL )
4310 : {
4311 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4312 : }
4313 :
4314 934116 : hIvasRend->headRotData.headRotEnabled = 0;
4315 934116 : move32();
4316 :
4317 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
4318 934116 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
4319 : {
4320 360048 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
4321 : {
4322 180024 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4323 : {
4324 43506 : IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, TRUE ) ), IVAS_ERR_OK ) )
4325 : {
4326 :
4327 0 : return error;
4328 : }
4329 : }
4330 : }
4331 : }
4332 :
4333 934116 : return IVAS_ERR_OK;
4334 : }
4335 :
4336 : /*-------------------------------------------------------------------*
4337 : * IVAS_REND_SetOrientationTrackingMode()
4338 : *
4339 : *
4340 : *-------------------------------------------------------------------*/
4341 :
4342 658 : ivas_error IVAS_REND_SetOrientationTrackingMode(
4343 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4344 : const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i : Head orientation tracking type */
4345 : )
4346 : {
4347 658 : return ivas_orient_trk_SetTrackingType_fx( hIvasRend->headRotData.hOrientationTracker, orientation_tracking );
4348 : }
4349 :
4350 :
4351 : /*-------------------------------------------------------------------*
4352 : * IVAS_REND_SetReferenceRotation()
4353 : *
4354 : *
4355 : *-------------------------------------------------------------------*/
4356 :
4357 0 : ivas_error IVAS_REND_SetReferenceRotation(
4358 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4359 : const IVAS_QUATERNION refRot /* i : Reference rotation */
4360 : )
4361 : {
4362 : ivas_error error;
4363 :
4364 : /* Validate function arguments */
4365 0 : IF( hIvasRend == NULL )
4366 : {
4367 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4368 : }
4369 :
4370 0 : error = ivas_orient_trk_SetReferenceRotation_fx( hIvasRend->headRotData.hOrientationTracker, refRot );
4371 :
4372 0 : IF( NE_32( error, IVAS_ERR_OK ) )
4373 : {
4374 :
4375 0 : return error;
4376 : }
4377 0 : return IVAS_ERR_OK;
4378 : }
4379 :
4380 :
4381 : /*-------------------------------------------------------------------*
4382 : * IVAS_REND_GetMainOrientation()
4383 : *
4384 : *
4385 : *-------------------------------------------------------------------*/
4386 :
4387 :
4388 : /*-------------------------------------------------------------------*
4389 : * IVAS_REND_GetTrackedRotation()
4390 : *
4391 : *
4392 : *-------------------------------------------------------------------*/
4393 :
4394 :
4395 : /*---------------------------------------------------------------------*
4396 : * IVAS_REND_SetReferenceVector( )
4397 : *
4398 : * Sets a reference vector spanning from listenerPos to refPos. Only
4399 : * available in OTR_TRACKING_REF_VEC and OTR_TRACKING_REF_VEC_LEV modes.
4400 : *---------------------------------------------------------------------*/
4401 :
4402 0 : ivas_error IVAS_REND_SetReferenceVector(
4403 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4404 : const IVAS_VECTOR3 listenerPos, /* i : Listener position */
4405 : const IVAS_VECTOR3 refPos /* i : Reference position */
4406 : )
4407 : {
4408 0 : test();
4409 0 : IF( hIvasRend == NULL || hIvasRend->headRotData.hOrientationTracker == NULL )
4410 : {
4411 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4412 : }
4413 :
4414 0 : return ivas_orient_trk_SetReferenceVector_fx( hIvasRend->headRotData.hOrientationTracker, listenerPos, refPos );
4415 : }
4416 :
4417 : /*---------------------------------------------------------------------*
4418 : * IVAS_REND_SetExternalOrientation()
4419 : *
4420 : *
4421 : *---------------------------------------------------------------------*/
4422 :
4423 0 : ivas_error IVAS_REND_SetExternalOrientation(
4424 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4425 : IVAS_QUATERNION *orientation, /* i : external orientation data */
4426 : Word8 enableHeadRotation, /* i : flag to enable head rotation for this frame */
4427 : Word8 enableExternalOrientation, /* i : flag to enable external orientation for this frame */
4428 : Word8 enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */
4429 : Word16 numFramesToTargetOrientation, /* i : number of frames until target orientation is reached */
4430 : const Word16 sf_idx /* i : subframe index */
4431 : )
4432 : {
4433 : /* Validate function arguments */
4434 0 : test();
4435 0 : IF( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL )
4436 : {
4437 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4438 : }
4439 :
4440 0 : IF( orientation == NULL )
4441 : {
4442 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = 0;
4443 0 : move16();
4444 : }
4445 : ELSE
4446 : {
4447 0 : QuaternionInverse_fx( *orientation, &hIvasRend->hExternalOrientationData->Quaternions[sf_idx] );
4448 :
4449 0 : hIvasRend->hExternalOrientationData->enableHeadRotation[sf_idx] = enableHeadRotation;
4450 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = enableExternalOrientation;
4451 0 : hIvasRend->hExternalOrientationData->enableRotationInterpolation[sf_idx] = enableRotationInterpolation;
4452 0 : hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[sf_idx] = numFramesToTargetOrientation;
4453 0 : move16();
4454 0 : move16();
4455 0 : move16();
4456 0 : move16();
4457 : }
4458 :
4459 0 : return IVAS_ERR_OK;
4460 : }
4461 :
4462 : /*---------------------------------------------------------------------*
4463 : * IVAS_REND_CombineHeadAndExternalOrientation()
4464 : *
4465 : *
4466 : *---------------------------------------------------------------------*/
4467 :
4468 1114140 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
4469 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
4470 : )
4471 : {
4472 1114140 : IF( hIvasRend == NULL )
4473 : {
4474 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4475 : }
4476 1114140 : ivas_error error_type = combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
4477 1114140 : return error_type;
4478 : }
4479 :
4480 :
4481 : /*---------------------------------------------------------------------*
4482 : * IVAS_REND_GetCombinedOrientation()
4483 : *
4484 : *
4485 : *---------------------------------------------------------------------*/
4486 :
4487 :
4488 : /*-------------------------------------------------------------------*
4489 : * Local functions
4490 : *-------------------------------------------------------------------*/
4491 : /* Take one channel from input buffer and copy it to each channel
4492 : in output buffer, with different gain applied per output channel.
4493 : This function takes 2 gain vectors - one for the beginning and one
4494 : for the end of the buffer. Gain values are lineraly interpolated
4495 : for all samples in between. */
4496 : /* Take one channel from input buffer and copy it to each channel
4497 : in output buffer, with different gain applied per output channel.
4498 : This function takes 2 gain vectors - one for the beginning and one
4499 : for the end of the buffer. Gain values are lineraly interpolated
4500 : for all samples in between. */
4501 5252295 : static void renderBufferChannelLerp_fx(
4502 : const IVAS_REND_AudioBuffer inAudio,
4503 : const Word32 inChannelIdx,
4504 : const Word32 *const gainsCurrent, /* Q31 */
4505 : const Word32 *const gainsPrev, /* Q31 */
4506 : IVAS_REND_AudioBuffer outAudio )
4507 : {
4508 : const Word32 *inSmpl;
4509 : Word32 *outSmpl;
4510 : Word32 fadeIn;
4511 : Word32 fadeOut;
4512 : Word32 i;
4513 : const Word32 *lastInSmpl;
4514 : Word16 outChnlIdx;
4515 : Word32 currentGain; /* Q31 */
4516 : Word32 previousGain; /* Q31 */
4517 :
4518 : /* Pointer to behind last input sample */
4519 5252295 : lastInSmpl = getSmplPtr_fx( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
4520 :
4521 50814875 : FOR( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
4522 : {
4523 45562580 : currentGain = gainsCurrent[outChnlIdx];
4524 45562580 : move32();
4525 45562580 : if ( gainsPrev == NULL )
4526 : {
4527 42520688 : previousGain = 0;
4528 42520688 : move32();
4529 : }
4530 : else
4531 : {
4532 3041892 : previousGain = gainsPrev[outChnlIdx];
4533 3041892 : move32();
4534 : }
4535 :
4536 : /* Process current output channel only if applying non-zero gains */
4537 45562580 : test();
4538 45562580 : test();
4539 45562580 : IF( GT_32( L_abs( currentGain ), EPSILON_FX ) || ( gainsPrev != NULL && GT_32( L_abs( previousGain ), EPSILON_FX ) ) )
4540 : {
4541 : /* Reset input pointer to the beginning of input channel */
4542 27002745 : inSmpl = getSmplPtr_fx( inAudio, inChannelIdx, 0 );
4543 :
4544 : /* Set output pointer to first output channel sample */
4545 27002745 : outSmpl = getSmplPtr_fx( outAudio, outChnlIdx, 0 );
4546 :
4547 27002745 : test();
4548 27002745 : IF( gainsPrev == NULL || LE_32( L_abs( L_sub( L_shr( previousGain, 1 ), L_shr( currentGain, 1 ) ) ), EPSILON_FX ) )
4549 : {
4550 : /* If no interpolation from previous frame, apply current gain */
4551 : DO
4552 : {
4553 10022454000 : *outSmpl = L_add( Mpy_32_32( currentGain, ( *inSmpl ) ), *outSmpl );
4554 10022454000 : move32();
4555 10022454000 : ++outSmpl;
4556 10022454000 : ++inSmpl;
4557 : }
4558 10022454000 : WHILE( inSmpl != lastInSmpl );
4559 : }
4560 : ELSE
4561 : {
4562 1864869 : i = 0;
4563 1864869 : Word32 tmp = Q31_BY_SUB_FRAME_240;
4564 1864869 : Word32 tmp1 = 239; /* L_SUBFRAME_48k - 1 */
4565 1864869 : move32();
4566 1864869 : move32();
4567 1864869 : move32();
4568 1864869 : SWITCH( outAudio.config.numSamplesPerChannel )
4569 : {
4570 919770 : case NUM_SAMPLES_960:
4571 919770 : tmp = Q31_BY_NUM_SAMPLES_960;
4572 919770 : tmp1 = 959; /* NUM_SAMPLES_960 - 1 */
4573 919770 : move32();
4574 919770 : move32();
4575 919770 : BREAK;
4576 0 : case NUM_SAMPLES_720:
4577 0 : tmp = Q31_BY_NUM_SAMPLES_720;
4578 0 : tmp1 = 719; /* NUM_SAMPLES_720 - 1 */
4579 0 : move32();
4580 0 : move32();
4581 0 : BREAK;
4582 0 : case NUM_SAMPLES_320:
4583 0 : tmp = Q31_BY_NUM_SAMPLES_320;
4584 0 : tmp1 = 319; /* NUM_SAMPLES_320 - 1 */
4585 0 : move32();
4586 0 : move32();
4587 0 : BREAK;
4588 0 : case NUM_SAMPLES_160:
4589 0 : tmp = Q31_BY_NUM_SAMPLES_160;
4590 0 : tmp1 = 159; /* NUM_SAMPLES_160 - 1 */
4591 0 : move32();
4592 0 : move32();
4593 0 : BREAK;
4594 945099 : case L_SUBFRAME_48k:
4595 945099 : tmp = Q31_BY_SUB_FRAME_240;
4596 945099 : tmp1 = 239; /* L_SUBFRAME_48k - 1 */
4597 945099 : move32();
4598 945099 : move32();
4599 945099 : BREAK;
4600 0 : case L_SUBFRAME_32k:
4601 0 : tmp = Q31_BY_SUB_FRAME_180;
4602 0 : tmp1 = 179; /* L_SUBFRAME_32k - 1 */
4603 0 : move32();
4604 0 : move32();
4605 0 : BREAK;
4606 0 : case L_SUBFRAME_16k:
4607 0 : tmp = Q31_BY_SUB_FRAME_80;
4608 0 : tmp1 = 79; /* L_SUBFRAME_16k - 1 */
4609 0 : move32();
4610 0 : move32();
4611 0 : BREAK;
4612 0 : case L_SUBFRAME_8k:
4613 0 : tmp = Q31_BY_SUB_FRAME_40;
4614 0 : tmp1 = 39; /* L_SUBFRAME_8k - 1 */
4615 0 : move32();
4616 0 : move32();
4617 0 : BREAK;
4618 0 : default:
4619 0 : BREAK;
4620 : }
4621 : /* Otherwise use weighted average between previous and current gain */
4622 1107938091 : DO
4623 : {
4624 1109802960 : IF( EQ_32( i, tmp1 ) )
4625 : {
4626 1864869 : fadeIn = ONE_IN_Q31;
4627 1864869 : move32();
4628 : }
4629 : ELSE
4630 : {
4631 1107938091 : fadeIn = UL_Mpy_32_32( i, tmp );
4632 : }
4633 1109802960 : fadeOut = L_sub( ONE_IN_Q31, fadeIn );
4634 :
4635 1109802960 : *outSmpl = L_add( Mpy_32_32( L_add( Mpy_32_32( fadeIn, currentGain ), Mpy_32_32( fadeOut, previousGain ) ), ( *inSmpl ) ), *outSmpl );
4636 1109802960 : move32();
4637 1109802960 : ++outSmpl;
4638 1109802960 : ++inSmpl;
4639 1109802960 : ++i;
4640 : }
4641 1109802960 : WHILE( inSmpl != lastInSmpl );
4642 : }
4643 : }
4644 : }
4645 :
4646 5252295 : return;
4647 : }
4648 : /* Take one channel from input buffer and copy it to each channel
4649 : in output buffer, with different gain applied per output channel */
4650 4334795 : static void renderBufferChannel_fx(
4651 : const IVAS_REND_AudioBuffer inAudio,
4652 : const Word32 inChannelIdx,
4653 : const Word32 *const outputGains, /* Q31 */
4654 : IVAS_REND_AudioBuffer outAudio )
4655 : {
4656 4334795 : renderBufferChannelLerp_fx( inAudio, inChannelIdx, outputGains, NULL, outAudio );
4657 :
4658 4334795 : return;
4659 : }
4660 :
4661 70522 : static ivas_error chooseCrossfade_fx(
4662 : const IVAS_REND_HeadRotData *headRotData,
4663 : const Word32 **pCrossfade /* Q31 */ )
4664 : {
4665 70522 : *pCrossfade = headRotData->crossfade_fx;
4666 :
4667 70522 : return IVAS_ERR_OK;
4668 : }
4669 :
4670 :
4671 25504 : static ivas_error rotateFrameMc_fx(
4672 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
4673 : AUDIO_CONFIG inConfig, /* i : Input Audio config */
4674 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs, /* i : Input Custom LS setup */
4675 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
4676 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
4677 : rotation_gains_Word32 gains_prev, /* i/o: Previous frame rotation gains */
4678 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
4679 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
4680 : )
4681 : {
4682 : Word16 i;
4683 : Word16 j;
4684 : const Word32 *crossfade; /* Q31 */
4685 : Word16 num_subframes;
4686 : Word16 subframe_idx, subframe_len;
4687 : Word32 azimuth_fx, elevation_fx; /* Q22 */
4688 : Word16 is_planar_setup, lfe_idx;
4689 : Word16 nchan;
4690 : Word16 ch_in, ch_out;
4691 : Word16 ch_in_woLFE, ch_out_woLFE;
4692 25504 : Word32 *readPtr, *writePtr = NULL;
4693 : const Word32 *ls_azimuth, *ls_elevation;
4694 : rotation_matrix_fx Rmat_fx;
4695 : rotation_gains_Word32 gains;
4696 : Word32 tmp_gains[MAX_INPUT_CHANNELS]; /* Q30 */
4697 : ivas_error error;
4698 25504 : push_wmops( "rotateFrameMc_fx" );
4699 25504 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
4700 : {
4701 0 : return error;
4702 : }
4703 25504 : IF( ( hCombinedOrientationData != NULL ) )
4704 : {
4705 25504 : num_subframes = ( *hCombinedOrientationData )->num_subframes;
4706 : }
4707 : ELSE
4708 : {
4709 0 : num_subframes = MAX_PARAM_SPATIAL_SUBFRAMES;
4710 : }
4711 25504 : move16();
4712 :
4713 25504 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
4714 : {
4715 12500 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ), IVAS_ERR_OK ) )
4716 : {
4717 0 : return error;
4718 : }
4719 : }
4720 : ELSE
4721 : {
4722 13004 : nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe );
4723 : }
4724 :
4725 25504 : IF( NE_32( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ), IVAS_ERR_OK ) )
4726 : {
4727 0 : return error;
4728 : }
4729 :
4730 : /* initialize gains to passthrough */
4731 319068 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
4732 : {
4733 293564 : set32_fx( gains[ch_in], 0, nchan );
4734 293564 : gains[ch_in][ch_in] = ONE_IN_Q30;
4735 293564 : move32();
4736 : }
4737 :
4738 : /* subframe loop */
4739 : Word16 tmp_e;
4740 25504 : Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e );
4741 25504 : tmp = shr( tmp, negate( add( 1, tmp_e ) ) );
4742 25504 : subframe_len = tmp;
4743 25504 : move16();
4744 :
4745 66314 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
4746 : {
4747 163240 : FOR( i = 0; i < 3; i++ )
4748 : {
4749 122430 : IF( hCombinedOrientationData != NULL )
4750 : {
4751 489720 : FOR( j = 0; j < 3; j++ )
4752 : {
4753 367290 : Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
4754 367290 : move32();
4755 : }
4756 : }
4757 : ELSE
4758 : {
4759 : /* Set to identity */
4760 0 : set32_fx( Rmat_fx[i], 0, 3 );
4761 0 : Rmat_fx[i][i] = ONE_IN_Q30;
4762 0 : move32();
4763 : }
4764 : }
4765 :
4766 510570 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
4767 : {
4768 : /* skip LFE */
4769 469760 : IF( EQ_16( ch_in, lfe_idx ) )
4770 : {
4771 20000 : CONTINUE;
4772 : }
4773 :
4774 : /* input channel index without LFE */
4775 449760 : test();
4776 449760 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_in, lfe_idx ) ) )
4777 : {
4778 85600 : ch_in_woLFE = sub( ch_in, 1 );
4779 : }
4780 : ELSE
4781 : {
4782 364160 : ch_in_woLFE = ch_in;
4783 364160 : move16();
4784 : }
4785 :
4786 :
4787 : /* gains for current subframe rotation */
4788 449760 : rotateAziEle_fixed( (Word16) L_shr( ls_azimuth[ch_in_woLFE], 22 ), (Word16) L_shr( ls_elevation[ch_in_woLFE], 22 ), &azimuth_fx, &elevation_fx, Rmat_fx, is_planar_setup );
4789 :
4790 449760 : test();
4791 449760 : test();
4792 449760 : IF( hEFAPdata != NULL && ( NE_32( ls_azimuth[ch_in_woLFE], azimuth_fx ) || NE_32( ls_elevation[ch_in_woLFE], elevation_fx ) ) )
4793 : {
4794 144730 : efap_determine_gains_fx( hEFAPdata, tmp_gains, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
4795 :
4796 1444790 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
4797 : {
4798 : /* skip LFE */
4799 1300060 : IF( EQ_16( ch_out, lfe_idx ) )
4800 : {
4801 144730 : CONTINUE;
4802 : }
4803 :
4804 : /* output channel index without LFE */
4805 1155330 : test();
4806 1155330 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_out, lfe_idx ) ) )
4807 : {
4808 721140 : ch_out_woLFE = sub( ch_out, 1 );
4809 : }
4810 : ELSE
4811 : {
4812 434190 : ch_out_woLFE = ch_out;
4813 434190 : move16();
4814 : }
4815 :
4816 1155330 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
4817 1155330 : move32();
4818 : }
4819 : }
4820 : }
4821 :
4822 : /* apply panning gains by mtx multiplication */
4823 510570 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
4824 : {
4825 6541120 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
4826 : {
4827 6071360 : writePtr = getSmplPtr_fx( outAudio, ch_out, imult1616( subframe_idx, subframe_len ) ); /* Qx */
4828 6071360 : readPtr = getSmplPtr_fx( inAudio, ch_in, imult1616( subframe_idx, subframe_len ) ); /* Qx */
4829 : /* crossfade with previous rotation gains */
4830 1463197760 : FOR( i = 0; i < subframe_len; i++ )
4831 : {
4832 1457126400 : *writePtr =
4833 1457126400 : L_add( *writePtr, L_add( Mpy_32_32( ( *readPtr ), Mpy_32_32( L_sub( ONE_IN_Q31, crossfade[i] ), gains_prev[ch_in][ch_out] ) ),
4834 1457126400 : Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); /* Qx - 1 */
4835 1457126400 : move32();
4836 1457126400 : readPtr++;
4837 1457126400 : writePtr++;
4838 : }
4839 : }
4840 : }
4841 :
4842 : /* move gains to gains_prev */
4843 510570 : FOR( i = 0; i < nchan; i++ )
4844 : {
4845 469760 : MVR2R_WORD32( gains[i], gains_prev[i], nchan );
4846 : }
4847 : }
4848 :
4849 25504 : pop_wmops();
4850 25504 : return IVAS_ERR_OK;
4851 : }
4852 :
4853 :
4854 45018 : static ivas_error rotateFrameSba_fx(
4855 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
4856 : const AUDIO_CONFIG inConfig, /* i : Input Audio config */
4857 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
4858 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
4859 : Word16 gains_prev[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS], /* i/o: Previous frame rotation gains Q14 */
4860 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
4861 : )
4862 : {
4863 : Word16 i, l, n, m;
4864 : Word16 m1, m2;
4865 : Word16 shd_rot_max_order;
4866 : const Word32 *crossfade; /* Q31 */
4867 : Word16 num_subframes;
4868 : Word16 subframe_idx, subframe_len;
4869 : Word32 *writePtr;
4870 : Word32 tmpRot[2 * HEADROT_ORDER + 1];
4871 : Word16 gains[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; /* Q14 */
4872 : Word32 temp;
4873 : Word32 Rmat[3][3]; /* Q30 */
4874 : ivas_error error;
4875 : Word16 idx, exp;
4876 : Word32 cf, oneminuscf; /* Q31 */
4877 : Word32 val;
4878 :
4879 45018 : push_wmops( "rotateFrameSba" );
4880 :
4881 45018 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
4882 : {
4883 0 : return error;
4884 : }
4885 45018 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
4886 45018 : move16();
4887 :
4888 45018 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inConfig, &shd_rot_max_order ) ), IVAS_ERR_OK ) )
4889 : {
4890 0 : return error;
4891 : }
4892 :
4893 : // subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
4894 45018 : subframe_len = BASOP_Util_Divide1616_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &exp );
4895 45018 : subframe_len = shr( subframe_len, sub( 15, exp ) );
4896 117063 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
4897 : {
4898 : /* initialize rotation matrices with zeros */
4899 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
4900 : {
4901 1152720 : set16_fx( gains[i], 0, HEADROT_SHMAT_DIM );
4902 : }
4903 :
4904 288180 : FOR( i = 0; i < 3; i++ )
4905 : {
4906 216135 : IF( hCombinedOrientationData != NULL )
4907 : {
4908 864540 : FOR( l = 0; l < 3; l++ )
4909 : {
4910 648405 : Rmat[i][l] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][l]; /* Q30 */
4911 648405 : move32();
4912 : }
4913 : }
4914 : ELSE
4915 : {
4916 : /* Set to identity */
4917 0 : set32_fx( Rmat[i], 0, 3 );
4918 0 : Rmat[i][i] = ONE_IN_Q30;
4919 0 : move32();
4920 : }
4921 : }
4922 : /* calculate ambisonics rotation matrices for the previous and current frames */
4923 72045 : SHrotmatgen_fx( gains, Rmat, shd_rot_max_order );
4924 :
4925 : #ifdef DEBUGGING
4926 : dbgwrite_txt( (const float *) ( gains[0] ), HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_code_gains.txt", NULL );
4927 : dbgwrite_txt( (const float *) ( Rmat[0] ), 3 * 3, "Fixed_code_Rmat.txt", NULL );
4928 : #endif
4929 17362845 : FOR( i = 0; i < subframe_len; i++ )
4930 : {
4931 17290800 : idx = add( imult1616( subframe_idx, subframe_len ), i );
4932 : // cf = crossfade[i];
4933 17290800 : cf = crossfade[i];
4934 17290800 : move32();
4935 17290800 : oneminuscf = L_sub( ONE_IN_Q31, cf );
4936 : /* As the rotation matrix becomes block diagonal in a SH basis, we can*/
4937 : /* apply each angular-momentum block individually to save complexity. */
4938 :
4939 : /* loop over l blocks */
4940 17290800 : m1 = 1;
4941 17290800 : m2 = 4;
4942 17290800 : move16();
4943 17290800 : move16();
4944 51872400 : FOR( l = 1; l <= shd_rot_max_order; l++ )
4945 : {
4946 : /* compute mtx-vector product for this l */
4947 184435200 : FOR( n = m1; n < m2; n++ )
4948 : {
4949 149853600 : tmpRot[n - m1] = 0;
4950 149853600 : move32();
4951 876067200 : FOR( m = m1; m < m2; m++ )
4952 : {
4953 726213600 : val = inAudio.data_fx[m * inAudio.config.numSamplesPerChannel + idx];
4954 : /* crossfade with previous rotation gains */
4955 726213600 : temp = Mpy_32_32( L_add( Mpy_32_16_r( cf, gains[n][m] ), ( Mpy_32_16_r( oneminuscf, gains_prev[n][m] ) ) ), val );
4956 726213600 : tmpRot[n - m1] = L_add( L_shl( temp, 1 ), tmpRot[n - m1] );
4957 726213600 : move32();
4958 726213600 : move32();
4959 : }
4960 : }
4961 : /* write back the result */
4962 184435200 : FOR( n = m1; n < m2; n++ )
4963 : {
4964 149853600 : writePtr = getSmplPtr_fx( outAudio, n, idx );
4965 149853600 : ( *writePtr ) = tmpRot[n - m1];
4966 149853600 : move32();
4967 : }
4968 34581600 : m1 = m2;
4969 34581600 : move16();
4970 34581600 : m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
4971 : }
4972 : }
4973 :
4974 : /* move SHrotmat to SHrotmat_prev */
4975 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
4976 : {
4977 1152720 : Copy( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
4978 : }
4979 : }
4980 45018 : pop_wmops();
4981 :
4982 45018 : return IVAS_ERR_OK;
4983 : }
4984 :
4985 150000 : static ivas_error renderIsmToBinaural(
4986 : input_ism *ismInput,
4987 : IVAS_REND_AudioBuffer outAudio )
4988 : {
4989 : Word32 tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
4990 : ivas_error error;
4991 : Word16 ism_md_subframe_update_ext;
4992 : Word16 i;
4993 150000 : Word16 exp = *outAudio.pq_fact;
4994 150000 : move16();
4995 150000 : push_wmops( "renderIsmToBinaural" );
4996 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
4997 150000 : ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, 429496730 /* 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
4998 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer );
4999 :
5000 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5001 : {
5002 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5003 : }
5004 :
5005 150000 : IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext,
5006 : *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer, &exp ) ),
5007 : IVAS_ERR_OK ) )
5008 : {
5009 0 : return error;
5010 : }
5011 :
5012 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5013 : {
5014 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5015 : }
5016 :
5017 150000 : IF( ismInput->hReverb != NULL )
5018 : {
5019 0 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
5020 : {
5021 0 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
5022 : {
5023 0 : tmpTDRendBuffer[i][j] = L_shl( tmpTDRendBuffer[i][j], Q2 ); /* Q(exp + 2) */
5024 0 : move32();
5025 : }
5026 : }
5027 : }
5028 150000 : accumulate2dArrayToBuffer_fx( tmpTDRendBuffer, &outAudio );
5029 :
5030 150000 : pop_wmops();
5031 :
5032 150000 : return IVAS_ERR_OK;
5033 : }
5034 :
5035 302544 : static Word16 getNumSubframesInBuffer(
5036 : const IVAS_REND_AudioBuffer *buffer,
5037 : const Word32 sampleRate )
5038 : {
5039 302544 : Word16 scale, temp = extract_l( Mpy_32_32( sampleRate, 10737418 /* 1 / FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
5040 302544 : temp = BASOP_Util_Divide1616_Scale( buffer->config.numSamplesPerChannel, temp, &scale );
5041 302544 : temp = shr( temp, sub( 15, scale ) ); /* Q0 */
5042 302544 : return temp;
5043 : }
5044 :
5045 :
5046 150000 : static ivas_error renderIsmToBinauralRoom(
5047 : input_ism *ismInput,
5048 : IVAS_REND_AudioBuffer outAudio,
5049 : Word16 *exp )
5050 : {
5051 : Word16 position_changed;
5052 : Word16 i, j;
5053 : Word32 azi_rot, ele_rot; /* Q22 */
5054 : Word16 subframe_idx;
5055 : Word16 tmp;
5056 : rotation_matrix_fx Rmat;
5057 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5058 : ivas_error error;
5059 : pan_vector_fx currentPanGains;
5060 : IVAS_REND_AudioBuffer tmpMcBuffer;
5061 : IVAS_ISM_METADATA rotatedPosPrev;
5062 : IVAS_ISM_METADATA rotatedPos;
5063 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5064 : Word8 combinedOrientationEnabled;
5065 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
5066 :
5067 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5068 : {
5069 2400000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
5070 : }
5071 :
5072 150000 : push_wmops( "renderIsmToBinauralRoom" );
5073 :
5074 150000 : rotatedPosPrev = defaultObjectPosition();
5075 150000 : rotatedPos = defaultObjectPosition();
5076 :
5077 150000 : hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
5078 150000 : combinedOrientationEnabled = 0;
5079 150000 : move16();
5080 150000 : IF( hCombinedOrientationData != NULL )
5081 : {
5082 270000 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5083 : {
5084 195000 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5085 : {
5086 75000 : combinedOrientationEnabled = 1;
5087 75000 : move16();
5088 75000 : BREAK;
5089 : }
5090 : }
5091 : }
5092 :
5093 150000 : IF( combinedOrientationEnabled )
5094 : {
5095 150000 : FOR( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
5096 : {
5097 300000 : FOR( i = 0; i < 3; i++ )
5098 : {
5099 225000 : test();
5100 225000 : IF( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
5101 : {
5102 900000 : FOR( j = 0; j < 3; j++ )
5103 : {
5104 675000 : Rmat[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
5105 675000 : move32();
5106 : }
5107 : }
5108 : ELSE
5109 : {
5110 : /* Set to identity */
5111 0 : set_zero_fx( Rmat[i], 3 );
5112 0 : Rmat[i][i] = ONE_IN_Q30;
5113 0 : move32();
5114 : }
5115 : }
5116 : }
5117 : }
5118 :
5119 : /* get previous position */
5120 150000 : IF( combinedOrientationEnabled )
5121 : {
5122 75000 : rotateAziEle_fx_frac_az_el( ismInput->previousPos.azimuth_fx, ismInput->previousPos.elevation_fx, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
5123 75000 : rotatedPosPrev.azimuth_fx = azi_rot;
5124 75000 : move32();
5125 75000 : rotatedPosPrev.elevation_fx = ele_rot;
5126 75000 : move32();
5127 : }
5128 : ELSE
5129 : {
5130 75000 : rotatedPosPrev.azimuth_fx = ismInput->previousPos.azimuth_fx;
5131 75000 : move32();
5132 75000 : rotatedPosPrev.elevation_fx = ismInput->previousPos.elevation_fx;
5133 75000 : move32();
5134 : }
5135 :
5136 : /* get current position */
5137 150000 : IF( combinedOrientationEnabled )
5138 : {
5139 75000 : rotateAziEle_fx_frac_az_el( ismInput->currentPos.azimuth_fx, ismInput->currentPos.elevation_fx, &azi_rot, &ele_rot, Rmat, 0 );
5140 75000 : rotatedPos.azimuth_fx = azi_rot;
5141 75000 : move32();
5142 75000 : rotatedPos.elevation_fx = ele_rot;
5143 75000 : move32();
5144 : }
5145 : ELSE
5146 : {
5147 75000 : rotatedPos.azimuth_fx = ismInput->currentPos.azimuth_fx;
5148 75000 : move32();
5149 75000 : rotatedPos.elevation_fx = ismInput->currentPos.elevation_fx;
5150 75000 : move32();
5151 : }
5152 :
5153 150000 : test();
5154 150000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &rotatedPos, &rotatedPosPrev );
5155 150000 : move16();
5156 :
5157 : /* set previous gains if this is the first frame */
5158 150000 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper, rotatedPosPrev.azimuth_fx, rotatedPosPrev.elevation_fx, ismInput->prev_pan_gains_fx ) ), IVAS_ERR_OK ) )
5159 : {
5160 0 : return error;
5161 : }
5162 :
5163 : /* compute gains only if position changed */
5164 150000 : IF( position_changed )
5165 : {
5166 64693 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
5167 : rotatedPos.azimuth_fx,
5168 : rotatedPos.elevation_fx,
5169 : currentPanGains ) ),
5170 : IVAS_ERR_OK ) )
5171 : {
5172 0 : return error;
5173 : }
5174 : }
5175 :
5176 : /* intermediate rendering to 7_1_4 */
5177 150000 : tmpMcBuffer = ismInput->base.inputBuffer;
5178 :
5179 150000 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
5180 : {
5181 0 : return error;
5182 : }
5183 :
5184 150000 : tmpMcBuffer.config.numChannels = tmp;
5185 150000 : move16();
5186 150000 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
5187 150000 : set_zero_fx( tmpMcBuffer.data_fx, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
5188 :
5189 150000 : IF( position_changed )
5190 : {
5191 64693 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5192 : currentPanGains,
5193 64693 : ismInput->prev_pan_gains_fx,
5194 : tmpMcBuffer );
5195 : }
5196 : ELSE
5197 : {
5198 85307 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5199 85307 : ismInput->prev_pan_gains_fx,
5200 : NULL,
5201 : tmpMcBuffer );
5202 : }
5203 :
5204 150000 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpRendBuffer );
5205 :
5206 : /* save gains for next frame */
5207 600000 : FOR( i = 0; i < 3; i++ )
5208 : {
5209 450000 : Copy32( Rmat[i], ismInput->rot_mat_prev[i], 3 );
5210 : }
5211 :
5212 150000 : IF( position_changed )
5213 : {
5214 64693 : Copy32( currentPanGains, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
5215 : }
5216 : // Crend_process porting
5217 : CREND_HANDLE hCrend;
5218 150000 : hCrend = ismInput->crendWrapper->hCrend;
5219 150000 : IF( hCrend->reflections != NULL )
5220 : {
5221 0 : test();
5222 0 : IF( EQ_32( hCrend->reflections->use_er, 1 ) && EQ_32( hCrend->reflections->is_ready, 1 ) )
5223 : {
5224 0 : FOR( i = 0; i < 150; i++ )
5225 : {
5226 0 : hCrend->reflections->shoebox_data.gains.data_fx[i] = L_shl( hCrend->reflections->shoebox_data.gains.data_fx[i], Q9 );
5227 0 : move32();
5228 : }
5229 : }
5230 : }
5231 :
5232 150000 : move16();
5233 :
5234 : /* render 7_1_4 with BRIRs */
5235 150000 : IF( NE_32( ( error = ivas_rend_crendProcess( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR,
5236 : NULL, NULL, NULL, NULL, p_tmpRendBuffer, *ismInput->base.ctx.pOutSampleRate,
5237 : getNumSubframesInBuffer( &outAudio, *ismInput->base.ctx.pOutSampleRate ) ) ),
5238 : IVAS_ERR_OK ) )
5239 :
5240 : {
5241 0 : return error;
5242 : }
5243 150000 : IF( hCrend->hReverb != NULL )
5244 : {
5245 0 : *exp = sub( *exp, 2 );
5246 0 : move16();
5247 : }
5248 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
5249 :
5250 150000 : free( tmpMcBuffer.data_fx );
5251 :
5252 150000 : pop_wmops();
5253 :
5254 150000 : return IVAS_ERR_OK;
5255 : }
5256 150000 : static ivas_error renderIsmToBinauralReverb(
5257 : input_ism *ismInput,
5258 : IVAS_REND_AudioBuffer outAudio )
5259 : {
5260 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5261 : ivas_error error;
5262 : Word16 ism_md_subframe_update_ext, i;
5263 150000 : Word16 exp = *outAudio.pq_fact;
5264 150000 : move16();
5265 :
5266 150000 : push_wmops( "renderIsmToBinauralRoom" );
5267 :
5268 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5269 150000 : ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, 429496730 /* 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
5270 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
5271 :
5272 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5273 : {
5274 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5275 : }
5276 :
5277 150000 : IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ), IVAS_ERR_OK ) )
5278 : {
5279 0 : return error;
5280 : }
5281 :
5282 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5283 : {
5284 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( 11, exp ) ) ); /* Q(exp) */
5285 : }
5286 :
5287 150000 : IF( ismInput->hReverb != NULL )
5288 : {
5289 450000 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
5290 : {
5291 115500000 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
5292 : {
5293 115200000 : tmpRendBuffer_fx[i][j] = L_shl( tmpRendBuffer_fx[i][j], 2 ); /* Q(exp + 2) */
5294 115200000 : move16();
5295 : }
5296 : }
5297 : }
5298 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
5299 150000 : pop_wmops();
5300 :
5301 150000 : return IVAS_ERR_OK;
5302 : }
5303 :
5304 539500 : static ivas_error renderIsmToMc(
5305 : input_ism *ismInput,
5306 : const IVAS_REND_AudioBuffer outAudio )
5307 : {
5308 : Word8 position_changed;
5309 : pan_vector_fx currentPanGains_fx; /* Q31 */
5310 : ivas_error error;
5311 :
5312 539500 : push_wmops( "renderIsmToMc" );
5313 :
5314 539500 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5315 539500 : move32();
5316 539500 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5317 539500 : move32();
5318 539500 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5319 539500 : move32();
5320 539500 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5321 539500 : move32();
5322 :
5323 539500 : test();
5324 539500 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
5325 539500 : move16();
5326 539500 : IF( EQ_32( *ismInput->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_STEREO ) )
5327 : {
5328 83500 : IF( ismInput->nonDiegeticPan )
5329 : {
5330 7500 : currentPanGains_fx[0] = L_add( L_shr( ismInput->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); /* Q31 */
5331 7500 : currentPanGains_fx[1] = L_sub( ONE_IN_Q31, currentPanGains_fx[0] ); /* Q31 */
5332 7500 : ismInput->prev_pan_gains_fx[0] = currentPanGains_fx[0]; /* Q31 */
5333 7500 : ismInput->prev_pan_gains_fx[1] = currentPanGains_fx[1]; /* Q31 */
5334 7500 : move32();
5335 7500 : move32();
5336 7500 : move32();
5337 7500 : move32();
5338 : }
5339 : ELSE
5340 : {
5341 76000 : set32_fx( currentPanGains_fx, 0, MAX_OUTPUT_CHANNELS );
5342 :
5343 : Word16 gains_fx[2];
5344 : Word16 azimuth_tmp, elevation_tmp;
5345 :
5346 76000 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
5347 76000 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
5348 :
5349 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
5350 76000 : currentPanGains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
5351 76000 : currentPanGains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
5352 76000 : move32();
5353 76000 : move32();
5354 :
5355 76000 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
5356 76000 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
5357 :
5358 76000 : set32_fx( ismInput->prev_pan_gains_fx, 0, MAX_OUTPUT_CHANNELS );
5359 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
5360 76000 : ismInput->prev_pan_gains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
5361 76000 : ismInput->prev_pan_gains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
5362 76000 : move32();
5363 76000 : move32();
5364 : }
5365 : }
5366 : ELSE
5367 : {
5368 : /* compute gains only if position changed */
5369 456000 : IF( position_changed )
5370 : {
5371 : // TODO tmu review when #215 is resolved
5372 177696 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
5373 : ismInput->currentPos.azimuth_fx,
5374 : ismInput->currentPos.elevation_fx,
5375 : currentPanGains_fx ) ),
5376 : IVAS_ERR_OK ) )
5377 : {
5378 0 : return error;
5379 : }
5380 : }
5381 :
5382 : /* set previous gains if this is the first frame */
5383 456000 : IF( !ismInput->firstFrameRendered )
5384 : {
5385 : // TODO tmu review when #215 is resolved
5386 168 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
5387 : ismInput->previousPos.azimuth_fx,
5388 : ismInput->previousPos.elevation_fx,
5389 : ismInput->prev_pan_gains_fx ) ),
5390 : IVAS_ERR_OK ) )
5391 : {
5392 0 : return error;
5393 : }
5394 : /* fix2float to be removed */
5395 : }
5396 : }
5397 :
5398 : /* Assume num channels in audio buffer to be 1.
5399 : * This should have been validated in IVAS_REND_FeedInputAudio() */
5400 539500 : IF( position_changed )
5401 : {
5402 214692 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5403 : currentPanGains_fx,
5404 214692 : ismInput->prev_pan_gains_fx,
5405 : outAudio );
5406 : }
5407 : ELSE
5408 : {
5409 324808 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5410 324808 : ismInput->prev_pan_gains_fx,
5411 : NULL,
5412 : outAudio );
5413 : }
5414 :
5415 539500 : IF( position_changed )
5416 : {
5417 214692 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
5418 : }
5419 :
5420 539500 : pop_wmops();
5421 :
5422 :
5423 539500 : return IVAS_ERR_OK;
5424 : }
5425 228000 : static ivas_error renderIsmToSba(
5426 : input_ism *ismInput,
5427 : const AUDIO_CONFIG outConfig,
5428 : const IVAS_REND_AudioBuffer outAudio )
5429 : {
5430 : Word16 i;
5431 : Word8 position_changed;
5432 : Word16 ambiOrderOut;
5433 : Word16 numOutChannels;
5434 : pan_vector_fx currentPanGains_fx;
5435 : ivas_error error;
5436 228000 : error = IVAS_ERR_OK;
5437 228000 : move32();
5438 :
5439 228000 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5440 228000 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5441 228000 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5442 228000 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5443 228000 : move32();
5444 228000 : move32();
5445 228000 : move32();
5446 228000 : move32();
5447 :
5448 228000 : push_wmops( "renderIsmToSba" );
5449 :
5450 228000 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
5451 : {
5452 0 : return error;
5453 : }
5454 :
5455 228000 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &ambiOrderOut ) ), IVAS_ERR_OK ) )
5456 : {
5457 0 : return error;
5458 : }
5459 :
5460 228000 : test();
5461 228000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
5462 228000 : move16();
5463 :
5464 : /* set previous gains if this is the first frame */
5465 : Word16 azimuth_tmp, elevation_tmp;
5466 228000 : IF( !ismInput->firstFrameRendered )
5467 : {
5468 : // TODO tmu review when #215 is resolved
5469 84 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
5470 84 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
5471 84 : ivas_dirac_dec_get_response_fx( azimuth_tmp,
5472 : elevation_tmp,
5473 84 : ismInput->prev_pan_gains_fx,
5474 : ambiOrderOut,
5475 : Q29 );
5476 1428 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5477 : {
5478 1344 : ismInput->prev_pan_gains_fx[i] = L_shl_sat( ismInput->prev_pan_gains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
5479 1344 : move32();
5480 : }
5481 : }
5482 :
5483 : /* compute gains only if position changed */
5484 228000 : IF( position_changed )
5485 : {
5486 : // TODO tmu review when #215 is resolved
5487 88848 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
5488 88848 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
5489 88848 : ivas_dirac_dec_get_response_fx( azimuth_tmp,
5490 : elevation_tmp,
5491 : currentPanGains_fx,
5492 : ambiOrderOut,
5493 : Q29 );
5494 1510416 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5495 : {
5496 1421568 : currentPanGains_fx[i] = L_shl_sat( currentPanGains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
5497 1421568 : move32();
5498 : }
5499 : }
5500 :
5501 : /* Assume num channels in audio buffer to be 1.
5502 : * This should have been validated in IVAS_REND_FeedInputAudio() */
5503 228000 : IF( position_changed )
5504 : {
5505 88848 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5506 : currentPanGains_fx,
5507 88848 : ismInput->prev_pan_gains_fx,
5508 : outAudio );
5509 : }
5510 : ELSE
5511 : {
5512 139152 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5513 139152 : ismInput->prev_pan_gains_fx,
5514 : NULL,
5515 : outAudio );
5516 : }
5517 :
5518 228000 : IF( position_changed )
5519 : {
5520 88848 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
5521 : }
5522 228000 : pop_wmops();
5523 :
5524 228000 : return error;
5525 : }
5526 :
5527 150 : static void renderIsmToMasa(
5528 : input_ism *ismInput,
5529 : IVAS_REND_AudioBuffer outAudio,
5530 : Word16 *exp )
5531 : {
5532 : Word32 tmpRendBuffer_fx[MAX_NUM_OBJECTS][L_FRAME48k];
5533 : Word16 i, j;
5534 : Word16 q_fact;
5535 :
5536 150 : push_wmops( "renderIsmToMasa" );
5537 :
5538 750 : FOR( i = 0; i < MAX_NUM_OBJECTS; i++ )
5539 : {
5540 600 : set32_fx( tmpRendBuffer_fx[i], 0, L_FRAME48k );
5541 : }
5542 :
5543 150 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
5544 : Word16 input_e[MAX_NUM_OBJECTS], max_e;
5545 :
5546 750 : FOR( i = 0; i < MAX_NUM_OBJECTS; i++ )
5547 : {
5548 600 : input_e[i] = sub( 31, add( getScaleFactor32( tmpRendBuffer_fx[i], L_FRAME48k ), *outAudio.pq_fact ) );
5549 600 : move16();
5550 : }
5551 :
5552 150 : Word16 guard_bits = find_guarded_bits_fx( L_FRAME48k );
5553 150 : max_e = input_e[0];
5554 150 : move16();
5555 :
5556 600 : FOR( i = 1; i < MAX_NUM_OBJECTS; i++ )
5557 : {
5558 450 : if ( LT_16( max_e, input_e[0] ) )
5559 : {
5560 0 : max_e = input_e[i];
5561 0 : move16();
5562 : }
5563 : }
5564 :
5565 750 : FOR( i = 0; i < MAX_NUM_OBJECTS; i++ )
5566 : {
5567 576600 : FOR( j = 0; j < L_FRAME48k; j++ )
5568 : {
5569 576000 : tmpRendBuffer_fx[i][j] = L_shr( tmpRendBuffer_fx[i][j], add( sub( max_e, sub( 31, *outAudio.pq_fact ) ), guard_bits ) ); /* Q(31 - (max_e + guard_bits)) */
5570 576000 : move32();
5571 : }
5572 : }
5573 :
5574 150 : max_e = add( max_e, guard_bits );
5575 150 : q_fact = sub( Q31, max_e );
5576 :
5577 150 : ivas_omasa_ana_fx( ismInput->hOMasa, tmpRendBuffer_fx, &q_fact, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
5578 :
5579 150 : *exp = q_fact;
5580 150 : move16();
5581 :
5582 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
5583 :
5584 150 : pop_wmops();
5585 :
5586 150 : return;
5587 : }
5588 :
5589 1217650 : static ivas_error renderInputIsm(
5590 : input_ism *ismInput,
5591 : const AUDIO_CONFIG outConfig,
5592 : const IVAS_REND_AudioBuffer outAudio )
5593 : {
5594 : ivas_error error;
5595 : IVAS_REND_AudioBuffer inAudio;
5596 1217650 : Word16 exp = *outAudio.pq_fact;
5597 1217650 : move16();
5598 :
5599 1217650 : error = IVAS_ERR_OK;
5600 1217650 : move32();
5601 1217650 : inAudio = ismInput->base.inputBuffer;
5602 :
5603 1217650 : IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
5604 : {
5605 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" );
5606 : }
5607 1217650 : ismInput->base.numNewSamplesPerChannel = 0;
5608 1217650 : move32();
5609 :
5610 : /* Apply input gain to new audio */
5611 1217650 : v_multc_fixed( inAudio.data_fx, ismInput->base.gain_fx, inAudio.data_fx, imult1616( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
5612 1217650 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 );
5613 1217650 : move16();
5614 1217650 : exp = *outAudio.pq_fact;
5615 1217650 : move16();
5616 :
5617 : /* set combined orientation subframe info to start info */
5618 1217650 : ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
5619 :
5620 :
5621 1217650 : SWITCH( getAudioConfigType( outConfig ) )
5622 : {
5623 539500 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
5624 539500 : error = renderIsmToMc( ismInput, outAudio );
5625 539500 : BREAK;
5626 228000 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
5627 228000 : error = renderIsmToSba( ismInput, outConfig, outAudio );
5628 228000 : BREAK;
5629 450000 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
5630 : SWITCH( outConfig )
5631 : {
5632 150000 : case IVAS_AUDIO_CONFIG_BINAURAL:
5633 150000 : error = renderIsmToBinaural( ismInput, outAudio );
5634 150000 : BREAK;
5635 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
5636 150000 : error = renderIsmToBinauralRoom( ismInput, outAudio, &exp );
5637 150000 : BREAK;
5638 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
5639 150000 : error = renderIsmToBinauralReverb( ismInput, outAudio );
5640 150000 : BREAK;
5641 0 : default:
5642 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
5643 : }
5644 450000 : BREAK;
5645 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
5646 150 : renderIsmToMasa( ismInput, outAudio, &exp );
5647 750 : FOR( Word16 block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
5648 : {
5649 600 : ismInput->hOMasa->energy_e[block_m_idx] = sub( 31, ismInput->hOMasa->energy_q );
5650 600 : move16();
5651 : }
5652 150 : BREAK;
5653 0 : default:
5654 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
5655 : }
5656 :
5657 : /* Check error here to keep switch statement more compact */
5658 1217650 : IF( NE_32( error, IVAS_ERR_OK ) )
5659 : {
5660 0 : return error;
5661 : }
5662 :
5663 1217650 : ismInput->firstFrameRendered = TRUE;
5664 1217650 : move16();
5665 :
5666 1217650 : *outAudio.pq_fact = exp;
5667 1217650 : move16();
5668 :
5669 1217650 : return error;
5670 : }
5671 :
5672 1114140 : static ivas_error renderActiveInputsIsm(
5673 : IVAS_REND_HANDLE hIvasRend,
5674 : IVAS_REND_AudioBuffer outAudio )
5675 : {
5676 : Word16 i;
5677 : input_ism *pCurrentInput;
5678 : ivas_error error;
5679 1114140 : Word16 input_q = Q8;
5680 1114140 : move16();
5681 5570700 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
5682 : {
5683 4456560 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5684 : {
5685 : /* Skip inactive inputs */
5686 3238910 : CONTINUE;
5687 : }
5688 :
5689 1217650 : *outAudio.pq_fact = Q8;
5690 1217650 : move16();
5691 1217650 : IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
5692 : {
5693 0 : return error;
5694 : }
5695 2579489650 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
5696 : {
5697 2578272000 : outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
5698 2578272000 : move32();
5699 : }
5700 1217650 : *outAudio.pq_fact = sub( input_q, 1 );
5701 1217650 : move16();
5702 : }
5703 1114140 : return IVAS_ERR_OK;
5704 : }
5705 87012 : static ivas_error renderLfeToBinaural_fx(
5706 : const input_mc *mcInput,
5707 : IVAS_REND_AudioBuffer outAudio,
5708 : Word16 in_q,
5709 : Word16 out_q )
5710 : {
5711 : Word16 lfe_idx;
5712 : Word32 gain_fx;
5713 : Word16 ear_idx, i, r_shift;
5714 : Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL];
5715 : Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
5716 : const Word32 *lfeInput;
5717 : Word32 *writePtr;
5718 :
5719 87012 : assert( ( outAudio.config.numChannels == 2 ) && "Must be binaural output" );
5720 :
5721 87012 : push_wmops( "renderLfeToBinaural" );
5722 87012 : gain_fx = GAIN_LFE_WORD32; /* 1.88364911f in Q30 */
5723 87012 : move32();
5724 :
5725 87012 : IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
5726 : {
5727 48000 : lfe_idx = LFE_CHANNEL;
5728 48000 : move16();
5729 : }
5730 39012 : ELSE IF( mcInput->customLsInput.num_lfe > 0 )
5731 : {
5732 0 : lfe_idx = mcInput->customLsInput.lfe_idx[0];
5733 0 : move16();
5734 : }
5735 : ELSE
5736 : {
5737 : /* no LFE to render */
5738 39012 : return IVAS_ERR_OK;
5739 : }
5740 :
5741 : /* --- Prepare LFE signal to be added to binaural output --- */
5742 48000 : lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 );
5743 48000 : frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
5744 48000 : move16();
5745 48000 : num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
5746 48000 : move16();
5747 48000 : num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame );
5748 :
5749 : /* Assuming LFE should be delayed by less that the duration of one frame */
5750 48000 : assert( mcInput->binauralDelaySmp < frame_size );
5751 :
5752 : /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
5753 48000 : v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
5754 :
5755 : /* Continue filling tmp buffer, now with LFE signal from current frame */
5756 48000 : v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); /* Qx - 1 */
5757 :
5758 : /* Save remaining LFE samples of current frame for next frame */
5759 48000 : MVR2R_WORD32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame );
5760 48000 : r_shift = sub( sub( in_q, 1 ), out_q );
5761 :
5762 48000 : IF( r_shift != 0 )
5763 : {
5764 14533750 : FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ )
5765 : {
5766 14496000 : tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); /* Q(out_q) */
5767 14496000 : move32();
5768 : }
5769 : }
5770 : /* Copy LFE to left and right ears */
5771 144000 : FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
5772 : {
5773 96000 : writePtr = getSmplPtr_fx( outAudio, ear_idx, 0 );
5774 96000 : move32();
5775 : #ifdef VEC_ARITH_OPT_v1
5776 96000 : v_add_fixed_no_hdrm( writePtr, tmpLfeBuffer, writePtr, frame_size ); /* Q(out_q) */
5777 : #else /* VEC_ARITH_OPT_v1 */
5778 : v_add_fixed( writePtr, tmpLfeBuffer, writePtr, frame_size, 0 ); /* Q(out_q) */
5779 : #endif /* VEC_ARITH_OPT_v1 */
5780 : }
5781 :
5782 48000 : pop_wmops();
5783 :
5784 48000 : return IVAS_ERR_OK;
5785 : }
5786 29004 : static ivas_error renderMcToBinaural(
5787 : input_mc *mcInput,
5788 : const AUDIO_CONFIG outConfig,
5789 : IVAS_REND_AudioBuffer outAudio )
5790 : {
5791 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5792 : AUDIO_CONFIG inConfig;
5793 : ivas_error error;
5794 : IVAS_REND_AudioBuffer tmpRotBuffer;
5795 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5796 : Word8 combinedOrientationEnabled;
5797 : Word16 subframe_idx;
5798 : Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS];
5799 : Word16 i;
5800 29004 : Word16 exp = *outAudio.pq_fact;
5801 29004 : move16();
5802 493068 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5803 : {
5804 464064 : p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i];
5805 : }
5806 29004 : push_wmops( "renderMcToBinaural" );
5807 29004 : inConfig = mcInput->base.inConfig;
5808 29004 : move32();
5809 29004 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
5810 29004 : combinedOrientationEnabled = 0;
5811 29004 : move16();
5812 29004 : IF( hCombinedOrientationData != NULL )
5813 : {
5814 52209 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5815 : {
5816 37707 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5817 : {
5818 14502 : combinedOrientationEnabled = 1;
5819 14502 : move16();
5820 14502 : BREAK;
5821 : }
5822 : }
5823 : }
5824 :
5825 29004 : test();
5826 29004 : test();
5827 29004 : test();
5828 29004 : IF( ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) || ( combinedOrientationEnabled && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) ) )
5829 : {
5830 18754 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
5831 :
5832 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5833 : {
5834 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5835 : }
5836 18754 : IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
5837 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ),
5838 : IVAS_ERR_OK ) )
5839 : {
5840 0 : return error;
5841 : }
5842 :
5843 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5844 : {
5845 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5846 : }
5847 : }
5848 : ELSE
5849 : {
5850 : /* apply rotation */
5851 10250 : IF( combinedOrientationEnabled )
5852 : {
5853 2250 : tmpRotBuffer = mcInput->base.inputBuffer;
5854 2250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
5855 2250 : set32_fx( tmpRotBuffer.data_fx, 0, imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
5856 :
5857 2250 : IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev_fx, mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ), IVAS_ERR_OK ) )
5858 : {
5859 0 : return error;
5860 : }
5861 :
5862 2250 : exp = sub( *outAudio.pq_fact, 1 );
5863 :
5864 2250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx );
5865 :
5866 2250 : free( tmpRotBuffer.data_fx );
5867 : }
5868 : ELSE
5869 : {
5870 8000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
5871 : }
5872 : // Porting Crend_process function
5873 : CREND_HANDLE hCrend;
5874 10250 : hCrend = mcInput->crendWrapper->hCrend;
5875 :
5876 : /* call CREND */
5877 10250 : IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, p_tmpRendBuffer_fx, *mcInput->base.ctx.pOutSampleRate,
5878 : getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
5879 : IVAS_ERR_OK ) )
5880 : {
5881 0 : return error;
5882 : }
5883 10250 : IF( hCrend->hReverb != NULL )
5884 : {
5885 0 : exp = sub( exp, 2 );
5886 : }
5887 : }
5888 :
5889 29004 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
5890 :
5891 29004 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
5892 :
5893 : {
5894 0 : return error;
5895 : }
5896 29004 : *outAudio.pq_fact = exp;
5897 29004 : move16();
5898 29004 : pop_wmops();
5899 29004 : return IVAS_ERR_OK;
5900 : }
5901 32000 : static ivas_error renderMcToBinauralRoom(
5902 : input_mc *mcInput,
5903 : const AUDIO_CONFIG outConfig,
5904 : IVAS_REND_AudioBuffer outAudio )
5905 : {
5906 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5907 : AUDIO_CONFIG inConfig;
5908 : ivas_error error;
5909 : IVAS_REND_AudioBuffer tmpRotBuffer;
5910 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
5911 : Word16 i;
5912 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5913 : Word8 combinedOrientationEnabled;
5914 : Word16 subframe_idx;
5915 32000 : Word16 exp = *outAudio.pq_fact;
5916 32000 : move16();
5917 544000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5918 : {
5919 512000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
5920 : }
5921 :
5922 32000 : push_wmops( "renderMcToBinauralRoom" );
5923 32000 : inConfig = mcInput->base.inConfig;
5924 32000 : move32();
5925 32000 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
5926 32000 : combinedOrientationEnabled = 0;
5927 32000 : move16();
5928 32000 : IF( hCombinedOrientationData != NULL )
5929 : {
5930 57600 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5931 : {
5932 41600 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5933 : {
5934 16000 : combinedOrientationEnabled = 1;
5935 16000 : move16();
5936 16000 : BREAK;
5937 : }
5938 : }
5939 : }
5940 :
5941 32000 : test();
5942 32000 : test();
5943 32000 : test();
5944 32000 : test();
5945 32000 : test();
5946 32000 : IF( ( mcInput->hReverb != NULL && EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) ) ) )
5947 : {
5948 5750 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
5949 :
5950 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5951 : {
5952 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5953 : }
5954 :
5955 5750 : IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
5956 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ),
5957 : IVAS_ERR_OK ) )
5958 : {
5959 0 : return error;
5960 : }
5961 :
5962 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5963 : {
5964 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5965 : }
5966 : }
5967 : ELSE
5968 : {
5969 : /* apply rotation */
5970 26250 : IF( combinedOrientationEnabled )
5971 : {
5972 10250 : tmpRotBuffer = mcInput->base.inputBuffer;
5973 10250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
5974 10250 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
5975 :
5976 10250 : IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData,
5977 : mcInput->rot_gains_prev_fx,
5978 : mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
5979 : IVAS_ERR_OK ) )
5980 : {
5981 0 : return error;
5982 : }
5983 :
5984 10250 : exp = sub( *outAudio.pq_fact, 1 );
5985 :
5986 10250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
5987 10250 : free( tmpRotBuffer.data_fx );
5988 : }
5989 : ELSE
5990 : {
5991 16000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
5992 : }
5993 : // Porting Crend_process function
5994 : CREND_HANDLE hCrend;
5995 26250 : hCrend = mcInput->crendWrapper->hCrend;
5996 :
5997 : /* call CREND */
5998 26250 : IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate,
5999 : getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
6000 : IVAS_ERR_OK ) )
6001 : {
6002 0 : return error;
6003 : }
6004 26250 : IF( hCrend->hReverb != NULL )
6005 : {
6006 10250 : exp = sub( exp, Q2 );
6007 : }
6008 : }
6009 :
6010 32000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
6011 :
6012 32000 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
6013 : {
6014 0 : return error;
6015 : }
6016 32000 : *outAudio.pq_fact = exp;
6017 32000 : move16();
6018 32000 : pop_wmops();
6019 32000 : return IVAS_ERR_OK;
6020 : }
6021 26008 : static ivas_error renderMcCustomLsToBinauralRoom(
6022 : input_mc *mcInput,
6023 : const AUDIO_CONFIG outConfig,
6024 : IVAS_REND_AudioBuffer outAudio )
6025 : {
6026 : Word16 i;
6027 : Word16 tmp;
6028 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6029 : ivas_error error;
6030 : IVAS_REND_AudioBuffer tmpRotBuffer;
6031 : IVAS_REND_AudioBuffer tmpMcBuffer;
6032 : IVAS_REND_AudioBuffer *tmpBufPtr;
6033 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6034 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6035 : Word8 combinedOrientationEnabled;
6036 : Word16 subframe_idx;
6037 26008 : Word16 exp = *outAudio.pq_fact;
6038 26008 : move16();
6039 26008 : push_wmops( "renderMcCustomLsToBinauralRoom" );
6040 26008 : tmpRotBuffer = outAudio; /* avoid compilation warning */
6041 :
6042 442136 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6043 : {
6044 416128 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6045 : }
6046 :
6047 26008 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6048 26008 : combinedOrientationEnabled = 0;
6049 26008 : move16();
6050 26008 : IF( hCombinedOrientationData != NULL )
6051 : {
6052 46818 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6053 : {
6054 33814 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6055 : {
6056 13004 : combinedOrientationEnabled = 1;
6057 13004 : move16();
6058 13004 : BREAK;
6059 : }
6060 : }
6061 : }
6062 :
6063 : /* apply rotation */
6064 26008 : IF( combinedOrientationEnabled )
6065 : {
6066 13004 : tmpRotBuffer = mcInput->base.inputBuffer;
6067 13004 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
6068 13004 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6069 :
6070 13004 : IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData,
6071 : mcInput->rot_gains_prev_fx,
6072 : mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
6073 : IVAS_ERR_OK ) )
6074 : {
6075 0 : return error;
6076 : }
6077 13004 : exp = sub( *outAudio.pq_fact, Q1 );
6078 : }
6079 :
6080 : /* intermediate conversion to 7_1_4 */
6081 26008 : tmpMcBuffer = mcInput->base.inputBuffer;
6082 :
6083 26008 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
6084 : {
6085 0 : return error;
6086 : }
6087 :
6088 26008 : tmpMcBuffer.config.numChannels = tmp;
6089 26008 : move16();
6090 26008 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
6091 26008 : set32_fx( tmpMcBuffer.data_fx, 0, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
6092 :
6093 26008 : IF( combinedOrientationEnabled )
6094 : {
6095 13004 : tmpBufPtr = &tmpRotBuffer;
6096 : }
6097 : ELSE
6098 : {
6099 13004 : tmpBufPtr = &mcInput->base.inputBuffer;
6100 : }
6101 406136 : FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
6102 : {
6103 380128 : renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer );
6104 : }
6105 26008 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
6106 :
6107 : CREND_HANDLE hCrend;
6108 26008 : hCrend = mcInput->crendWrapper->hCrend;
6109 : /* call CREND */
6110 26008 : IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL,
6111 : p_tmpCrendBuffer, *mcInput->base.ctx.pOutSampleRate, getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
6112 : IVAS_ERR_OK ) )
6113 : {
6114 0 : return error;
6115 : }
6116 26008 : IF( hCrend->hReverb != NULL )
6117 : {
6118 13004 : exp = sub( exp, 2 );
6119 : }
6120 :
6121 26008 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
6122 :
6123 26008 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
6124 : {
6125 0 : return error;
6126 : }
6127 26008 : *outAudio.pq_fact = exp;
6128 26008 : move16();
6129 26008 : IF( combinedOrientationEnabled )
6130 : {
6131 13004 : free( tmpRotBuffer.data_fx );
6132 : }
6133 26008 : free( tmpMcBuffer.data_fx );
6134 :
6135 26008 : pop_wmops();
6136 26008 : return IVAS_ERR_OK;
6137 : }
6138 196617 : static void renderMcToMc(
6139 : const input_mc *mcInput,
6140 : IVAS_REND_AudioBuffer outAudio )
6141 : {
6142 : Word16 i;
6143 : IVAS_REND_AudioBuffer inAudio;
6144 :
6145 196617 : push_wmops( "renderMcToMc" );
6146 196617 : inAudio = mcInput->base.inputBuffer;
6147 :
6148 1507289 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6149 : {
6150 1310672 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
6151 : }
6152 :
6153 196617 : pop_wmops();
6154 196617 : return;
6155 : }
6156 75756 : static void renderMcToSba(
6157 : const input_mc *mcInput,
6158 : IVAS_REND_AudioBuffer outAudio )
6159 : {
6160 : Word16 i;
6161 : IVAS_REND_AudioBuffer inAudio;
6162 :
6163 75756 : push_wmops( "renderMcToSba" );
6164 75756 : inAudio = mcInput->base.inputBuffer;
6165 :
6166 591852 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6167 : {
6168 516096 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
6169 : }
6170 75756 : pop_wmops();
6171 75756 : return;
6172 : }
6173 :
6174 150 : static void renderMcToMasa(
6175 : input_mc *mcInput,
6176 : IVAS_REND_AudioBuffer outAudio )
6177 : {
6178 150 : push_wmops( "renderMcToMasa" );
6179 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6180 150 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
6181 150 : ivas_mcmasa_ana_fx( mcInput->hMcMasa, tmpRendBuffer_fx, *( outAudio.pq_fact ), mcInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, mcInput->base.inputBuffer.config.numChannels );
6182 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6183 :
6184 150 : pop_wmops();
6185 150 : return;
6186 : }
6187 :
6188 359535 : static ivas_error renderInputMc(
6189 : input_mc *mcInput,
6190 : const AUDIO_CONFIG outConfig,
6191 : IVAS_REND_AudioBuffer outAudio )
6192 : {
6193 : ivas_error error;
6194 : IVAS_REND_AudioBuffer inAudio;
6195 359535 : error = IVAS_ERR_OK;
6196 359535 : move32();
6197 :
6198 359535 : inAudio = mcInput->base.inputBuffer;
6199 :
6200 359535 : IF( NE_32( mcInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6201 : {
6202 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" );
6203 : }
6204 359535 : mcInput->base.numNewSamplesPerChannel = 0;
6205 359535 : move32();
6206 359535 : v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
6207 359535 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 ); // reducing the Q by 1 compensating for the v_mult_fixed done
6208 359535 : move16();
6209 : /* set combined orientation subframe info to start info */
6210 359535 : ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
6211 :
6212 359535 : SWITCH( getAudioConfigType( outConfig ) )
6213 : {
6214 196617 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6215 196617 : renderMcToMc( mcInput, outAudio );
6216 196617 : BREAK;
6217 75756 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6218 75756 : renderMcToSba( mcInput, outAudio );
6219 75756 : BREAK;
6220 87012 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6221 : SWITCH( outConfig )
6222 : {
6223 29004 : case IVAS_AUDIO_CONFIG_BINAURAL:
6224 29004 : error = renderMcToBinaural( mcInput, outConfig, outAudio );
6225 29004 : BREAK;
6226 58008 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6227 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6228 58008 : IF( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
6229 : {
6230 26008 : error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
6231 : }
6232 : ELSE
6233 : {
6234 32000 : error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
6235 : }
6236 58008 : BREAK;
6237 0 : default:
6238 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6239 : }
6240 87012 : BREAK;
6241 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6242 150 : renderMcToMasa( mcInput, outAudio );
6243 150 : BREAK;
6244 0 : default:
6245 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6246 : }
6247 359535 : return error;
6248 : }
6249 1114140 : static ivas_error renderActiveInputsMc(
6250 : IVAS_REND_HANDLE hIvasRend,
6251 : IVAS_REND_AudioBuffer outAudio )
6252 : {
6253 : Word16 i;
6254 : input_mc *pCurrentInput;
6255 : ivas_error error;
6256 2228280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMc ); i < RENDERER_MAX_MC_INPUTS; ( ++i, ++pCurrentInput ) )
6257 : {
6258 1114140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6259 : {
6260 : /* Skip inactive inputs */
6261 754605 : CONTINUE;
6262 : }
6263 :
6264 359535 : *outAudio.pq_fact = Q8;
6265 359535 : move16();
6266 359535 : IF( NE_32( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6267 : {
6268 0 : return error;
6269 : }
6270 : }
6271 :
6272 1114140 : return IVAS_ERR_OK;
6273 : }
6274 115801 : static void renderSbaToMc(
6275 : const input_sba *sbaInput,
6276 : IVAS_REND_AudioBuffer outAudio )
6277 : {
6278 : Word16 i;
6279 : IVAS_REND_AudioBuffer inAudio;
6280 :
6281 115801 : push_wmops( "renderSbaToMc" );
6282 115801 : inAudio = sbaInput->base.inputBuffer;
6283 :
6284 1225294 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6285 : {
6286 1109493 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
6287 : }
6288 :
6289 115801 : pop_wmops();
6290 115801 : return;
6291 : }
6292 :
6293 :
6294 45768 : static void renderSbaToSba(
6295 : const input_sba *sbaInput,
6296 : IVAS_REND_AudioBuffer outAudio )
6297 : {
6298 : Word16 i;
6299 : IVAS_REND_AudioBuffer inAudio;
6300 :
6301 45768 : push_wmops( "renderSbaToSba" );
6302 45768 : inAudio = sbaInput->base.inputBuffer;
6303 :
6304 483942 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6305 : {
6306 438174 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
6307 : }
6308 :
6309 45768 : pop_wmops();
6310 45768 : return;
6311 : }
6312 30012 : static ivas_error renderSbaToBinaural(
6313 : input_sba *sbaInput,
6314 : const AUDIO_CONFIG outConfig,
6315 : IVAS_REND_AudioBuffer outAudio )
6316 : {
6317 : ivas_error error;
6318 : IVAS_REND_AudioBuffer tmpRotBuffer;
6319 : Word16 i;
6320 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6321 : Word8 combinedOrientationEnabled;
6322 : Word16 subframe_idx;
6323 : Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6324 : Word32 *output_fx[MAX_OUTPUT_CHANNELS];
6325 :
6326 30012 : push_wmops( "renderSbaToBinaural" );
6327 : {
6328 :
6329 510204 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6330 : {
6331 480192 : output_fx[i] = output_buffer_fx[i];
6332 : }
6333 :
6334 30012 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
6335 30012 : combinedOrientationEnabled = 0;
6336 30012 : move16();
6337 30012 : IF( hCombinedOrientationData != NULL )
6338 : {
6339 54027 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6340 : {
6341 39021 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6342 : {
6343 15006 : combinedOrientationEnabled = 1;
6344 15006 : move16();
6345 15006 : BREAK;
6346 : }
6347 : }
6348 : }
6349 : /* apply rotation */
6350 30012 : IF( combinedOrientationEnabled )
6351 : {
6352 15006 : tmpRotBuffer = sbaInput->base.inputBuffer;
6353 :
6354 15006 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
6355 : /* copy input for in-place rotation */
6356 :
6357 15006 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
6358 :
6359 15006 : IF( NE_16( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
6360 : sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx, tmpRotBuffer ) ),
6361 : IVAS_ERR_OK ) )
6362 : {
6363 0 : return error;
6364 : }
6365 :
6366 15006 : copyBufferTo2dArray_fx( tmpRotBuffer, output_buffer_fx );
6367 15006 : free( tmpRotBuffer.data_fx );
6368 : }
6369 : ELSE
6370 : {
6371 15006 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, output_buffer_fx );
6372 : }
6373 : // Porting Crend_process function
6374 : CREND_HANDLE hCrend;
6375 30012 : hCrend = sbaInput->crendWrapper->hCrend;
6376 :
6377 : /* call CREND */
6378 30012 : IF( NE_32( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, output_fx, *sbaInput->base.ctx.pOutSampleRate,
6379 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ),
6380 : IVAS_ERR_OK ) )
6381 : {
6382 0 : return error;
6383 : }
6384 30012 : IF( hCrend->hReverb != NULL )
6385 : {
6386 0 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
6387 0 : move16();
6388 : }
6389 30012 : accumulate2dArrayToBuffer_fx( output_buffer_fx, &outAudio );
6390 : }
6391 :
6392 30012 : pop_wmops();
6393 30012 : return IVAS_ERR_OK;
6394 : }
6395 60024 : static ivas_error renderSbaToBinauralRoom(
6396 : input_sba *sbaInput,
6397 : const AUDIO_CONFIG outConfig,
6398 : IVAS_REND_AudioBuffer outAudio )
6399 : {
6400 : Word16 i;
6401 : Word16 tmp;
6402 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6403 : ivas_error error;
6404 : IVAS_REND_AudioBuffer tmpRotBuffer;
6405 : IVAS_REND_AudioBuffer tmpMcBuffer;
6406 : IVAS_REND_AudioBuffer *tmpBufPtr;
6407 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6408 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6409 : Word8 combinedOrientationEnabled;
6410 : Word16 subframe_idx;
6411 :
6412 60024 : tmpRotBuffer = outAudio; /* avoid compilation warning */
6413 60024 : push_wmops( "renderSbaToBinauralRoom" );
6414 : Word16 nchan_out;
6415 : CREND_HANDLE hCrend;
6416 :
6417 60024 : hCrend = sbaInput->crendWrapper->hCrend;
6418 :
6419 60024 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ), IVAS_ERR_OK ) )
6420 : {
6421 0 : return error;
6422 : }
6423 :
6424 1020408 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6425 : {
6426 960384 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6427 : }
6428 :
6429 60024 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
6430 60024 : combinedOrientationEnabled = 0;
6431 60024 : move16();
6432 60024 : IF( hCombinedOrientationData != NULL )
6433 : {
6434 108054 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6435 : {
6436 78042 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6437 : {
6438 30012 : combinedOrientationEnabled = 1;
6439 30012 : move16();
6440 30012 : BREAK;
6441 : }
6442 : }
6443 : }
6444 :
6445 : /* apply rotation */
6446 60024 : IF( combinedOrientationEnabled )
6447 : {
6448 30012 : tmpRotBuffer = sbaInput->base.inputBuffer;
6449 30012 : tmpRotBuffer.data_fx = malloc( imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) * sizeof( Word32 ) );
6450 :
6451 : /* copy input for in-place rotation */
6452 30012 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
6453 :
6454 30012 : IF( NE_32( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
6455 : sbaInput->base.ctx.pCombinedOrientationData,
6456 : sbaInput->rot_gains_prev_fx,
6457 : tmpRotBuffer ) ),
6458 : IVAS_ERR_OK ) )
6459 : {
6460 0 : return error;
6461 : }
6462 : }
6463 :
6464 : /* intermediate rendering to 7_1_4 */
6465 60024 : tmpMcBuffer = sbaInput->base.inputBuffer;
6466 :
6467 60024 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
6468 : {
6469 0 : return error;
6470 : }
6471 :
6472 60024 : tmpMcBuffer.config.numChannels = tmp;
6473 60024 : move16();
6474 60024 : tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) );
6475 60024 : set32_fx( tmpMcBuffer.data_fx, 0, i_mult( tmpMcBuffer.config.numChannels, tmpMcBuffer.config.numSamplesPerChannel ) );
6476 :
6477 60024 : IF( combinedOrientationEnabled )
6478 : {
6479 30012 : tmpBufPtr = &tmpRotBuffer;
6480 : }
6481 : ELSE
6482 : {
6483 30012 : tmpBufPtr = &sbaInput->base.inputBuffer;
6484 : }
6485 640256 : FOR( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
6486 : {
6487 580232 : renderBufferChannel_fx( *tmpBufPtr, i, sbaInput->hoaDecMtx_fx[i], tmpMcBuffer );
6488 : }
6489 60024 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
6490 : // Porting Crend_process function
6491 :
6492 : /* call CREND */
6493 60024 : IF( NE_32( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig,
6494 : NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *sbaInput->base.ctx.pOutSampleRate,
6495 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ),
6496 : IVAS_ERR_OK ) )
6497 : {
6498 0 : return error;
6499 : }
6500 60024 : IF( hCrend->hReverb != NULL )
6501 : {
6502 30012 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 2 );
6503 30012 : move16();
6504 : }
6505 :
6506 60024 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
6507 :
6508 60024 : IF( combinedOrientationEnabled )
6509 : {
6510 30012 : free( tmpRotBuffer.data_fx );
6511 : }
6512 60024 : free( tmpMcBuffer.data_fx );
6513 :
6514 60024 : pop_wmops();
6515 60024 : return IVAS_ERR_OK;
6516 : }
6517 150 : static void renderSbaToMasa(
6518 : input_sba *sbaInput,
6519 : IVAS_REND_AudioBuffer outAudio )
6520 : {
6521 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6522 :
6523 150 : push_wmops( "renderMcToMasa" );
6524 150 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, tmpRendBuffer );
6525 150 : ivas_dirac_ana_fx( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels );
6526 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
6527 :
6528 150 : pop_wmops();
6529 150 : return;
6530 : }
6531 251755 : static ivas_error renderInputSba(
6532 : input_sba *sbaInput,
6533 : const AUDIO_CONFIG outConfig,
6534 : IVAS_REND_AudioBuffer outAudio )
6535 : {
6536 : ivas_error error;
6537 : IVAS_REND_AudioBuffer inAudio;
6538 251755 : error = IVAS_ERR_OK;
6539 251755 : move32();
6540 251755 : inAudio = sbaInput->base.inputBuffer;
6541 :
6542 251755 : IF( NE_32( sbaInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6543 : {
6544 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" );
6545 : }
6546 251755 : sbaInput->base.numNewSamplesPerChannel = 0;
6547 251755 : move32();
6548 251755 : *outAudio.pq_fact = outAudio.q_factor;
6549 251755 : move16();
6550 : /* Apply input gain to new audio */
6551 251755 : v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
6552 251755 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
6553 251755 : move16();
6554 :
6555 : /* set combined orientation subframe info to start info */
6556 251755 : ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
6557 :
6558 251755 : SWITCH( getAudioConfigType( outConfig ) )
6559 : {
6560 115801 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6561 115801 : renderSbaToMc( sbaInput, outAudio );
6562 115801 : BREAK;
6563 45768 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6564 45768 : renderSbaToSba( sbaInput, outAudio );
6565 45768 : BREAK;
6566 90036 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6567 : SWITCH( outConfig )
6568 : {
6569 30012 : case IVAS_AUDIO_CONFIG_BINAURAL:
6570 30012 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
6571 30012 : BREAK;
6572 60024 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6573 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6574 60024 : error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
6575 60024 : BREAK;
6576 0 : default:
6577 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6578 : }
6579 90036 : BREAK;
6580 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6581 150 : renderSbaToMasa( sbaInput, outAudio );
6582 150 : BREAK;
6583 0 : default:
6584 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6585 : }
6586 :
6587 251755 : return error;
6588 : }
6589 1114140 : static ivas_error renderActiveInputsSba(
6590 : IVAS_REND_HANDLE hIvasRend,
6591 : IVAS_REND_AudioBuffer outAudio )
6592 : {
6593 : Word16 i;
6594 : input_sba *pCurrentInput;
6595 : ivas_error error;
6596 :
6597 2228280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsSba ); i < RENDERER_MAX_SBA_INPUTS; ( ++i, ++pCurrentInput ) )
6598 : {
6599 1114140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6600 : {
6601 : /* Skip inactive inputs */
6602 862385 : CONTINUE;
6603 : }
6604 251755 : *outAudio.pq_fact = Q8;
6605 251755 : move16();
6606 251755 : IF( NE_32( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6607 : {
6608 0 : return error;
6609 : }
6610 : }
6611 1114140 : return IVAS_ERR_OK;
6612 : }
6613 :
6614 :
6615 17250 : static void copyMasaMetadataToDiracRenderer_fx(
6616 : MASA_METADATA_FRAME *meta,
6617 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
6618 : const Word16 maxBin )
6619 : {
6620 : Word16 band, sf, bin;
6621 : Word16 meta_write_index;
6622 :
6623 17250 : hSpatParamRendCom->numParametricDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
6624 17250 : hSpatParamRendCom->numSimultaneousDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
6625 17250 : move16();
6626 17250 : move16();
6627 :
6628 86250 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
6629 : {
6630 69000 : meta_write_index = add( hSpatParamRendCom->dirac_bs_md_write_idx, sf ) % hSpatParamRendCom->dirac_md_buffer_length;
6631 :
6632 1725000 : FOR( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
6633 : {
6634 5796000 : FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
6635 : {
6636 4140000 : hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6637 4140000 : move16();
6638 4140000 : hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6639 4140000 : move16();
6640 4140000 : hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band];
6641 4140000 : move32();
6642 4140000 : hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( ONE_IN_Q30, meta->directional_meta[0].energy_ratio_fx[sf][band] );
6643 4140000 : move32();
6644 4140000 : hSpatParamRendCom->spreadCoherence_fx[meta_write_index][bin] = meta->directional_meta[0].spread_coherence_fx[sf][band];
6645 4140000 : move16();
6646 4140000 : hSpatParamRendCom->surroundingCoherence_fx[meta_write_index][bin] = meta->common_meta.surround_coherence_fx[sf][band];
6647 4140000 : move16();
6648 :
6649 4140000 : IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) )
6650 : {
6651 2160000 : hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6652 2160000 : move16();
6653 2160000 : hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6654 2160000 : move16();
6655 2160000 : hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band];
6656 2160000 : move32();
6657 2160000 : hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin], meta->directional_meta[1].energy_ratio_fx[sf][band] );
6658 2160000 : move32();
6659 2160000 : hSpatParamRendCom->spreadCoherence2_fx[meta_write_index][bin] = meta->directional_meta[1].spread_coherence_fx[sf][band];
6660 2160000 : move16();
6661 : }
6662 : }
6663 : }
6664 : }
6665 :
6666 17250 : hSpatParamRendCom->dirac_bs_md_write_idx = add( hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
6667 17250 : move16();
6668 :
6669 17250 : return;
6670 : }
6671 :
6672 :
6673 150 : static void renderMasaToMasa(
6674 : input_masa *masaInput,
6675 : IVAS_REND_AudioBuffer outAudio )
6676 : {
6677 : Word16 sf, band, dir, numDirs;
6678 : Word32 ratioSum_fx; /* Q30 */
6679 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
6680 : MASA_METADATA_FRAME *inMeta;
6681 : Word32 tmpBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6682 : Word16 ts, i, j, l_ts;
6683 : Word32 Chan_RealBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
6684 : Word32 Chan_ImagBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
6685 : Word16 band_m_idx, block_m_idx;
6686 : Word16 mrange[2];
6687 : Word16 brange[2];
6688 : Word16 numAnalysisChannels;
6689 : Word16 tmp_energy_e[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
6690 150 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_fx );
6691 150 : Word16 q_cldfb = *outAudio.pq_fact;
6692 150 : Word16 q_cldfb_out = *outAudio.pq_fact;
6693 150 : Word16 scale_factor = 31;
6694 : Word16 scale_fac_arr[MASA_MAX_TRANSPORT_CHANNELS];
6695 150 : move16();
6696 150 : move16();
6697 150 : move16();
6698 : /* Calculate energy */
6699 : // l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
6700 150 : l_ts = shr( masaInput->base.inputBuffer.config.numSamplesPerChannel, 4 );
6701 150 : numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
6702 150 : move16();
6703 : /* do processing over all CLDFB time slots */
6704 750 : FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
6705 : {
6706 600 : mrange[0] = DirAC_block_grouping[block_m_idx];
6707 600 : mrange[1] = DirAC_block_grouping[block_m_idx + 1];
6708 600 : move16();
6709 600 : move16();
6710 :
6711 600 : set_zero_fx( masaInput->hMasaPrerend->energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
6712 :
6713 3000 : FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
6714 : {
6715 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
6716 : {
6717 4800 : scale_factor = 31;
6718 4800 : move16();
6719 4800 : masaInput->hMasaPrerend->cldfbAnaEnc[i]->Q_cldfb_state = q_cldfb;
6720 4800 : q_cldfb_out = q_cldfb;
6721 4800 : move16();
6722 4800 : move16();
6723 4800 : cldfbAnalysis_ts_fx_fixed_q( &( tmpBuffer_fx[i][l_ts * ts] ), Chan_RealBuffer_fx[i], Chan_ImagBuffer_fx[i], l_ts, masaInput->hMasaPrerend->cldfbAnaEnc[i], &q_cldfb_out );
6724 4800 : scale_factor = s_min( scale_factor, s_min( getScaleFactor32( Chan_RealBuffer_fx[i], CLDFB_NO_CHANNELS_MAX ), getScaleFactor32( Chan_ImagBuffer_fx[i], CLDFB_NO_CHANNELS_MAX ) ) );
6725 4800 : scale_factor = sub( scale_factor, 1 );
6726 4800 : scale_sig32( Chan_RealBuffer_fx[i], CLDFB_NO_CHANNELS_MAX, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
6727 4800 : scale_sig32( Chan_ImagBuffer_fx[i], CLDFB_NO_CHANNELS_MAX, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
6728 4800 : scale_fac_arr[i] = scale_factor;
6729 4800 : move16();
6730 : }
6731 :
6732 2400 : scale_factor = MAX_16;
6733 2400 : move16();
6734 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
6735 : {
6736 4800 : scale_factor = s_min( scale_factor, scale_fac_arr[i] );
6737 : }
6738 :
6739 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
6740 : {
6741 4800 : IF( NE_16( scale_factor, scale_fac_arr[i] ) )
6742 : {
6743 48861 : FOR( j = 0; j < CLDFB_NO_CHANNELS_MAX; j++ )
6744 : {
6745 48060 : Chan_RealBuffer_fx[i][j] = L_shr( Chan_RealBuffer_fx[i][j], sub( scale_fac_arr[i], scale_factor ) ); /* Q(q_cldfb_out+scale_factor) */
6746 48060 : move32();
6747 48060 : Chan_ImagBuffer_fx[i][j] = L_shr( Chan_ImagBuffer_fx[i][j], sub( scale_fac_arr[i], scale_factor ) ); /* Q(q_cldfb_out+scale_factor) */
6748 48060 : move32();
6749 : }
6750 : }
6751 : }
6752 :
6753 2400 : Word16 q_add = sub( 31, add( scale_factor, q_cldfb_out ) );
6754 : /* Compute channel energy for metadata processing */
6755 60000 : FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
6756 : {
6757 57600 : brange[0] = MASA_band_grouping_24[band_m_idx];
6758 57600 : move16();
6759 57600 : brange[1] = MASA_band_grouping_24[band_m_idx + 1];
6760 57600 : move16();
6761 201600 : FOR( j = brange[0]; j < brange[1]; j++ )
6762 : {
6763 432000 : FOR( i = 0; i < numAnalysisChannels; i++ )
6764 : {
6765 288000 : Word32 temp = L_add( Mpy_32_32( Chan_RealBuffer_fx[0][j], Chan_RealBuffer_fx[0][j] ), Mpy_32_32( Chan_ImagBuffer_fx[0][j], Chan_ImagBuffer_fx[0][j] ) ); /* 2 * Q(q_cldfb_out + scale_factor) - 31 */
6766 288000 : masaInput->hMasaPrerend->energy_fx[block_m_idx][band_m_idx] = BASOP_Util_Add_Mant32Exp( masaInput->hMasaPrerend->energy_fx[block_m_idx][band_m_idx], tmp_energy_e[block_m_idx][band_m_idx], temp, shl( q_add, 1 ), &tmp_energy_e[block_m_idx][band_m_idx] );
6767 288000 : move32();
6768 : }
6769 : }
6770 : }
6771 : }
6772 : }
6773 750 : FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
6774 : {
6775 600 : Word16 max_e = MIN_16;
6776 600 : move16();
6777 15000 : FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
6778 : {
6779 14400 : max_e = s_max( max_e, tmp_energy_e[i][j] );
6780 : }
6781 600 : masaInput->hMasaPrerend->energy_e[i] = max_e;
6782 600 : move16();
6783 15000 : FOR( j = 0; j < MASA_FREQUENCY_BANDS; j++ )
6784 : {
6785 :
6786 14400 : masaInput->hMasaPrerend->energy_fx[i][j] = L_shr( masaInput->hMasaPrerend->energy_fx[i][j], sub( max_e, tmp_energy_e[i][j] ) ); /* Q(31 - max_e) */
6787 14400 : move32();
6788 : }
6789 : }
6790 : /* Copy audio channels if mismatch in number of transports */
6791 150 : test();
6792 150 : test();
6793 150 : IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 1 ) && EQ_16( outAudio.config.numChannels, 2 ) )
6794 : {
6795 0 : Copy32( tmpBuffer_fx[0], tmpBuffer_fx[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
6796 : }
6797 150 : ELSE IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 2 ) && EQ_16( outAudio.config.numChannels, 1 ) )
6798 : {
6799 : // v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
6800 : #ifdef VEC_ARITH_OPT_v1
6801 0 : v_add_fixed_no_hdrm( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
6802 : #else /* VEC_ARITH_OPT_v1 */
6803 : v_add_fixed( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel, 0 );
6804 : #endif /* VEC_ARITH_OPT_v1 */
6805 : }
6806 :
6807 : /* Copy metadata */
6808 150 : outMeta = masaInput->hMasaPrerend->hMasaOut;
6809 150 : inMeta = &masaInput->masaMetadata;
6810 150 : numDirs = add( inMeta->descriptive_meta.numberOfDirections, 1 );
6811 :
6812 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
6813 : {
6814 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
6815 : {
6816 : /* Remainder is always set to zero and energy removal is compensated in following steps
6817 : * to other ratios. */
6818 : // inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
6819 14400 : inMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0;
6820 14400 : move32();
6821 14400 : ratioSum_fx = 0;
6822 14400 : move32();
6823 43200 : FOR( dir = 0; dir < numDirs; dir++ )
6824 : {
6825 28800 : ratioSum_fx = L_add( ratioSum_fx, inMeta->directional_meta[dir].energy_ratio_fx[sf][band] );
6826 : }
6827 14400 : ratioSum_fx = L_add( ratioSum_fx, inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
6828 :
6829 14400 : IF( ratioSum_fx == 0 )
6830 : {
6831 0 : FOR( dir = 0; dir < numDirs; dir++ )
6832 : {
6833 0 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0;
6834 0 : move32();
6835 : }
6836 0 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30;
6837 0 : move32();
6838 : }
6839 14400 : ELSE IF( NE_32( ratioSum_fx, ONE_IN_Q30 ) )
6840 : {
6841 14400 : Word16 tmp_e = 0;
6842 14400 : move16();
6843 14400 : Word32 tmp = 0;
6844 14400 : move32();
6845 43200 : FOR( dir = 0; dir < numDirs; dir++ )
6846 : {
6847 28800 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
6848 28800 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
6849 28800 : move32();
6850 : }
6851 14400 : tmp_e = 0;
6852 14400 : move16();
6853 14400 : tmp = 0;
6854 14400 : move32();
6855 14400 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
6856 14400 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
6857 14400 : move32();
6858 : }
6859 : }
6860 : }
6861 :
6862 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
6863 : {
6864 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
6865 : {
6866 14400 : outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
6867 14400 : move16();
6868 43200 : FOR( dir = 0; dir < numDirs; dir++ )
6869 : {
6870 28800 : outMeta->directionIndex[dir][sf][band] = index_theta_phi_16_fx( &inMeta->directional_meta[dir].elevation_fx[sf][band], &inMeta->directional_meta[dir].azimuth_fx[sf][band], masaInput->hMasaPrerend->sph_grid16 );
6871 28800 : outMeta->directToTotalRatio[dir][sf][band] = (UWord8) L_shr( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], Q22 );
6872 28800 : outMeta->diffuseToTotalRatio[sf][band] = (UWord8) sub( outMeta->diffuseToTotalRatio[sf][band], outMeta->directToTotalRatio[dir][sf][band] );
6873 28800 : outMeta->spreadCoherence[dir][sf][band] = (UWord8) shr( inMeta->directional_meta[dir].spread_coherence_fx[sf][band], Q7 );
6874 :
6875 28800 : move16();
6876 28800 : move16();
6877 28800 : move16();
6878 28800 : move16();
6879 : }
6880 14400 : outMeta->surroundCoherence[sf][band] = (UWord8) shr( inMeta->common_meta.surround_coherence_fx[sf][band], Q7 );
6881 14400 : move16();
6882 : }
6883 : }
6884 :
6885 150 : copy_masa_descriptive_meta_fx( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
6886 :
6887 150 : accumulate2dArrayToBuffer_fx( tmpBuffer_fx, &outAudio );
6888 :
6889 150 : return;
6890 : }
6891 :
6892 18150 : static ivas_error renderInputMasa(
6893 : input_masa *masaInput,
6894 : const AUDIO_CONFIG outConfig,
6895 : IVAS_REND_AudioBuffer outAudio )
6896 : {
6897 : IVAS_REND_AudioBuffer inAudio;
6898 : Word16 ch;
6899 : Word16 maxBin;
6900 : Word32 *tmpBuffer_fx[MAX_OUTPUT_CHANNELS];
6901 : Word32 tmpBuffer_buff_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6902 :
6903 18150 : IF( !masaInput->metadataHasBeenFed )
6904 : {
6905 0 : return IVAS_ERR_MISSING_METADATA;
6906 : }
6907 :
6908 18150 : inAudio = masaInput->base.inputBuffer;
6909 18150 : IF( NE_32( masaInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6910 : {
6911 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Mismatch between the number of input samples vs number of requested output samples - currently not allowed" );
6912 : }
6913 18150 : masaInput->base.numNewSamplesPerChannel = 0;
6914 18150 : move32();
6915 :
6916 18150 : *outAudio.pq_fact = outAudio.q_factor;
6917 18150 : move16();
6918 : /* Apply input gain to new audio */
6919 18150 : v_multc_fixed( inAudio.data_fx, masaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
6920 18150 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
6921 18150 : move16();
6922 :
6923 18150 : maxBin = extract_l( Mpy_32_32( *masaInput->base.ctx.pOutSampleRate, INV_CLDFB_BANDWIDTH_Q31 ) ); /* Q0 */
6924 :
6925 : /* set combined orientation subframe info to start info */
6926 18150 : ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
6927 :
6928 18150 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
6929 : {
6930 : /* MASA prerendering path for MASA -> MASA */
6931 150 : renderMasaToMasa( masaInput, outAudio );
6932 : }
6933 : ELSE
6934 : {
6935 : /* MASA external renderer -> other formats */
6936 : Word16 num_subframes, exp;
6937 306000 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
6938 : {
6939 288000 : tmpBuffer_fx[ch] = tmpBuffer_buff_fx[ch];
6940 : }
6941 18000 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_buff_fx );
6942 :
6943 18000 : num_subframes = BASOP_Util_Divide3232_Scale( L_mult0( masaInput->base.inputBuffer.config.numSamplesPerChannel, IVAS_NUM_FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ), *masaInput->base.ctx.pOutSampleRate, &exp );
6944 18000 : num_subframes = shr( num_subframes, sub( 15, exp ) ); /* Q0 */
6945 :
6946 18000 : SWITCH( masaInput->hMasaExtRend->renderer_type )
6947 : {
6948 12750 : case RENDERER_DIRAC:
6949 :
6950 12750 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
6951 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 1 );
6952 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
6953 : {
6954 110250 : masaInput->hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state = Q11;
6955 110250 : move16();
6956 : }
6957 216750 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
6958 : {
6959 204000 : Scale_sig32( tmpBuffer_buff_fx[ch], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6960 : }
6961 :
6962 12750 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6963 :
6964 12750 : ivas_masa_ext_dirac_render_fx( masaInput->hMasaExtRend, tmpBuffer_fx, num_subframes );
6965 :
6966 12750 : *outAudio.pq_fact = Q11;
6967 12750 : move16();
6968 :
6969 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
6970 : {
6971 110250 : scale_sig32( masaInput->hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, masaInput->hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state ) ); /* Q11 */
6972 110250 : masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
6973 110250 : move16();
6974 : }
6975 :
6976 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 0 );
6977 12750 : BREAK;
6978 4500 : case RENDERER_STEREO_PARAMETRIC:
6979 : case RENDERER_BINAURAL_PARAMETRIC:
6980 : case RENDERER_BINAURAL_PARAMETRIC_ROOM:
6981 :
6982 4500 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
6983 :
6984 4500 : Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6985 4500 : Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6986 :
6987 4500 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
6988 :
6989 4500 : ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes );
6990 4500 : *outAudio.pq_fact = Q11;
6991 4500 : move16();
6992 4500 : BREAK;
6993 750 : case RENDERER_DISABLE:
6994 750 : BREAK; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
6995 0 : default:
6996 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
6997 : }
6998 :
6999 18000 : accumulate2dArrayToBuffer_fx( tmpBuffer_buff_fx, &outAudio );
7000 : }
7001 :
7002 18150 : return IVAS_ERR_OK;
7003 : }
7004 1114140 : static ivas_error renderActiveInputsMasa(
7005 : IVAS_REND_HANDLE hIvasRend,
7006 : IVAS_REND_AudioBuffer outAudio )
7007 : {
7008 : Word16 i;
7009 : input_masa *pCurrentInput;
7010 : ivas_error error;
7011 :
7012 2228280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMasa ); i < RENDERER_MAX_MASA_INPUTS; ( ++i, ++pCurrentInput ) )
7013 : {
7014 1114140 : IF( EQ_16( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7015 : {
7016 : /* Skip inactive inputs */
7017 1095990 : CONTINUE;
7018 : }
7019 :
7020 18150 : *outAudio.pq_fact = Q8;
7021 18150 : move16();
7022 :
7023 18150 : IF( NE_32( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
7024 : {
7025 0 : return error;
7026 : }
7027 : }
7028 :
7029 1114140 : return IVAS_ERR_OK;
7030 : }
7031 :
7032 : /*---------------------------------------------------------------------*
7033 : * IVAS_REND_GetMasaMetadata( )
7034 : *
7035 : * Get metadata of the estimated MASA frame
7036 : *---------------------------------------------------------------------*/
7037 :
7038 0 : ivas_error IVAS_REND_GetMasaMetadata(
7039 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7040 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to analyzed MASA metadata */
7041 : const IVAS_REND_AudioConfigType inputType /* i : Input type */
7042 : )
7043 : {
7044 0 : IF( hIvasRend == NULL )
7045 : {
7046 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7047 : }
7048 :
7049 : /* Get the metadata handle */
7050 0 : IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
7051 : {
7052 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7053 : }
7054 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
7055 : {
7056 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7057 : }
7058 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
7059 : {
7060 0 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7061 : }
7062 : ELSE
7063 : {
7064 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7065 : }
7066 :
7067 0 : return IVAS_ERR_OK;
7068 : }
7069 :
7070 :
7071 : /*---------------------------------------------------------------------*
7072 : * IVAS_REND_MergeMasaMetadata( )
7073 : *
7074 : * Merge MASA metadata from two formats
7075 : *---------------------------------------------------------------------*/
7076 :
7077 450 : ivas_error IVAS_REND_MergeMasaMetadata(
7078 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7079 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to merged metadata */
7080 : const IVAS_REND_AudioConfigType inputType1, /* i : Input type 1 */
7081 : const IVAS_REND_AudioConfigType inputType2 /* i : Input type 2 */
7082 : )
7083 : {
7084 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
7085 : Word32( *inEne1_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7086 : Word32( *inEne2_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7087 : Word16 *inEne1_e;
7088 : Word16 *inEne2_e;
7089 :
7090 450 : IF( hIvasRend == NULL )
7091 : {
7092 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7093 : }
7094 :
7095 : /* Input1 metadata and energy */
7096 450 : IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
7097 : {
7098 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7099 0 : inEne1_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
7100 0 : inEne1_e = ( hIvasRend->inputsIsm->hOMasa->energy_e );
7101 : }
7102 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
7103 : {
7104 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7105 0 : inEne1_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
7106 0 : inEne1_e = ( hIvasRend->inputsMc->hMcMasa->energy_exp );
7107 : }
7108 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
7109 : {
7110 450 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7111 450 : inEne1_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
7112 450 : inEne1_e = ( hIvasRend->inputsSba->hDirAC->energy_exp );
7113 : }
7114 0 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
7115 : {
7116 0 : *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7117 0 : inEne1_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
7118 0 : inEne1_e = ( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
7119 : }
7120 : ELSE
7121 : {
7122 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7123 : }
7124 :
7125 : /* Input2 metadata and energy */
7126 450 : IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
7127 : {
7128 150 : inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7129 150 : inEne2_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
7130 150 : inEne2_e = ( hIvasRend->inputsIsm->hOMasa->energy_e );
7131 : }
7132 300 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
7133 : {
7134 150 : inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7135 150 : inEne2_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
7136 150 : inEne2_e = ( hIvasRend->inputsMc->hMcMasa->energy_exp );
7137 : }
7138 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
7139 : {
7140 0 : inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
7141 0 : inEne2_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
7142 0 : inEne2_e = ( hIvasRend->inputsSba->hDirAC->energy_exp );
7143 : }
7144 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
7145 : {
7146 150 : inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7147 150 : inEne2_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
7148 150 : inEne2_e = ( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
7149 : }
7150 : ELSE
7151 : {
7152 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7153 : }
7154 :
7155 : /* Merge metadata */
7156 450 : ivas_prerend_merge_masa_metadata_fx( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1_fx, inEne1_e, inMeta2, inputType2, *inEne2_fx, inEne2_e );
7157 :
7158 :
7159 450 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
7160 : {
7161 0 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 0u;
7162 0 : move16();
7163 : }
7164 : ELSE
7165 : {
7166 450 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 1u;
7167 450 : move16();
7168 : }
7169 :
7170 450 : return IVAS_ERR_OK;
7171 : }
7172 :
7173 :
7174 : /*---------------------------------------------------------------------*
7175 : * IVAS_REND_SetTotalNumberOfObjects( )
7176 : *
7177 : * Set the total number of objects to the first object data
7178 : *---------------------------------------------------------------------*/
7179 :
7180 174 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
7181 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7182 : const UWord16 total_num_objects /* i : total number of objects */
7183 : )
7184 : {
7185 174 : IF( hIvasRend == NULL )
7186 : {
7187 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7188 : }
7189 :
7190 174 : hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
7191 174 : move16();
7192 :
7193 174 : return IVAS_ERR_OK;
7194 : }
7195 :
7196 :
7197 : /*---------------------------------------------------------------------*
7198 : * IVAS_REND_SetIsmMetadataDelay( )
7199 : *
7200 : * Set the Metadata Delay in ms in order to sync with audio delay
7201 : *---------------------------------------------------------------------*/
7202 174 : ivas_error IVAS_REND_SetIsmMetadataDelay(
7203 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7204 : const Word32 sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */
7205 : )
7206 : {
7207 : Word16 i;
7208 :
7209 174 : IF( hIvasRend == NULL )
7210 : {
7211 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7212 : }
7213 870 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
7214 : {
7215 696 : hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay;
7216 696 : move32();
7217 : }
7218 :
7219 174 : return IVAS_ERR_OK;
7220 : }
7221 :
7222 : /*-------------------------------------------------------------------*
7223 : * getSamplesInternal()
7224 : *
7225 : *
7226 : *-------------------------------------------------------------------*/
7227 :
7228 1114140 : static ivas_error getSamplesInternal(
7229 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7230 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7231 : )
7232 : {
7233 : ivas_error error;
7234 : Word16 numOutChannels;
7235 : /* Validate function arguments */
7236 1114140 : test();
7237 1114140 : IF( hIvasRend == NULL || outAudio.data_fx == NULL )
7238 : {
7239 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7240 : }
7241 :
7242 1114140 : test();
7243 1114140 : IF( outAudio.config.numSamplesPerChannel <= 0 || LT_16( MAX_BUFFER_LENGTH_PER_CHANNEL, outAudio.config.numSamplesPerChannel ) )
7244 : {
7245 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
7246 : }
7247 :
7248 1114140 : test();
7249 1114140 : IF( outAudio.config.numChannels <= 0 || LT_16( MAX_OUTPUT_CHANNELS, outAudio.config.numChannels ) )
7250 : {
7251 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7252 : }
7253 :
7254 1114140 : test();
7255 1114140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
7256 : NE_32( L_mult0( outAudio.config.numSamplesPerChannel, 1000 ), imult3216( hIvasRend->sampleRateOut, i_mult( hIvasRend->num_subframes, BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ) )
7257 : {
7258 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
7259 : }
7260 :
7261 : /* Check that there is allowed configuration for MASA format output */
7262 1114140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
7263 : {
7264 : Word16 i;
7265 150 : Word16 numMasaInputs = 0;
7266 150 : move16();
7267 150 : Word16 numOtherInputs = 0;
7268 150 : move16();
7269 :
7270 300 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
7271 : {
7272 : // numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7273 :
7274 150 : IF( EQ_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7275 : {
7276 0 : numMasaInputs = add( numMasaInputs, 0 );
7277 : }
7278 : ELSE
7279 : {
7280 150 : numMasaInputs = add( numMasaInputs, 1 );
7281 : }
7282 : }
7283 :
7284 300 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
7285 : {
7286 : // numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7287 :
7288 150 : IF( EQ_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7289 : {
7290 0 : numOtherInputs = add( numOtherInputs, 0 );
7291 : }
7292 : ELSE
7293 : {
7294 150 : numOtherInputs = add( numOtherInputs, 1 );
7295 : }
7296 : }
7297 :
7298 300 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
7299 : {
7300 : // numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7301 :
7302 150 : IF( EQ_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7303 : {
7304 0 : numOtherInputs = add( numOtherInputs, 0 );
7305 : }
7306 : ELSE
7307 : {
7308 150 : numOtherInputs = add( numOtherInputs, 1 );
7309 : }
7310 : }
7311 :
7312 : /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
7313 : // numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7314 150 : IF( EQ_32( hIvasRend->inputsIsm[0].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7315 : {
7316 0 : numOtherInputs = add( numOtherInputs, 0 );
7317 : }
7318 : ELSE
7319 : {
7320 150 : numOtherInputs = add( numOtherInputs, 1 );
7321 : }
7322 :
7323 150 : test();
7324 150 : IF( numMasaInputs == 0 || numOtherInputs == 0 )
7325 : {
7326 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
7327 : }
7328 : }
7329 :
7330 1114140 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
7331 : {
7332 0 : return error;
7333 : }
7334 :
7335 1114140 : IF( NE_16( numOutChannels, outAudio.config.numChannels ) )
7336 : {
7337 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7338 : }
7339 :
7340 : /* Clear original output buffer */
7341 1114140 : set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) );
7342 :
7343 1114140 : IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7344 : {
7345 0 : return error;
7346 : }
7347 1114140 : IF( NE_32( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7348 : {
7349 0 : return error;
7350 : }
7351 1114140 : IF( NE_32( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7352 : {
7353 0 : return error;
7354 : }
7355 1114140 : IF( NE_32( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7356 : {
7357 0 : return error;
7358 : }
7359 :
7360 1114140 : test();
7361 1114140 : test();
7362 :
7363 1114140 : Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact );
7364 1114140 : limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact );
7365 :
7366 : /* update global cominbed orientation start index */
7367 1114140 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
7368 :
7369 1114140 : return IVAS_ERR_OK;
7370 : }
7371 :
7372 : /*-------------------------------------------------------------------*
7373 : * IVAS_REND_GetSamples()
7374 : *
7375 : *
7376 : *-------------------------------------------------------------------*/
7377 :
7378 1114140 : ivas_error IVAS_REND_GetSamples(
7379 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7380 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7381 : )
7382 : {
7383 :
7384 1114140 : return getSamplesInternal( hIvasRend, outAudio );
7385 : }
7386 :
7387 :
7388 : /*-------------------------------------------------------------------*
7389 : * IVAS_REND_Close()
7390 : *
7391 : *
7392 : *-------------------------------------------------------------------*/
7393 :
7394 :
7395 658 : void IVAS_REND_Close(
7396 : IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
7397 : )
7398 : {
7399 : UWord16 i;
7400 : IVAS_REND_HANDLE hIvasRend;
7401 :
7402 : /* Validate function arguments */
7403 658 : test();
7404 658 : IF( phIvasRend == NULL || *phIvasRend == NULL )
7405 : {
7406 0 : return;
7407 : }
7408 658 : hIvasRend = *phIvasRend;
7409 :
7410 658 : IF( hIvasRend->efapOutWrapper.hEfap != NULL )
7411 : {
7412 463 : efap_free_data_fx( &hIvasRend->efapOutWrapper.hEfap );
7413 : }
7414 :
7415 : /* clear inputs */
7416 3290 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
7417 : {
7418 2632 : clearInputIsm( &hIvasRend->inputsIsm[i] );
7419 : }
7420 1316 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
7421 : {
7422 658 : clearInputMc( &hIvasRend->inputsMc[i] );
7423 : }
7424 1316 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
7425 : {
7426 658 : clearInputSba( &hIvasRend->inputsSba[i] );
7427 : }
7428 1316 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
7429 : {
7430 658 : clearInputMasa( &hIvasRend->inputsMasa[i] );
7431 : }
7432 :
7433 : /* clear Config. Renderer */
7434 658 : ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
7435 :
7436 658 : ivas_limiter_close_fx( &hIvasRend->hLimiter );
7437 :
7438 :
7439 658 : closeHeadRotation( hIvasRend );
7440 :
7441 658 : ivas_external_orientation_close_fx( &hIvasRend->hExternalOrientationData );
7442 658 : ivas_combined_orientation_close_fx( &hIvasRend->hCombinedOrientationData );
7443 :
7444 658 : free( hIvasRend );
7445 658 : *phIvasRend = NULL;
7446 :
7447 658 : return;
7448 : }
7449 :
7450 34 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
7451 : input_masa *inputMasa )
7452 : {
7453 : Word16 nchan_out_woLFE;
7454 : Word16 nchan_transport;
7455 : UWord16 i, j, k;
7456 : Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
7457 : Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
7458 : Word32 output_Fs;
7459 : ivas_error error;
7460 : DIRAC_REND_HANDLE hDirACRend;
7461 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
7462 :
7463 34 : error = IVAS_ERR_OK;
7464 34 : move32();
7465 :
7466 34 : hDirACRend = NULL;
7467 34 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
7468 34 : move32();
7469 :
7470 34 : hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
7471 :
7472 : /*-----------------------------------------------------------------*
7473 : * prepare library opening
7474 : *-----------------------------------------------------------------*/
7475 :
7476 34 : IF( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
7477 : {
7478 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
7479 : }
7480 :
7481 34 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
7482 : {
7483 18 : nchan_transport = 2;
7484 18 : move16();
7485 : }
7486 : ELSE
7487 : {
7488 16 : nchan_transport = 1;
7489 16 : move16();
7490 : }
7491 :
7492 : /*-----------------------------------------------------------------*
7493 : * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
7494 : *-----------------------------------------------------------------*/
7495 :
7496 34 : ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
7497 :
7498 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
7499 : {
7500 : /* Copy from ivas_ls_custom_setup */
7501 0 : hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
7502 0 : move16();
7503 0 : hDirACRend->hOutSetup.ls_azimuth_fx = inputMasa->base.ctx.pCustomLsOut->ls_azimuth_fx;
7504 0 : hDirACRend->hOutSetup.ls_elevation_fx = inputMasa->base.ctx.pCustomLsOut->ls_elevation_fx;
7505 :
7506 0 : hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
7507 0 : move16();
7508 0 : hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
7509 0 : move16();
7510 :
7511 0 : hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
7512 0 : move16();
7513 0 : hDirACRend->hOutSetup.is_planar_setup = (Word8) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
7514 0 : move16();
7515 : }
7516 :
7517 34 : nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
7518 34 : move16();
7519 :
7520 34 : test();
7521 34 : IF( hDirACRend->hOutSetup.ls_azimuth_fx != NULL && hDirACRend->hOutSetup.ls_elevation_fx != NULL )
7522 : {
7523 20 : Copy32( hDirACRend->hOutSetup.ls_azimuth_fx, ls_azimuth_fx, nchan_out_woLFE );
7524 20 : Copy32( hDirACRend->hOutSetup.ls_elevation_fx, ls_elevation_fx, nchan_out_woLFE );
7525 : }
7526 :
7527 34 : IF( EQ_16( hDirACRend->hOutSetup.ambisonics_order, -1 ) )
7528 : {
7529 22 : hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
7530 22 : move16();
7531 22 : test();
7532 22 : if ( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_STEREO ) )
7533 : {
7534 2 : hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
7535 2 : move16();
7536 : }
7537 : }
7538 12 : ELSE IF( GE_16( hDirACRend->hOutSetup.ambisonics_order, SBA_FOA_ORDER ) )
7539 : {
7540 12 : Copy32( ls_azimuth_4d4_fx, ls_azimuth_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
7541 12 : Copy32( ls_elevation_4d4_fx, ls_elevation_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
7542 : }
7543 :
7544 : /*-----------------------------------------------------------------*
7545 : * set input parameters
7546 : *-----------------------------------------------------------------*/
7547 :
7548 34 : test();
7549 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
7550 : {
7551 2 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
7552 2 : move32();
7553 2 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
7554 2 : move32();
7555 2 : nchan_out_woLFE = 1;
7556 2 : move16();
7557 : }
7558 32 : ELSE IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
7559 : {
7560 20 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
7561 20 : hDirACRend->panningConf = DIRAC_PANNING_VBAP;
7562 20 : move32();
7563 20 : move32();
7564 : }
7565 12 : ELSE IF( !hDirACRend->hOutSetup.is_loudspeaker_setup && GT_16( nchan_transport, 1 ) )
7566 : {
7567 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
7568 6 : move32();
7569 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
7570 6 : move32();
7571 : }
7572 : ELSE
7573 : {
7574 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
7575 6 : move32();
7576 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
7577 6 : move32();
7578 : }
7579 :
7580 34 : IF( ( hDirACRend->frequency_axis_fx = (Word16 *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( Word16 ) ) ) == NULL )
7581 : {
7582 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7583 : }
7584 34 : set16_fx( hDirACRend->frequency_axis_fx, 0, hSpatParamRendCom->num_freq_bands );
7585 34 : ivas_dirac_dec_get_frequency_axis_fx( hDirACRend->frequency_axis_fx, output_Fs, hSpatParamRendCom->num_freq_bands );
7586 :
7587 :
7588 34 : test();
7589 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) && EQ_16( nchan_transport, 2 ) )
7590 : {
7591 8 : IF( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
7592 : {
7593 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7594 : }
7595 8 : ivas_masa_init_stereotype_detection_fx( hDirACRend->masa_stereo_type_detect );
7596 : }
7597 : ELSE
7598 : {
7599 26 : hDirACRend->masa_stereo_type_detect = NULL;
7600 : }
7601 :
7602 34 : hSpatParamRendCom->numIsmDirections = 0;
7603 34 : move16();
7604 :
7605 : /*-----------------------------------------------------------------*
7606 : * (re)configure sub-modules
7607 : *-----------------------------------------------------------------*/
7608 :
7609 : /* prototype signal computation */
7610 : /* allocate output setup related arrays */
7611 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
7612 : {
7613 : /* Directional and diffuses components in output LS format */
7614 20 : hDirACRend->num_outputs_diff = nchan_out_woLFE;
7615 20 : move16();
7616 20 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
7617 20 : move16();
7618 : }
7619 14 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7620 : {
7621 : /* Directional and diffuses components in SHD */
7622 : /* Diffuseness components up to 1st order */
7623 6 : hDirACRend->num_outputs_diff = imult1616( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ), ( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ) ) );
7624 6 : hDirACRend->num_outputs_dir = ivas_sba_get_nchan_fx( hDirACRend->hOutSetup.ambisonics_order, 0 );
7625 : }
7626 8 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
7627 : {
7628 6 : hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
7629 6 : move16();
7630 6 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
7631 6 : move16();
7632 : }
7633 2 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
7634 : {
7635 2 : hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
7636 2 : move16();
7637 2 : hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
7638 2 : move16();
7639 : }
7640 : ELSE
7641 : {
7642 0 : assert( 0 && "DirAC: not existing synthesis methods!" );
7643 : }
7644 :
7645 34 : IF( ( hDirACRend->proto_index_dir = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
7646 : {
7647 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7648 : }
7649 :
7650 34 : IF( ( hDirACRend->proto_index_diff = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_diff ) ) == NULL )
7651 : {
7652 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7653 : }
7654 :
7655 34 : set16_fx( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
7656 34 : set16_fx( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
7657 :
7658 34 : hDirACRend->sba_map_tc = sba_map_tc;
7659 :
7660 34 : IF( EQ_16( nchan_transport, 1 ) )
7661 : {
7662 16 : hDirACRend->num_protos_ambi = 1;
7663 16 : move16();
7664 16 : hDirACRend->num_protos_dir = 1;
7665 16 : move16();
7666 16 : hDirACRend->num_protos_diff = 1;
7667 16 : move16();
7668 : }
7669 18 : ELSE IF( EQ_16( nchan_transport, 2 ) )
7670 : {
7671 18 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7672 : {
7673 0 : hDirACRend->num_protos_ambi = 2;
7674 0 : move16();
7675 0 : hDirACRend->num_protos_diff = 1;
7676 0 : move16();
7677 0 : hDirACRend->num_protos_dir = 2;
7678 0 : move16();
7679 0 : hDirACRend->proto_index_dir[1] = 1;
7680 0 : move16();
7681 : }
7682 18 : ELSE IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
7683 : {
7684 : /* Following the foa rendering for code compatibility */
7685 2 : hDirACRend->num_protos_ambi = 2;
7686 2 : move16();
7687 2 : hDirACRend->num_protos_dir = 2;
7688 2 : move16();
7689 2 : hDirACRend->num_protos_diff = 3;
7690 2 : move16();
7691 2 : hDirACRend->proto_index_dir[0] = 0;
7692 2 : move16();
7693 2 : hDirACRend->proto_index_diff[0] = 0;
7694 2 : move16();
7695 : }
7696 : ELSE
7697 : {
7698 16 : hDirACRend->num_protos_ambi = 2;
7699 16 : move16();
7700 16 : hDirACRend->num_protos_diff = 3;
7701 16 : move16();
7702 :
7703 142 : FOR( k = 0; k < hDirACRend->num_outputs_diff; k++ )
7704 : {
7705 126 : IF( ls_azimuth_fx[k] > 0 )
7706 : {
7707 58 : hDirACRend->proto_index_diff[k] = 1;
7708 : }
7709 68 : ELSE IF( ls_azimuth_fx[k] < 0 )
7710 : {
7711 58 : hDirACRend->proto_index_diff[k] = 2;
7712 : }
7713 : ELSE
7714 : {
7715 10 : hDirACRend->proto_index_diff[k] = 0;
7716 : }
7717 126 : move16();
7718 : }
7719 :
7720 16 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
7721 : {
7722 10 : hDirACRend->num_protos_dir = 3;
7723 10 : move16();
7724 10 : Copy( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
7725 : }
7726 : ELSE
7727 : {
7728 6 : hDirACRend->num_protos_dir = 2;
7729 6 : move16();
7730 6 : hDirACRend->proto_index_dir[1] = 1;
7731 6 : move16();
7732 : }
7733 : }
7734 : }
7735 :
7736 : /* direct/diffuse responses */
7737 :
7738 34 : IF( ( hDirACRend->diffuse_response_function_fx = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
7739 : {
7740 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7741 : }
7742 :
7743 34 : test();
7744 34 : test();
7745 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
7746 : {
7747 28 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
7748 28 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
7749 : }
7750 : ELSE
7751 : {
7752 6 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
7753 6 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
7754 : }
7755 :
7756 34 : hDirACRend->hoa_encoder_fx = NULL;
7757 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
7758 : {
7759 6 : IF( ( hDirACRend->hoa_encoder_fx = (Word32 *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( Word32 ) ) ) == NULL )
7760 : {
7761 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7762 : }
7763 :
7764 6 : set32_fx( hDirACRend->hoa_encoder_fx, 0, imult1616( nchan_out_woLFE, hDirACRend->num_outputs_diff ) );
7765 6 : compute_hoa_encoder_mtx_fx( ls_azimuth_fx, ls_elevation_fx, hDirACRend->hoa_encoder_fx, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
7766 : }
7767 :
7768 : /* VBAP */
7769 34 : inputMasa->hMasaExtRend->hVBAPdata = NULL;
7770 :
7771 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_VBAP ) )
7772 : {
7773 20 : IF( NE_32( ( error = vbap_init_data_fx( &( inputMasa->hMasaExtRend->hVBAPdata ), ls_azimuth_fx, ls_elevation_fx, nchan_out_woLFE, MASA_FORMAT ) ), IVAS_ERR_OK ) )
7774 : {
7775 0 : return error;
7776 : }
7777 : }
7778 :
7779 : /* HOA panning/dec */
7780 34 : hDirACRend->hoa_decoder = NULL;
7781 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) )
7782 : {
7783 14 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
7784 : {
7785 2 : IF( NE_32( ( error = ivas_sba_get_hoa_dec_matrix_fx( hDirACRend->hOutSetup, &inputMasa->hMasaExtRend->hoa_dec_mtx, hDirACRend->hOutSetup.ambisonics_order ) ), IVAS_ERR_OK ) )
7786 : {
7787 0 : return error;
7788 : }
7789 :
7790 2 : hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
7791 : }
7792 : }
7793 :
7794 : /* decorrelation */
7795 34 : hDirACRend->proto_signal_decorr_on = 1;
7796 34 : move16();
7797 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
7798 : {
7799 2 : hDirACRend->proto_signal_decorr_on = 0;
7800 2 : move16();
7801 : }
7802 :
7803 34 : IF( hDirACRend->proto_signal_decorr_on )
7804 : {
7805 32 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDirACRend->h_freq_domain_decorr_ap_params ),
7806 : &( hDirACRend->h_freq_domain_decorr_ap_state ),
7807 : hSpatParamRendCom->num_freq_bands,
7808 : hDirACRend->num_outputs_diff,
7809 : hDirACRend->num_protos_diff,
7810 : hDirACRend->synthesisConf,
7811 : hDirACRend->frequency_axis_fx,
7812 : nchan_transport,
7813 : output_Fs ) ),
7814 : IVAS_ERR_OK ) )
7815 : {
7816 0 : return error;
7817 : }
7818 : }
7819 :
7820 : /* output synthesis */
7821 34 : IF( NE_32( ( ivas_dirac_dec_output_synthesis_open_fx( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ), IVAS_ERR_OK ) )
7822 : {
7823 0 : return error;
7824 : }
7825 34 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
7826 34 : move16();
7827 :
7828 34 : test();
7829 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7830 : {
7831 12 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
7832 12 : move16();
7833 : }
7834 :
7835 : /*-----------------------------------------------------------------*
7836 : * memory allocation
7837 : *-----------------------------------------------------------------*/
7838 :
7839 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7840 : {
7841 6 : hDirACRend->proto_frame_f_fx = NULL;
7842 : }
7843 : ELSE
7844 : {
7845 28 : IF( ( hDirACRend->proto_frame_f_fx = (Word32 *) malloc( sizeof( Word32 ) * shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 ) ) ) == NULL )
7846 : {
7847 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7848 : }
7849 28 : hDirACRend->proto_frame_f_len = shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 );
7850 28 : move16();
7851 : }
7852 :
7853 :
7854 34 : hDirACRend->buffer_energy_fx = NULL;
7855 136 : FOR( i = 0; i < DIRAC_NUM_DIMS; i++ )
7856 : {
7857 3366 : FOR( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
7858 : {
7859 3264 : hDirACRend->buffer_intensity_real_fx[i][j] = NULL;
7860 : }
7861 : }
7862 :
7863 : /* output synthesis */
7864 34 : ivas_dirac_dec_output_synthesis_init_fx( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
7865 :
7866 : /* Allocate stack memory */
7867 34 : IF( NE_32( ( error = ivas_dirac_alloc_mem_fx( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ), IVAS_ERR_OK ) )
7868 : {
7869 0 : return error;
7870 : }
7871 :
7872 34 : inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
7873 :
7874 34 : return error;
7875 : }
7876 :
7877 :
7878 12 : static ivas_error ivas_masa_ext_rend_parambin_init(
7879 : input_masa *inputMasa /* i/o: MASA external renderer structure */
7880 : )
7881 : {
7882 : DIRAC_DEC_BIN_HANDLE hDiracDecBin;
7883 : HRTFS_PARAMBIN_HANDLE hHrtfParambin;
7884 : Word16 nBins;
7885 : Word32 output_Fs;
7886 : RENDERER_TYPE renderer_type;
7887 : Word16 j, k, bin;
7888 : Word32 binCenterFreq_fx;
7889 : Word16 tmpFloat_fx;
7890 : ivas_error error;
7891 : Word16 frequency_axis_fx[CLDFB_NO_CHANNELS_MAX];
7892 : Word16 tmp;
7893 : Word16 tmp_e;
7894 : Word16 tmp2;
7895 :
7896 12 : error = IVAS_ERR_OK;
7897 12 : move32();
7898 :
7899 12 : hHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
7900 :
7901 : /* Set common variables and defaults */
7902 12 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
7903 12 : move32();
7904 12 : nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
7905 12 : move16();
7906 12 : renderer_type = inputMasa->hMasaExtRend->renderer_type;
7907 12 : move32();
7908 :
7909 12 : hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin;
7910 :
7911 : /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
7912 12 : IF( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
7913 : {
7914 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
7915 : }
7916 :
7917 12 : hDiracDecBin->hTdDecorr = NULL;
7918 12 : hDiracDecBin->hReverb = NULL;
7919 12 : hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
7920 12 : hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
7921 12 : hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
7922 12 : hDiracDecBin->useTdDecorr = 0; /* Always use frequency domain decorrelator in external renderer */
7923 12 : move16();
7924 :
7925 36 : FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
7926 : {
7927 168 : FOR( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
7928 : {
7929 144 : set16_fx( hDiracDecBin->processMtxRe_fx[j][k], 0, nBins );
7930 144 : set16_fx( hDiracDecBin->processMtxIm_fx[j][k], 0, nBins );
7931 : }
7932 :
7933 72 : FOR( k = 0; k < BINAURAL_CHANNELS; k++ )
7934 : {
7935 48 : set16_fx( hDiracDecBin->processMtxDecRe_fx[j][k], 0, nBins );
7936 48 : set16_fx( hDiracDecBin->processMtxDecIm_fx[j][k], 0, nBins );
7937 : }
7938 24 : hDiracDecBin->q_processMtx = Q15;
7939 24 : hDiracDecBin->q_processMtxSCCR = Q15;
7940 24 : hDiracDecBin->q_processMtxPrev = Q15;
7941 24 : hDiracDecBin->q_processMtxPrevSCCR = Q15;
7942 24 : hDiracDecBin->q_processMtxDec = Q15;
7943 24 : hDiracDecBin->q_processMtxDecPrev = Q15;
7944 24 : move16();
7945 24 : move16();
7946 24 : move16();
7947 24 : move16();
7948 24 : move16();
7949 24 : move16();
7950 24 : set_zero_fx( hDiracDecBin->ChEnePrev_fx[j], nBins );
7951 24 : set_zero_fx( hDiracDecBin->ChEneOutPrev_fx[j], nBins );
7952 24 : set16_fx( hDiracDecBin->ChEnePrev_e[j], 0, nBins );
7953 24 : set16_fx( hDiracDecBin->ChEneOutPrev_e[j], 0, nBins );
7954 : }
7955 12 : set_zero_fx( hDiracDecBin->ChCrossRePrev_fx, nBins );
7956 12 : set_zero_fx( hDiracDecBin->ChCrossImPrev_fx, nBins );
7957 12 : set_zero_fx( hDiracDecBin->ChCrossReOutPrev_fx, nBins );
7958 12 : set_zero_fx( hDiracDecBin->ChCrossImOutPrev_fx, nBins );
7959 12 : set16_fx( hDiracDecBin->ChCrossRePrev_e, 0, nBins );
7960 12 : set16_fx( hDiracDecBin->ChCrossImPrev_e, 0, nBins );
7961 12 : set16_fx( hDiracDecBin->ChCrossReOutPrev_e, 0, nBins );
7962 12 : set16_fx( hDiracDecBin->ChCrossImOutPrev_e, 0, nBins );
7963 12 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
7964 12 : move16();
7965 :
7966 732 : FOR( bin = 0; bin < nBins; bin++ )
7967 : {
7968 720 : binCenterFreq_fx = L_mult0( extract_l( L_shr( output_Fs, 1 ) ), div_s( add( shl( bin, 1 ), 1 ), shl( nBins, 1 ) ) ) /*( (float) bin + 0.5f ) / (float) nBins * ( (float) output_Fs / 2.0f )*/; /*Q15*/
7969 : /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
7970 720 : tmp = BASOP_Util_Divide3232_Scale( binCenterFreq_fx, L_shl( 2700, Q15 ), &tmp_e );
7971 720 : IF( tmp_e < 0 )
7972 : {
7973 36 : tmp = shl( tmp, tmp_e ); /*q15*/
7974 36 : tmp_e = 0;
7975 36 : move16();
7976 : }
7977 720 : tmpFloat_fx = s_max( 0, sub( shl_sat( 1, sub( 15, tmp_e ) ), tmp ) ) /*max( 0.0f, 1.0f - binCenterFreq / 2700.0f )*/; /*Q30*/
7978 720 : tmp2 = extract_l( Mult_32_32( binCenterFreq_fx, 1952258 /*=2^31*180/(550)/360*/ ) % 32767 ); //*binCenterFreq_fx * EVS_PI / 550.0f*/
7979 720 : hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( L_mult0( divide3232( tmpFloat_fx, Mult_32_16( binCenterFreq_fx, 187 /*2^15*pi/550*/ ) ), getSineWord16R2( tmp2 ) ), tmp_e ); /*tmpFloat * sinf( binCenterFreq * EVS_PI / 550.0f ) / ( binCenterFreq * EVS_PI / 550.0f );*/
7980 720 : hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( hDiracDecBin->diffuseFieldCoherence_fx[bin], 1 ); /* Q31 */
7981 720 : move32();
7982 720 : move32();
7983 : }
7984 :
7985 : /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
7986 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceX_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
7987 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceY_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
7988 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceZ_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
7989 :
7990 12 : IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC ) ) /* Indication of binaural rendering without room effect */
7991 : {
7992 8 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
7993 8 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
7994 8 : move16();
7995 8 : hDiracDecBin->hReverb = NULL;
7996 : }
7997 4 : ELSE IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) /* Indication of binaural rendering with room effect */
7998 : {
7999 0 : Copy32( hHrtfParambin->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
8000 0 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
8001 0 : move16();
8002 :
8003 0 : IF( hDiracDecBin->hReverb == NULL )
8004 : {
8005 : /* Todo Philips: Room acoustics should be passed here once the underlying part works. In this case, it probably should come from render context or somewhere else suitable. */
8006 0 : IF( NE_32( ( error = ivas_binaural_reverb_open_parambin( &hDiracDecBin->hReverb, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, NULL, output_Fs, hHrtfParambin ) ), IVAS_ERR_OK ) )
8007 : {
8008 0 : return error;
8009 : }
8010 : }
8011 : }
8012 4 : ELSE IF( EQ_16( renderer_type, RENDERER_STEREO_PARAMETRIC ) )
8013 : {
8014 4 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
8015 4 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
8016 4 : move16();
8017 4 : hDiracDecBin->hReverb = NULL;
8018 4 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
8019 4 : move16();
8020 : }
8021 : ELSE /* Not valid renderer type for this renderer */
8022 : {
8023 0 : assert( false );
8024 : }
8025 :
8026 : /* Always open frequency domain decorrelator */
8027 12 : ivas_dirac_dec_get_frequency_axis_fx( frequency_axis_fx, output_Fs, nBins );
8028 :
8029 12 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
8030 : &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
8031 : nBins,
8032 : BINAURAL_CHANNELS,
8033 : BINAURAL_CHANNELS,
8034 : DIRAC_SYNTHESIS_PSD_LS,
8035 : frequency_axis_fx,
8036 : BINAURAL_CHANNELS,
8037 : output_Fs ) ),
8038 : IVAS_ERR_OK ) )
8039 : {
8040 0 : return error;
8041 : }
8042 : /* External renderer uses constant regularization factor */
8043 12 : hDiracDecBin->reqularizationFactor_fx = 6554; /* 0.4f in Q14 */
8044 12 : move16();
8045 :
8046 12 : inputMasa->hMasaExtRend->hDiracDecBin = hDiracDecBin;
8047 :
8048 12 : return error;
8049 : }
8050 :
8051 48 : static ivas_error initMasaExtRenderer(
8052 : input_masa *inputMasa,
8053 : const AUDIO_CONFIG outConfig )
8054 : {
8055 : Word16 i;
8056 : ivas_error error;
8057 : MASA_EXT_REND_HANDLE hMasaExtRend;
8058 :
8059 48 : error = IVAS_ERR_OK;
8060 48 : move32();
8061 :
8062 48 : IF( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
8063 : {
8064 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
8065 : }
8066 :
8067 48 : inputMasa->hMasaExtRend = hMasaExtRend;
8068 :
8069 : /* Default init */
8070 48 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
8071 48 : move32();
8072 48 : hMasaExtRend->hDirACRend = NULL;
8073 48 : hMasaExtRend->hSpatParamRendCom = NULL;
8074 48 : hMasaExtRend->hDiracDecBin = NULL;
8075 48 : hMasaExtRend->hReverb = NULL;
8076 48 : hMasaExtRend->hHrtfParambin = NULL;
8077 48 : hMasaExtRend->hVBAPdata = NULL;
8078 48 : hMasaExtRend->hoa_dec_mtx = NULL;
8079 :
8080 48 : IF( NE_32( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ), IVAS_ERR_OK ) )
8081 : {
8082 0 : return error;
8083 : }
8084 :
8085 48 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ), IVAS_ERR_OK ) )
8086 : {
8087 0 : return error;
8088 : }
8089 :
8090 48 : SWITCH( outConfig )
8091 : {
8092 4 : case IVAS_AUDIO_CONFIG_MONO:
8093 4 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
8094 : {
8095 2 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
8096 2 : move32();
8097 : }
8098 : ELSE
8099 : {
8100 : /* 1TC MASA to mono does not need rendering. */
8101 2 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
8102 2 : move32();
8103 : }
8104 4 : BREAK;
8105 :
8106 4 : case IVAS_AUDIO_CONFIG_STEREO:
8107 4 : hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
8108 4 : move32();
8109 4 : BREAK;
8110 :
8111 32 : case IVAS_AUDIO_CONFIG_5_1:
8112 : case IVAS_AUDIO_CONFIG_7_1:
8113 : case IVAS_AUDIO_CONFIG_5_1_2:
8114 : case IVAS_AUDIO_CONFIG_5_1_4:
8115 : case IVAS_AUDIO_CONFIG_7_1_4:
8116 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
8117 : case IVAS_AUDIO_CONFIG_FOA:
8118 : case IVAS_AUDIO_CONFIG_HOA2:
8119 : case IVAS_AUDIO_CONFIG_HOA3:
8120 32 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
8121 32 : move32();
8122 32 : BREAK;
8123 :
8124 8 : case IVAS_AUDIO_CONFIG_BINAURAL:
8125 8 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
8126 8 : move32();
8127 8 : BREAK;
8128 :
8129 0 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
8130 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
8131 0 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
8132 0 : move32();
8133 0 : BREAK;
8134 :
8135 0 : default:
8136 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
8137 : }
8138 :
8139 48 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
8140 : {
8141 : Word16 subframe;
8142 46 : IF( NE_32( ( error = ivas_spat_hSpatParamRendCom_config_fx( &hMasaExtRend->hSpatParamRendCom, DIRAC_OPEN, 0, MASA_FORMAT, MC_MODE_NONE, *( inputMasa->base.ctx.pOutSampleRate ), 0, 1 ) ), IVAS_ERR_OK ) )
8143 : {
8144 0 : return error;
8145 : }
8146 : /* Simple population of the metadata index map as no adaptation is present */
8147 46 : set16_fx( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
8148 230 : FOR( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
8149 : {
8150 184 : hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
8151 184 : move16();
8152 : }
8153 46 : hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
8154 46 : move16();
8155 : }
8156 :
8157 48 : IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_DIRAC ) )
8158 : {
8159 34 : IF( NE_32( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ), IVAS_ERR_OK ) )
8160 : {
8161 0 : return error;
8162 : }
8163 : }
8164 :
8165 48 : test();
8166 48 : test();
8167 48 : IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) || EQ_16( hMasaExtRend->renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) || EQ_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
8168 : {
8169 12 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
8170 : {
8171 8 : IF( NE_32( ( error = ivas_dirac_dec_binaural_copy_hrtfs_fx( &inputMasa->hMasaExtRend->hHrtfParambin ) ), IVAS_ERR_OK ) )
8172 : {
8173 0 : return error;
8174 : }
8175 : }
8176 :
8177 12 : IF( NE_32( ( error = ivas_masa_ext_rend_parambin_init( inputMasa ) ), IVAS_ERR_OK ) )
8178 : {
8179 0 : return error;
8180 : }
8181 : }
8182 :
8183 : /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
8184 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
8185 : {
8186 96 : hMasaExtRend->cldfbAnaRend[i] = NULL;
8187 : }
8188 :
8189 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
8190 : {
8191 768 : hMasaExtRend->cldfbSynRend[i] = NULL;
8192 : }
8193 :
8194 48 : IF( NE_32( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
8195 : {
8196 116 : FOR( i = 0; i < hMasaExtRend->nchan_input; i++ )
8197 : {
8198 70 : IF( NE_32( ( error = openCldfb_ivas_fx( &( hMasaExtRend->cldfbAnaRend[i] ), CLDFB_ANALYSIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS, DEC ) ), IVAS_ERR_OK ) )
8199 : {
8200 0 : return error;
8201 : }
8202 : }
8203 :
8204 364 : FOR( i = 0; i < hMasaExtRend->nchan_output; i++ )
8205 : {
8206 318 : IF( NE_32( ( error = openCldfb_ivas_fx( &( hMasaExtRend->cldfbSynRend[i] ), CLDFB_SYNTHESIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS, DEC ) ), IVAS_ERR_OK ) )
8207 : {
8208 0 : return error;
8209 : }
8210 : }
8211 : }
8212 :
8213 48 : inputMasa->hMasaExtRend = hMasaExtRend;
8214 :
8215 48 : return IVAS_ERR_OK;
8216 : }
8217 :
8218 658 : static void freeMasaExtRenderer(
8219 : MASA_EXT_REND_HANDLE *hMasaExtRendOut )
8220 : {
8221 : MASA_EXT_REND_HANDLE hMasaExtRend;
8222 : Word16 i;
8223 :
8224 658 : test();
8225 658 : IF( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
8226 : {
8227 610 : return;
8228 : }
8229 :
8230 48 : hMasaExtRend = *hMasaExtRendOut;
8231 :
8232 48 : IF( hMasaExtRend->hDirACRend != NULL )
8233 : {
8234 34 : ivas_dirac_rend_close_fx( &hMasaExtRend->hDirACRend );
8235 : }
8236 :
8237 48 : IF( hMasaExtRend->hSpatParamRendCom != NULL )
8238 : {
8239 46 : ivas_spat_hSpatParamRendCom_close_fx( &hMasaExtRend->hSpatParamRendCom );
8240 : }
8241 :
8242 48 : IF( hMasaExtRend->hDiracDecBin != NULL )
8243 : {
8244 12 : ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin );
8245 : }
8246 :
8247 48 : IF( hMasaExtRend->hReverb != NULL )
8248 : {
8249 0 : ivas_binaural_reverb_close_fx( &hMasaExtRend->hReverb );
8250 : }
8251 :
8252 48 : IF( hMasaExtRend->hHrtfParambin != NULL )
8253 : {
8254 8 : ivas_HRTF_parambin_binary_close_fx( &hMasaExtRend->hHrtfParambin );
8255 : }
8256 :
8257 48 : IF( hMasaExtRend->hVBAPdata != NULL )
8258 : {
8259 20 : vbap_free_data_fx( &hMasaExtRend->hVBAPdata );
8260 : }
8261 :
8262 48 : IF( hMasaExtRend->hoa_dec_mtx != NULL )
8263 : {
8264 2 : free( hMasaExtRend->hoa_dec_mtx );
8265 : }
8266 :
8267 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
8268 : {
8269 96 : IF( hMasaExtRend->cldfbAnaRend[i] != NULL )
8270 : {
8271 70 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbAnaRend[i] );
8272 : }
8273 : }
8274 :
8275 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
8276 : {
8277 768 : IF( hMasaExtRend->cldfbSynRend[i] != NULL )
8278 : {
8279 318 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbSynRend[i] );
8280 : }
8281 : }
8282 :
8283 48 : free( hMasaExtRend );
8284 48 : *hMasaExtRendOut = NULL;
8285 :
8286 48 : return;
8287 : }
8288 :
8289 25500 : static void intermidiate_ext_dirac_render(
8290 : MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure */
8291 : Word16 to_fix )
8292 : {
8293 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
8294 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
8295 : DIRAC_DEC_STACK_MEM DirAC_mem;
8296 : Word16 ch;
8297 : DIRAC_REND_HANDLE hDirACRend;
8298 : Word16 subframe_idx;
8299 : Word16 slot_idx;
8300 : Word16 nchan_transport;
8301 : Word16 tmp;
8302 :
8303 25500 : hDirACRend = hMasaExtRend->hDirACRend;
8304 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
8305 25500 : nchan_transport = hMasaExtRend->nchan_input;
8306 : DIRAC_OUTPUT_SYNTHESIS_STATE *h_dirac_output_synthesis_state;
8307 :
8308 25500 : h_dirac_output_synthesis_state = &( hDirACRend->h_output_synthesis_psd_state );
8309 :
8310 25500 : subframe_idx = hSpatParamRendCom->subframes_rendered;
8311 25500 : move16();
8312 :
8313 25500 : DirAC_mem = hDirACRend->stack_mem;
8314 :
8315 25500 : IF( to_fix )
8316 : {
8317 : #ifdef FIX_867_CLDFB_NRG_SCALE
8318 12750 : DirAC_mem.reference_power_smooth_q[0] = DirAC_mem.reference_power_q[0] = Q31;
8319 12750 : DirAC_mem.reference_power_smooth_q[1] = DirAC_mem.reference_power_q[1] = Q31;
8320 12750 : move16();
8321 12750 : move16();
8322 : #else
8323 : DirAC_mem.reference_power_smooth_q = DirAC_mem.reference_power_q = Q31;
8324 : move16();
8325 : #endif
8326 12750 : move16();
8327 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
8328 : {
8329 30736 : Scale_sig32( hDirACRend->h_output_synthesis_psd_state.direct_responses_fx, i_mult( hSpatParamRendCom->num_freq_bands, hDirACRend->num_outputs_dir ), sub( Q30, hDirACRend->h_output_synthesis_psd_state.direct_responses_q ) ); /* Q30 */
8330 30736 : hDirACRend->h_output_synthesis_psd_state.direct_responses_q = Q30;
8331 30736 : move16();
8332 : }
8333 :
8334 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx )
8335 : {
8336 12750 : Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_len );
8337 12750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth + shift) */
8338 12750 : hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth = add( hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth, shift );
8339 12750 : move16();
8340 : }
8341 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx )
8342 : {
8343 12750 : Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_len );
8344 12750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth_prev + shift) */
8345 12750 : hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth_prev = add( hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth_prev, shift );
8346 12750 : move16();
8347 : }
8348 :
8349 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx )
8350 : {
8351 10500 : Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx, imult1616( hDirACRend->num_outputs_dir, hSpatParamRendCom->num_freq_bands ) );
8352 10500 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth + shift) */
8353 10500 : hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth = add( hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth, shift );
8354 10500 : move16();
8355 : }
8356 :
8357 12750 : Word16 num_channels_dir = hDirACRend->num_outputs_dir;
8358 12750 : move16();
8359 :
8360 12750 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
8361 : {
8362 7500 : num_channels_dir = hDirACRend->hOutSetup.nchan_out_woLFE;
8363 7500 : move16();
8364 : }
8365 :
8366 12750 : IF( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx )
8367 : {
8368 12750 : tmp = L_norm_arr( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, imult1616( num_channels_dir, hSpatParamRendCom->num_freq_bands ) );
8369 12750 : scale_sig32( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_len, tmp ); /* Q(h_dirac_output_synthesis_state->q_cy_auto_diff_smooth + tmp) */
8370 12750 : h_dirac_output_synthesis_state->q_cy_auto_diff_smooth = add( h_dirac_output_synthesis_state->q_cy_auto_diff_smooth, tmp );
8371 12750 : move16();
8372 : }
8373 :
8374 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx )
8375 : {
8376 12750 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_len );
8377 12750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_auto_diff_smooth_prev + tmp) */
8378 12750 : hDirACRend->h_output_synthesis_psd_state.q_cy_auto_diff_smooth_prev = add( hDirACRend->h_output_synthesis_psd_state.q_cy_auto_diff_smooth_prev, tmp );
8379 12750 : move16();
8380 : }
8381 :
8382 12750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_fx, hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_len, sub( Q26, hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q ) ); /* Q26 */
8383 12750 : hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q = Q26;
8384 12750 : move16();
8385 12750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_fx, hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_len, sub( Q26, hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q ) ); /* Q26 */
8386 12750 : hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q = Q26;
8387 12750 : move16();
8388 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx )
8389 : {
8390 10500 : Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx, imult1616( hSpatParamRendCom->num_freq_bands, hDirACRend->num_outputs_dir ) );
8391 10500 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth_prev + shift) */
8392 10500 : hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth_prev = add( hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth_prev, shift );
8393 10500 : move16();
8394 : }
8395 :
8396 12750 : IF( EQ_16( hDirACRend->proto_signal_decorr_on, 1 ) )
8397 : {
8398 12000 : tmp = L_norm_arr( hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_fx, hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_len );
8399 12000 : scale_sig32( hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_fx, hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_len, tmp ); /* Q(hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer + tmp) */
8400 12000 : hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer = add( hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer, tmp );
8401 12000 : move16();
8402 : }
8403 :
8404 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len > 0 )
8405 : {
8406 : Word16 shift, norm1, norm2;
8407 : Word32 tmp1, tmp2;
8408 12000 : maximum_abs_32_fx( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_fx, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len, &tmp2 );
8409 12000 : maximum_abs_32_fx( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_fx, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len, &tmp1 );
8410 :
8411 12000 : IF( tmp1 == 0 )
8412 : {
8413 32 : norm1 = 31;
8414 32 : move16();
8415 : }
8416 : ELSE
8417 : {
8418 11968 : norm1 = norm_l( tmp1 );
8419 : }
8420 :
8421 12000 : IF( tmp2 == 0 )
8422 : {
8423 32 : norm2 = 31;
8424 32 : move16();
8425 : }
8426 : ELSE
8427 : {
8428 11968 : norm2 = norm_l( tmp2 );
8429 : }
8430 :
8431 12000 : shift = s_min( norm1, norm2 );
8432 :
8433 12000 : Word16 hr_exp = sub( 31, shift );
8434 :
8435 12000 : Scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_fx, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len, sub( sub( 31, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q ), hr_exp ) ); /* Q(31 - hr_exp) */
8436 12000 : hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q = sub( 31, hr_exp );
8437 12000 : move16();
8438 : }
8439 :
8440 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
8441 : {
8442 : /* CLDFB Analysis*/
8443 77744 : FOR( ch = 0; ch < nchan_transport; ch++ )
8444 : {
8445 47008 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
8446 47008 : move16();
8447 : }
8448 : }
8449 12750 : hDirACRend->proto_frame_dec_f_q = sub( 31, hDirACRend->proto_frame_dec_f_q );
8450 12750 : move16();
8451 :
8452 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx )
8453 : {
8454 : #ifdef FIX_867_CLDFB_NRG_SCALE
8455 10500 : tmp = 0;
8456 10500 : move16();
8457 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8458 : {
8459 81750 : tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx, s_min( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ) );
8460 : }
8461 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8462 : {
8463 81750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx, s_min( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q + tmp) */
8464 : }
8465 10500 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[0] = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[0], tmp );
8466 10500 : move16();
8467 10500 : tmp = 0;
8468 10500 : move16();
8469 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8470 : {
8471 81750 : tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ) ) );
8472 : }
8473 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8474 : {
8475 81750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q + tmp) */
8476 : }
8477 10500 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[1] = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[1], tmp );
8478 10500 : move16();
8479 : #else
8480 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx, imult1616( hDirACRend->num_protos_dir, hSpatParamRendCom->num_freq_bands ) );
8481 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q + tmp) */
8482 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q, tmp );
8483 : move16();
8484 : #endif
8485 : #ifdef FIX_867_CLDFB_NRG_SCALE
8486 10500 : tmp = 0;
8487 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8488 : {
8489 81750 : tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, s_min( CLDFB_NO_CHANNELS_HALF, hSpatParamRendCom->num_freq_bands ) ) );
8490 : }
8491 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8492 : {
8493 81750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, s_min( CLDFB_NO_CHANNELS_HALF, hSpatParamRendCom->num_freq_bands ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q + tmp) */
8494 : }
8495 10500 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[0] = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[0] );
8496 10500 : move16();
8497 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8498 : {
8499 81750 : tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ) ) );
8500 : }
8501 92250 : FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
8502 : {
8503 81750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q + tmp) */
8504 : }
8505 10500 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[1] = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[1] );
8506 10500 : move16();
8507 : #else
8508 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, imult1616( hDirACRend->num_protos_dir, hSpatParamRendCom->num_freq_bands ) );
8509 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q + tmp) */
8510 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q );
8511 : move16();
8512 : #endif
8513 : }
8514 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx != NULL )
8515 : {
8516 :
8517 10500 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_len );
8518 10500 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_q + tmp) */
8519 10500 : hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_q, tmp );
8520 10500 : move16();
8521 : }
8522 :
8523 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx != NULL )
8524 : {
8525 9750 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_len );
8526 9750 : scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_q + tmp) */
8527 9750 : hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_q, tmp );
8528 9750 : move16();
8529 : }
8530 : }
8531 : ELSE
8532 : {
8533 43350 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[hSpatParamRendCom->subframes_rendered]; slot_idx++ )
8534 : {
8535 : /* CLDFB Analysis*/
8536 77400 : FOR( ch = 0; ch < nchan_transport; ch++ )
8537 : {
8538 46800 : scale_sig32( hMasaExtRend->cldfbAnaRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbAnaRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state ) ); /* Q11 */
8539 46800 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
8540 46800 : move16();
8541 : }
8542 : }
8543 :
8544 123000 : FOR( ch = 0; ch < hDirACRend->hOutSetup.nchan_out_woLFE + hDirACRend->hOutSetup.num_lfe; ch++ )
8545 : {
8546 110250 : scale_sig32( hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbSynRend[0]->Q_cldfb_state ) ); /* Q11 */
8547 110250 : hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
8548 110250 : move16();
8549 : }
8550 : }
8551 25500 : }
8552 :
8553 658 : static ivas_error printConfigInfo_rend(
8554 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
8555 : )
8556 : {
8557 : ivas_error error;
8558 : Word8 config_str[50];
8559 :
8560 : /*-----------------------------------------------------------------*
8561 : * Print output audio configuration
8562 : *-----------------------------------------------------------------*/
8563 :
8564 658 : IF( NE_32( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ), IVAS_ERR_OK ) )
8565 : {
8566 0 : return error;
8567 : }
8568 :
8569 658 : fprintf( stdout, "Output configuration: %s\n", config_str );
8570 :
8571 : /*-----------------------------------------------------------------*
8572 : * Print renderer configurations
8573 : *-----------------------------------------------------------------*/
8574 :
8575 658 : fprintf( stdout, "Output sampling rate: %d Hz\n", hIvasRend->sampleRateOut );
8576 :
8577 658 : if ( hIvasRend->headRotData.headRotEnabled )
8578 : {
8579 658 : fprintf( stdout, "Head-tracking: ON\n" );
8580 : }
8581 :
8582 658 : IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) ||
8583 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) ||
8584 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ||
8585 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
8586 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8587 : {
8588 188 : fprintf( stdout, "Render framesize: %dms\n", mult( hIvasRend->num_subframes, 5 ) );
8589 : }
8590 :
8591 658 : return IVAS_ERR_OK;
8592 : }
8593 :
8594 :
8595 : /*---------------------------------------------------------------------*
8596 : * IVAS_REND_PrintInputConfig()
8597 : *
8598 : *
8599 : *---------------------------------------------------------------------*/
8600 :
8601 721 : void IVAS_REND_PrintInputConfig(
8602 : const IVAS_AUDIO_CONFIG inputConfig /* i : input audio configuration */
8603 : )
8604 : {
8605 : Word8 config_str[50];
8606 :
8607 721 : get_channel_config( inputConfig, &config_str[0] );
8608 721 : fprintf( stdout, "Input configuration: %s\n", config_str );
8609 :
8610 721 : return;
8611 : }
8612 :
8613 :
8614 : /*---------------------------------------------------------------------*
8615 : * IVAS_REND_PrintConfig()
8616 : *
8617 : *
8618 : *---------------------------------------------------------------------*/
8619 :
8620 658 : ivas_error IVAS_REND_PrintConfig(
8621 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
8622 : )
8623 : {
8624 658 : if ( hIvasRend == NULL )
8625 : {
8626 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8627 : }
8628 :
8629 658 : return printConfigInfo_rend( hIvasRend );
8630 : }
8631 :
8632 :
8633 : /*---------------------------------------------------------------------*
8634 : * IVAS_REND_PrintDisclaimer()
8635 : *
8636 : * Print IVAS disclaimer to console
8637 : *---------------------------------------------------------------------*/
8638 :
8639 658 : void IVAS_REND_PrintDisclaimer( void )
8640 : {
8641 658 : print_disclaimer( stderr );
8642 :
8643 658 : return;
8644 : }
|