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 973 : static ivas_error allocateInputBaseBufferData_fx(
232 : Word32 **data, /* Qx */
233 : const Word16 data_size )
234 : {
235 973 : *data = (Word32 *) malloc( data_size * sizeof( Word32 ) );
236 973 : 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 973 : return IVAS_ERR_OK;
242 : }
243 4662 : static void freeInputBaseBufferData_fx(
244 : Word32 **data /* Qx */ )
245 : {
246 4662 : IF( *data != NULL )
247 : {
248 973 : free( *data );
249 973 : *data = NULL;
250 : }
251 :
252 4662 : 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 666 : static void freeMcLfeDelayBuffer_fx(
267 : Word32 **lfeDelayBuffer /* Qx */ )
268 : {
269 666 : IF( *lfeDelayBuffer != NULL )
270 : {
271 372 : free( *lfeDelayBuffer );
272 372 : *lfeDelayBuffer = NULL;
273 : }
274 :
275 666 : return;
276 : }
277 :
278 :
279 1752 : static IVAS_QUATERNION quaternionInit_fx(
280 : void )
281 : {
282 : IVAS_QUATERNION q;
283 1752 : q.w_fx = ONE_IN_Q29;
284 1752 : move32();
285 1752 : q.x_fx = q.y_fx = q.z_fx = 0;
286 1752 : move32();
287 1752 : move32();
288 1752 : move32();
289 :
290 1752 : q.q_fact = Q29;
291 1752 : move16();
292 1752 : move16();
293 1752 : move16();
294 1752 : move16();
295 :
296 1752 : return q;
297 : }
298 :
299 221694105 : static Word32 *getSmplPtr_fx(
300 : IVAS_REND_AudioBuffer buffer,
301 : const UWord32 chnlIdx,
302 : const UWord32 smplIdx )
303 : {
304 221694105 : 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 1126140 : 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 1126140 : Word32 numClipping = 0;
365 1126140 : move32();
366 :
367 : /* return early if given bad parameters */
368 1126140 : test();
369 1126140 : test();
370 1126140 : IF( hLimiter == NULL || output == NULL || output_frame <= 0 )
371 : {
372 0 : return 0;
373 : }
374 :
375 1126140 : channels = hLimiter->channel_ptrs_fx;
376 1126140 : num_channels = hLimiter->num_channels;
377 1126140 : move16();
378 :
379 7755488 : FOR( i = 0; i < num_channels; ++i )
380 : {
381 6629348 : channels[i] = output + imult1616( i, output_frame );
382 : }
383 :
384 1126140 : 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 2809398780 : FOR( i = 0; i < output_frame * num_channels; ++i )
388 : {
389 :
390 2808272640 : output[i] = L_min( L_max( L_shl( INT16_MIN, q_factor ), output[i] ), L_shl( INT16_MAX, q_factor ) );
391 2808272640 : move32();
392 : }
393 :
394 1126140 : return numClipping;
395 : }
396 :
397 : /*-------------------------------------------------------------------*
398 : * validateOutputAudioConfig()
399 : *
400 : *
401 : *-------------------------------------------------------------------*/
402 :
403 666 : static ivas_error validateOutputAudioConfig(
404 : const AUDIO_CONFIG outConfig )
405 : {
406 666 : SWITCH( outConfig )
407 : {
408 666 : 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 666 : 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 8477919 : IVAS_REND_AudioConfigType getAudioConfigType(
439 : const AUDIO_CONFIG config )
440 : {
441 : IVAS_REND_AudioConfigType type;
442 :
443 8477919 : SWITCH( config )
444 : {
445 4284824 : 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 4284824 : type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
454 4284824 : move16();
455 4284824 : 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 301622 : case IVAS_AUDIO_CONFIG_OBA:
463 301622 : type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
464 301622 : move16();
465 301622 : 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 8477919 : return type;
486 : }
487 :
488 : /*-------------------------------------------------------------------*
489 : * validateOutputSampleRate()
490 : *
491 : *
492 : *-------------------------------------------------------------------*/
493 :
494 666 : static ivas_error validateOutputSampleRate(
495 : const Word32 sampleRate,
496 : const AUDIO_CONFIG outConfig )
497 : {
498 666 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
499 : {
500 : /* If no binaural rendering, any sampling rate is supported */
501 478 : 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 5841645 : ivas_error getAudioConfigNumChannels(
523 : const AUDIO_CONFIG config,
524 : Word16 *numChannels )
525 : {
526 5841645 : SWITCH( config )
527 : {
528 1484129 : case IVAS_AUDIO_CONFIG_MONO:
529 : case IVAS_AUDIO_CONFIG_OBA:
530 : case IVAS_AUDIO_CONFIG_MASA1:
531 1484129 : *numChannels = 1;
532 1484129 : move16();
533 1484129 : 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 5841645 : move16();
576 5841645 : return IVAS_ERR_OK;
577 : }
578 : /*-------------------------------------------------------------------*
579 : * Local functions
580 : *-------------------------------------------------------------------*/
581 :
582 713 : 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 713 : test();
591 713 : test();
592 713 : 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 713 : IF( *phLimiter != NULL )
599 : {
600 47 : ivas_limiter_close_fx( phLimiter );
601 : }
602 :
603 713 : IF( NE_32( ( error = ivas_limiter_open_fx( phLimiter, numChannels, sampleRate ) ), IVAS_ERR_OK ) )
604 : {
605 0 : return error;
606 : }
607 :
608 713 : return IVAS_ERR_OK;
609 : }
610 1038 : 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 1038 : ls.is_planar_setup = 1;
618 1038 : ls.num_spk = 1;
619 1038 : move16();
620 1038 : move16();
621 1038 : set32_fx( ls.ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS );
622 1038 : set32_fx( ls.ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS );
623 1038 : ls.num_lfe = 0;
624 1038 : move16();
625 1038 : set16_fx( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
626 1038 : ls.separate_ch_found = 0;
627 1038 : move16();
628 1038 : set16_fx( ls.separate_ch_gains_fx, 0, MAX_OUTPUT_CHANNELS );
629 :
630 1038 : 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 878 : 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 878 : test();
876 878 : 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 758 : pEfapWrapper->speakerConfig = outConfig;
884 758 : move32();
885 : }
886 878 : pEfapWrapper->pCustomLsSetup = pCustomLsOut;
887 :
888 : /* If re-initializing, free existing EFAP handle. */
889 878 : IF( pEfapWrapper->hEfap != NULL )
890 : {
891 47 : efap_free_data_fx( &pEfapWrapper->hEfap );
892 : }
893 :
894 : /* Only initialize EFAP handle if output config is channel-based */
895 878 : 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 683 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
902 : {
903 199 : 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 683 : return IVAS_ERR_OK;
931 : }
932 :
933 423262 : 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 423262 : efap_determine_gains_fx( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
948 :
949 : /* Now copy to buffer that includes LFE channels */
950 423262 : IF( EQ_32( efapWrapper.speakerConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
951 : {
952 29835 : numChannels = add( efapWrapper.pCustomLsSetup->num_spk, efapWrapper.pCustomLsSetup->num_lfe );
953 29835 : readPtr = tmpPanGains;
954 29835 : lfeCount = 0;
955 29835 : move16();
956 387823 : FOR( i = 0; i < numChannels; ++i )
957 : {
958 357988 : test();
959 357988 : 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 357988 : IF( EQ_32( *readPtr, ONE_IN_Q30 ) )
968 : {
969 0 : panGains[i] = ONE_IN_Q31;
970 : }
971 : ELSE
972 : {
973 357988 : panGains[i] = L_shl( *readPtr, 1 );
974 : }
975 357988 : move32();
976 357988 : ++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 423262 : return IVAS_ERR_OK;
1014 : }
1015 :
1016 666 : 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 666 : hIvasRend->headRotData.headRotEnabled = 1;
1025 666 : move16();
1026 :
1027 : /* Initialize 5ms crossfade */
1028 666 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
1029 666 : move16();
1030 666 : tmp_fx = Q31_BY_SUB_FRAME_240;
1031 666 : move16();
1032 :
1033 160506 : FOR( i = 0; i < crossfade_len; i++ )
1034 : {
1035 159840 : hIvasRend->headRotData.crossfade_fx[i] = UL_Mpy_32_32( i, tmp_fx );
1036 159840 : move32();
1037 : }
1038 :
1039 : /* Initialize with unit quaternions */
1040 2418 : FOR( i = 0; i < hIvasRend->num_subframes; ++i )
1041 : {
1042 1752 : hIvasRend->headRotData.headPositions[i] = quaternionInit_fx();
1043 : }
1044 :
1045 :
1046 666 : 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 666 : IF( NE_32( ( error = ivas_orient_trk_Init_fx( hIvasRend->headRotData.hOrientationTracker ) ), IVAS_ERR_OK ) )
1052 : {
1053 0 : return error;
1054 : }
1055 :
1056 666 : return IVAS_ERR_OK;
1057 : }
1058 :
1059 :
1060 666 : static void closeHeadRotation(
1061 : IVAS_REND_HANDLE hIvasRend )
1062 : {
1063 666 : test();
1064 666 : IF( ( hIvasRend != NULL ) && ( hIvasRend->headRotData.hOrientationTracker != NULL ) )
1065 : {
1066 666 : free( hIvasRend->headRotData.hOrientationTracker );
1067 : }
1068 :
1069 666 : return;
1070 : }
1071 :
1072 :
1073 426 : static void initRotMatrix_fx(
1074 : rotation_matrix_fx rot_mat )
1075 : {
1076 : Word16 i;
1077 :
1078 : /* Initialize rotation matrices */
1079 1704 : FOR( i = 0; i < 3; i++ )
1080 : {
1081 1278 : set_zero_fx( rot_mat[i], 3 );
1082 1278 : rot_mat[i][i] = ONE_IN_Q30;
1083 1278 : move32();
1084 : }
1085 :
1086 426 : 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 10297 : 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 10297 : inputBase->inConfig = inConfig;
1129 10297 : move32();
1130 10297 : inputBase->id = id;
1131 10297 : move16();
1132 10297 : inputBase->gain_fx = ONE_IN_Q30;
1133 10297 : move32();
1134 10297 : inputBase->ctx = rendCtx;
1135 10297 : inputBase->numNewSamplesPerChannel = 0;
1136 10297 : move32();
1137 :
1138 10297 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
1139 10297 : inputBase->inputBuffer.config.numChannels = 0;
1140 10297 : move16();
1141 10297 : move16();
1142 10297 : inputBase->inputBuffer.data_fx = dataBuf;
1143 10297 : IF( inputBase->inputBuffer.data_fx != NULL )
1144 : {
1145 973 : set32_fx( inputBase->inputBuffer.data_fx, 0, dataBufSize );
1146 : }
1147 :
1148 10297 : return;
1149 : }
1150 :
1151 300852 : static IVAS_ISM_METADATA defaultObjectPosition(
1152 : void )
1153 : {
1154 : IVAS_ISM_METADATA pos;
1155 :
1156 300852 : pos.azimuth_fx = 0;
1157 300852 : move32();
1158 300852 : pos.elevation_fx = 0;
1159 300852 : move32();
1160 300852 : pos.radius_fx = ONE_IN_Q9;
1161 300852 : move16();
1162 300852 : pos.spread_fx = 0;
1163 300852 : move32();
1164 300852 : pos.gainFactor_fx = ONE_IN_Q31;
1165 300852 : move32();
1166 300852 : pos.yaw_fx = 0;
1167 300852 : move32();
1168 300852 : pos.pitch_fx = 0;
1169 300852 : move32();
1170 300852 : return pos;
1171 : }
1172 :
1173 :
1174 947155 : static Word8 checkObjectPositionChanged_fx(
1175 : IVAS_ISM_METADATA *currentPos,
1176 : IVAS_ISM_METADATA *previousPos )
1177 : {
1178 947155 : test();
1179 1555417 : return !( LT_32( L_abs( L_sub( currentPos->azimuth_fx, previousPos->azimuth_fx ) ), EPSILLON_FX ) &&
1180 608262 : LT_32( L_abs( L_sub( currentPos->elevation_fx, previousPos->elevation_fx ) ), EPSILLON_FX ) );
1181 : }
1182 :
1183 4662 : 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 4662 : ctx.pOutConfig = &hIvasRend->outputConfig;
1192 4662 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
1193 4662 : ctx.pCustomLsOut = &hIvasRend->customLsOut;
1194 4662 : ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
1195 4662 : ctx.pHeadRotData = &hIvasRend->headRotData;
1196 4662 : ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
1197 :
1198 4662 : return ctx;
1199 : }
1200 :
1201 :
1202 798 : static TDREND_WRAPPER defaultTdRendWrapper(
1203 : void )
1204 : {
1205 : TDREND_WRAPPER w;
1206 :
1207 798 : w.binaural_latency_ns = 0;
1208 798 : move32();
1209 798 : w.hBinRendererTd = NULL;
1210 798 : w.hHrtfTD = NULL;
1211 :
1212 798 : return w;
1213 : }
1214 :
1215 :
1216 973 : 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 973 : test();
1222 973 : test();
1223 973 : 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 973 : 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 426 : 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 426 : inputIsm = (input_ism *) input;
1269 426 : rendCtx = inputIsm->base.ctx;
1270 426 : outConfig = *rendCtx.pOutConfig;
1271 :
1272 426 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
1273 : {
1274 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
1275 : }
1276 :
1277 426 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputIsm->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
1278 : {
1279 0 : return error;
1280 : }
1281 426 : initRendInputBase_fx( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData_fx, MAX_BUFFER_LENGTH );
1282 :
1283 426 : inputIsm->firstFrameRendered = FALSE;
1284 426 : move16();
1285 :
1286 426 : inputIsm->currentPos = defaultObjectPosition();
1287 426 : inputIsm->previousPos = defaultObjectPosition();
1288 426 : inputIsm->crendWrapper = NULL;
1289 426 : inputIsm->hReverb = NULL;
1290 426 : inputIsm->tdRendWrapper = defaultTdRendWrapper();
1291 :
1292 426 : initRotMatrix_fx( inputIsm->rot_mat_prev );
1293 :
1294 426 : set_zero_fx( inputIsm->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
1295 :
1296 426 : inputIsm->hOMasa = NULL;
1297 :
1298 426 : error = IVAS_ERR_OK;
1299 426 : move32();
1300 :
1301 426 : test();
1302 426 : 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 386 : 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 385 : IF( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
1322 : {
1323 0 : ivas_format = MC_FORMAT;
1324 : }
1325 : ELSE
1326 : {
1327 385 : ivas_format = ISM_FORMAT;
1328 : }
1329 :
1330 385 : move16();
1331 385 : 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 385 : Word16 nchan_rend = num_src;
1337 385 : move16();
1338 :
1339 385 : test();
1340 385 : 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 770 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
1345 : {
1346 385 : TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
1347 385 : IF( Src_p != NULL )
1348 : {
1349 385 : IF( Src_p->SrcSpatial_p != NULL )
1350 : {
1351 385 : Src_p->SrcSpatial_p->q_Pos_p = Q31;
1352 385 : move16();
1353 : }
1354 385 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
1355 385 : SrcSpatial_p->q_Pos_p = Q31;
1356 385 : move16();
1357 : }
1358 : }
1359 :
1360 385 : 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 426 : return IVAS_ERR_OK;
1370 : }
1371 :
1372 2664 : static void clearInputIsm(
1373 : input_ism *inputIsm )
1374 : {
1375 : rendering_context rendCtx;
1376 :
1377 2664 : rendCtx = inputIsm->base.ctx;
1378 :
1379 2664 : freeInputBaseBufferData_fx( &inputIsm->base.inputBuffer.data_fx );
1380 :
1381 2664 : initRendInputBase_fx( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
1382 :
1383 : /* Free input's internal handles */
1384 2664 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1385 :
1386 2664 : ivas_reverb_close( &inputIsm->hReverb );
1387 :
1388 2664 : IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1389 : {
1390 385 : ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
1391 385 : inputIsm->tdRendWrapper.hHrtfTD = NULL;
1392 : }
1393 :
1394 :
1395 2664 : ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
1396 :
1397 2664 : 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 2507531 : 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 2507531 : pInputBase = (const input_base *) rendInput;
1599 :
1600 2507531 : 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 2291556 : IF( NE_32( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ), IVAS_ERR_OK ) )
1609 : {
1610 0 : return error;
1611 : }
1612 : }
1613 :
1614 2507531 : 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 666 : static void clearInputMc(
2488 : input_mc *inputMc )
2489 : {
2490 : rendering_context rendCtx;
2491 :
2492 666 : rendCtx = inputMc->base.ctx;
2493 666 : freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx );
2494 666 : freeInputBaseBufferData_fx( &inputMc->bufferData_fx );
2495 666 : initRendInputBase_fx( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2496 :
2497 : /* Free input's internal handles */
2498 666 : IF( inputMc->efapInWrapper.hEfap != NULL )
2499 : {
2500 129 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2501 : }
2502 :
2503 666 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2504 :
2505 666 : ivas_reverb_close( &inputMc->hReverb );
2506 :
2507 666 : 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 666 : ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
2515 :
2516 666 : 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 666 : static void clearInputSba(
2742 : input_sba *inputSba )
2743 : {
2744 : rendering_context rendCtx;
2745 :
2746 666 : rendCtx = inputSba->base.ctx;
2747 :
2748 666 : freeInputBaseBufferData_fx( &inputSba->bufferData_fx );
2749 :
2750 666 : initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2751 :
2752 : /* Free input's internal handles */
2753 666 : ivas_rend_closeCrend( &inputSba->crendWrapper );
2754 :
2755 666 : ivas_dirac_ana_close_fx( &( inputSba->hDirAC ) );
2756 :
2757 666 : 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 666 : static void clearInputMasa(
2827 : input_masa *inputMasa )
2828 : {
2829 : rendering_context rendCtx;
2830 :
2831 666 : rendCtx = inputMasa->base.ctx;
2832 :
2833 666 : freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
2834 :
2835 666 : masaPrerendClose_fx( &inputMasa->hMasaPrerend );
2836 :
2837 666 : freeMasaExtRenderer( &inputMasa->hMasaExtRend );
2838 :
2839 666 : initRendInputBase_fx( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2840 :
2841 666 : return;
2842 : }
2843 :
2844 :
2845 : /*-------------------------------------------------------------------------
2846 : * IVAS_REND_Open()
2847 : *
2848 : *
2849 : *------------------------------------------------------------------------*/
2850 :
2851 666 : 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 666 : IF( phIvasRend == NULL )
2866 : {
2867 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
2868 : }
2869 :
2870 666 : IF( NE_32( ( error = validateOutputAudioConfig( outConfig ) ), IVAS_ERR_OK ) )
2871 : {
2872 0 : return error;
2873 : }
2874 :
2875 666 : IF( NE_32( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ), IVAS_ERR_OK ) )
2876 : {
2877 0 : return error;
2878 : }
2879 :
2880 666 : *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
2881 666 : IF( *phIvasRend == NULL )
2882 : {
2883 0 : return IVAS_ERR_FAILED_ALLOC;
2884 : }
2885 :
2886 666 : hIvasRend = *phIvasRend;
2887 666 : hIvasRend->sampleRateOut = outputSampleRate;
2888 666 : hIvasRend->outputConfig = outConfig;
2889 666 : hIvasRend->customLsOut = defaultCustomLs();
2890 666 : hIvasRend->hLimiter = NULL;
2891 666 : hIvasRend->efapOutWrapper.hEfap = NULL;
2892 666 : hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
2893 666 : hIvasRend->num_subframes = num_subframes;
2894 :
2895 : /* Initialize limiter */
2896 666 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
2897 : {
2898 0 : return error;
2899 : }
2900 :
2901 666 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ), IVAS_ERR_OK ) )
2902 : {
2903 0 : return error;
2904 : }
2905 :
2906 : /* Initialize headrotation data */
2907 666 : IF( NE_32( ( error = initHeadRotation_fx( hIvasRend ) ), IVAS_ERR_OK ) )
2908 : {
2909 0 : return error;
2910 : }
2911 :
2912 : /* Initialize external orientation data */
2913 666 : 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 666 : 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 666 : 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 3330 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
2931 : {
2932 2664 : initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2933 2664 : hIvasRend->inputsIsm[i].crendWrapper = NULL;
2934 2664 : hIvasRend->inputsIsm[i].hReverb = NULL;
2935 2664 : hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
2936 2664 : hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
2937 2664 : move16();
2938 2664 : hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
2939 2664 : move32();
2940 2664 : hIvasRend->inputsIsm[i].hOMasa = NULL;
2941 2664 : hIvasRend->inputsIsm[i].bufferData_fx = NULL;
2942 : }
2943 :
2944 1332 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
2945 : {
2946 666 : initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2947 :
2948 666 : hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
2949 666 : hIvasRend->inputsMc[i].crendWrapper = NULL;
2950 666 : hIvasRend->inputsMc[i].hReverb = NULL;
2951 666 : hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
2952 666 : hIvasRend->inputsMc[i].bufferData_fx = NULL;
2953 666 : hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL;
2954 666 : hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
2955 666 : move16();
2956 666 : hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
2957 666 : move32();
2958 666 : hIvasRend->inputsMc[i].hMcMasa = NULL;
2959 : }
2960 :
2961 1332 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
2962 : {
2963 666 : initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2964 :
2965 666 : hIvasRend->inputsSba[i].crendWrapper = NULL;
2966 666 : hIvasRend->inputsSba[i].bufferData_fx = NULL;
2967 666 : hIvasRend->inputsSba[i].hDirAC = NULL;
2968 : }
2969 :
2970 1332 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
2971 : {
2972 666 : initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
2973 :
2974 666 : hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
2975 666 : hIvasRend->inputsMasa[i].bufferData_fx = NULL;
2976 666 : hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
2977 666 : hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
2978 666 : move16();
2979 : }
2980 :
2981 :
2982 666 : return IVAS_ERR_OK;
2983 : }
2984 152 : 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 152 : customLs.num_spk = rendCustomLsLayout.num_spk;
2992 152 : move16();
2993 152 : Copy32( rendCustomLsLayout.azimuth_fx, customLs.ls_azimuth_fx, rendCustomLsLayout.num_spk );
2994 152 : Copy32( rendCustomLsLayout.elevation_fx, customLs.ls_elevation_fx, rendCustomLsLayout.num_spk );
2995 152 : customLs.is_planar_setup = 1;
2996 152 : move16();
2997 776 : FOR( i = 0; i < rendCustomLsLayout.num_spk; ++i )
2998 : {
2999 776 : IF( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
3000 : {
3001 152 : customLs.is_planar_setup = 0;
3002 152 : move16();
3003 152 : BREAK;
3004 : }
3005 : }
3006 :
3007 152 : customLs.num_lfe = rendCustomLsLayout.num_lfe;
3008 152 : move16();
3009 152 : Copy( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
3010 :
3011 152 : return customLs;
3012 : }
3013 :
3014 :
3015 152 : 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 152 : test();
3022 152 : 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 152 : 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 152 : 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 152 : return IVAS_ERR_OK;
3043 : }
3044 :
3045 :
3046 : /*-------------------------------------------------------------------*
3047 : * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
3048 : *
3049 : *
3050 : *-------------------------------------------------------------------*/
3051 :
3052 47 : 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 47 : IF( hIvasRend == NULL )
3063 : {
3064 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3065 : }
3066 :
3067 47 : 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 47 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
3074 : {
3075 0 : return error;
3076 : }
3077 :
3078 47 : hIvasRend->customLsOut = makeCustomLsSetup( layout );
3079 :
3080 : /* Re-initialize limiter - number of output channels may have changed */
3081 47 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
3082 : {
3083 0 : return error;
3084 : }
3085 :
3086 47 : 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 47 : 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 94 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3101 : {
3102 47 : inputMc = &hIvasRend->inputsMc[i];
3103 47 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3104 : {
3105 : /* Input inactive, skip. */
3106 47 : 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 94 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3119 : {
3120 47 : inputSba = &hIvasRend->inputsSba[i];
3121 :
3122 47 : IF( EQ_32( inputSba->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3123 : {
3124 : /* Input inactive, skip. */
3125 47 : 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 47 : return IVAS_ERR_OK;
3134 : }
3135 :
3136 : /*-------------------------------------------------------------------*
3137 : * IVAS_REND_NumOutChannels()
3138 : *
3139 : *
3140 : *-------------------------------------------------------------------*/
3141 :
3142 1127519 : 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 1127519 : test();
3150 1127519 : 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 1127519 : SWITCH( hIvasRend->outputConfig )
3157 : {
3158 36003 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3159 36003 : *numOutChannels = add( hIvasRend->customLsOut.num_spk, hIvasRend->customLsOut.num_lfe );
3160 36003 : move16();
3161 36003 : 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 1127519 : return IVAS_ERR_OK;
3171 : }
3172 :
3173 :
3174 973 : 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 973 : return (IVAS_REND_InputId) UL_or( UL_lshl( ( (UWord32) getAudioConfigType( config ) ), 8 ), L_add( inputIndex, 1 ) );
3182 : }
3183 :
3184 :
3185 3133018 : 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 3133018 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3196 3133018 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3197 :
3198 : /* Validate values derived from input ID */
3199 3133018 : IF( inputIndex < 0 )
3200 : {
3201 0 : return IVAS_ERR_INVALID_INPUT_ID;
3202 : }
3203 3133018 : SWITCH( configType )
3204 : {
3205 2495576 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3206 2495576 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3207 : {
3208 0 : return IVAS_ERR_INVALID_INPUT_ID;
3209 : }
3210 2495576 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3211 2495576 : 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 3133018 : test();
3239 3133018 : 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 3133018 : *ppInput = pInputBase;
3246 :
3247 3133018 : return IVAS_ERR_OK;
3248 : }
3249 :
3250 :
3251 630413 : 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 630413 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3262 630413 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3263 :
3264 : /* Validate values derived from input ID */
3265 630413 : IF( inputIndex < 0 )
3266 : {
3267 0 : return IVAS_ERR_INVALID_INPUT_ID;
3268 : }
3269 630413 : SWITCH( configType )
3270 : {
3271 426 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3272 426 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3273 : {
3274 0 : return IVAS_ERR_INVALID_INPUT_ID;
3275 : }
3276 426 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3277 426 : 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 630413 : test();
3305 630413 : 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 630413 : *ppInput = pInputBase;
3312 :
3313 630413 : return IVAS_ERR_OK;
3314 : }
3315 :
3316 973 : 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 973 : canAddInput = false;
3335 973 : move16();
3336 :
3337 : /* Find first unused input in array */
3338 1353 : FOR( ( i = 0, pByte = inputs ); i < maxInputs; ( ++i, pByte += inputStructSize ) )
3339 : {
3340 1353 : pInputBase = (const input_base *) pByte;
3341 :
3342 1353 : IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3343 : {
3344 973 : *inputIndex = i;
3345 973 : move32();
3346 973 : canAddInput = true;
3347 973 : move16();
3348 973 : BREAK;
3349 : }
3350 : }
3351 :
3352 973 : IF( !canAddInput )
3353 : {
3354 0 : return IVAS_ERR_TOO_MANY_INPUTS;
3355 : }
3356 :
3357 973 : return IVAS_ERR_OK;
3358 : }
3359 :
3360 :
3361 : /*-------------------------------------------------------------------*
3362 : * IVAS_REND_AddInput()
3363 : *
3364 : *
3365 : *-------------------------------------------------------------------*/
3366 973 : 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 973 : test();
3381 973 : IF( hIvasRend == NULL || inputId == NULL )
3382 : {
3383 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3384 : }
3385 :
3386 :
3387 973 : SWITCH( getAudioConfigType( inConfig ) )
3388 : {
3389 426 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3390 426 : maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
3391 426 : inputsArray = hIvasRend->inputsIsm;
3392 426 : inputStructSize = sizeof( *hIvasRend->inputsIsm );
3393 426 : activateInput = setRendInputActiveIsm;
3394 426 : move32();
3395 426 : move32();
3396 426 : 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 973 : IF( NE_32( ( error = findFreeInputSlot_fx( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ), IVAS_ERR_OK ) )
3427 : {
3428 0 : return error;
3429 : }
3430 :
3431 973 : *inputId = makeInputId( inConfig, inputIndex );
3432 973 : move16();
3433 :
3434 973 : IF( NE_32( ( error = activateInput( (UWord8 *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
3435 : {
3436 0 : return error;
3437 : }
3438 :
3439 973 : 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 973 : 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 973 : IF( hIvasRend == NULL )
3526 : {
3527 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3528 : }
3529 :
3530 973 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3531 : {
3532 0 : return error;
3533 : }
3534 :
3535 973 : inputBase->gain_fx = gain;
3536 973 : move32();
3537 :
3538 973 : 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 630413 : 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 630413 : test();
3705 630413 : IF( hIvasRend == NULL || numChannels == NULL )
3706 : {
3707 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3708 : }
3709 :
3710 630413 : IF( NE_32( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ), IVAS_ERR_OK ) )
3711 : {
3712 0 : return error;
3713 : }
3714 :
3715 630413 : IF( NE_32( ( error = getRendInputNumChannels( pInput, numChannels ) ), IVAS_ERR_OK ) )
3716 : {
3717 0 : return error;
3718 : }
3719 :
3720 630413 : return IVAS_ERR_OK;
3721 : }
3722 :
3723 : /*-------------------------------------------------------------------*
3724 : * IVAS_REND_GetNumAllObjects()
3725 : *
3726 : *
3727 : *-------------------------------------------------------------------*/
3728 426 : 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 426 : test();
3734 426 : IF( hIvasRend == NULL || numChannels == NULL )
3735 : {
3736 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3737 : }
3738 :
3739 426 : test();
3740 426 : 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 426 : 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 1877090 : 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 1877090 : test();
3889 1877090 : IF( hIvasRend == NULL || inputAudio.data_fx == NULL )
3890 : {
3891 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3892 : }
3893 :
3894 1877090 : test();
3895 1877090 : 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 1877090 : test();
3901 1877090 : 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 1877090 : test();
3907 1877090 : move32(); // move added for typecasting
3908 1877090 : 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 1877090 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3915 : {
3916 0 : return error;
3917 : }
3918 :
3919 1877090 : IF( NE_32( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ), IVAS_ERR_OK ) )
3920 : {
3921 0 : return error;
3922 : }
3923 1877090 : test();
3924 1877090 : test();
3925 1877090 : 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 1877090 : IF( NE_16( numInputChannels, inputAudio.config.numChannels ) )
3932 : {
3933 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
3934 : }
3935 :
3936 1877090 : inputBase->inputBuffer.config = inputAudio.config;
3937 :
3938 1877090 : MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
3939 :
3940 1877090 : inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel;
3941 1877090 : move32();
3942 :
3943 1877090 : return IVAS_ERR_OK;
3944 : }
3945 :
3946 :
3947 : /*-------------------------------------------------------------------*
3948 : * IVAS_REND_FeedInputObjectMetadata()
3949 : *
3950 : *
3951 : *-------------------------------------------------------------------*/
3952 :
3953 1247500 : 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 1247500 : IF( hIvasRend == NULL )
3965 : {
3966 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3967 : }
3968 :
3969 1247500 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
3970 : {
3971 0 : return error;
3972 : }
3973 :
3974 1247500 : 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 1247500 : inputIsm = (input_ism *) inputBase;
3981 1247500 : inputIsm->previousPos = inputIsm->currentPos;
3982 1247500 : inputIsm->currentPos = objectPosition;
3983 :
3984 1247500 : 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 666 : 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 666 : rendererConfigEnabled = EQ_32( getAudioConfigType( outAudioConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
4070 :
4071 666 : IF( rendererConfigEnabled )
4072 : {
4073 188 : hIvasRend->rendererConfigEnabled = 1;
4074 188 : move16();
4075 : }
4076 : ELSE
4077 : {
4078 478 : hIvasRend->rendererConfigEnabled = 0;
4079 478 : move16();
4080 : }
4081 :
4082 666 : 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 478 : hIvasRend->hRendererConfig = NULL;
4096 : }
4097 :
4098 666 : 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 946116 : 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 946116 : IF( hIvasRend == NULL )
4310 : {
4311 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4312 : }
4313 :
4314 946116 : hIvasRend->headRotData.headRotEnabled = 0;
4315 946116 : move32();
4316 :
4317 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
4318 946116 : 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 946116 : return IVAS_ERR_OK;
4334 : }
4335 :
4336 : /*-------------------------------------------------------------------*
4337 : * IVAS_REND_SetOrientationTrackingMode()
4338 : *
4339 : *
4340 : *-------------------------------------------------------------------*/
4341 :
4342 666 : 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 666 : 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 1126140 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
4469 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
4470 : )
4471 : {
4472 1126140 : IF( hIvasRend == NULL )
4473 : {
4474 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4475 : }
4476 1126140 : ivas_error error_type = combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
4477 1126140 : 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 5282295 : 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 5282295 : lastInSmpl = getSmplPtr_fx( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
4520 :
4521 51204875 : FOR( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
4522 : {
4523 45922580 : currentGain = gainsCurrent[outChnlIdx];
4524 45922580 : move32();
4525 45922580 : if ( gainsPrev == NULL )
4526 : {
4527 42525392 : previousGain = 0;
4528 42525392 : move32();
4529 : }
4530 : else
4531 : {
4532 3397188 : previousGain = gainsPrev[outChnlIdx];
4533 3397188 : move32();
4534 : }
4535 :
4536 : /* Process current output channel only if applying non-zero gains */
4537 45922580 : test();
4538 45922580 : test();
4539 45922580 : 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 27135745 : inSmpl = getSmplPtr_fx( inAudio, inChannelIdx, 0 );
4543 :
4544 : /* Set output pointer to first output channel sample */
4545 27135745 : outSmpl = getSmplPtr_fx( outAudio, outChnlIdx, 0 );
4546 :
4547 27135745 : test();
4548 27135745 : 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 10024117680 : *outSmpl = L_add( Mpy_32_32( currentGain, ( *inSmpl ) ), *outSmpl );
4554 10024117680 : move32();
4555 10024117680 : ++outSmpl;
4556 10024117680 : ++inSmpl;
4557 : }
4558 10024117680 : WHILE( inSmpl != lastInSmpl );
4559 : }
4560 : ELSE
4561 : {
4562 1996136 : i = 0;
4563 1996136 : Word32 tmp = Q31_BY_SUB_FRAME_240;
4564 1996136 : Word32 tmp1 = 239; /* L_SUBFRAME_48k - 1 */
4565 1996136 : move32();
4566 1996136 : move32();
4567 1996136 : move32();
4568 1996136 : SWITCH( outAudio.config.numSamplesPerChannel )
4569 : {
4570 1051037 : case NUM_SAMPLES_960:
4571 1051037 : tmp = Q31_BY_NUM_SAMPLES_960;
4572 1051037 : tmp1 = 959; /* NUM_SAMPLES_960 - 1 */
4573 1051037 : move32();
4574 1051037 : move32();
4575 1051037 : 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_640:
4583 0 : tmp = Q31_BY_NUM_SAMPLES_640;
4584 0 : tmp1 = 639; /* NUM_SAMPLES_640 - 1 */
4585 0 : move32();
4586 0 : move32();
4587 0 : BREAK;
4588 0 : case NUM_SAMPLES_320:
4589 0 : tmp = Q31_BY_NUM_SAMPLES_320;
4590 0 : tmp1 = 319; /* NUM_SAMPLES_320 - 1 */
4591 0 : move32();
4592 0 : move32();
4593 0 : BREAK;
4594 0 : case NUM_SAMPLES_160:
4595 0 : tmp = Q31_BY_NUM_SAMPLES_160;
4596 0 : tmp1 = 159; /* NUM_SAMPLES_160 - 1 */
4597 0 : move32();
4598 0 : move32();
4599 0 : BREAK;
4600 945099 : case L_SUBFRAME_48k:
4601 945099 : tmp = Q31_BY_SUB_FRAME_240;
4602 945099 : tmp1 = 239; /* L_SUBFRAME_48k - 1 */
4603 945099 : move32();
4604 945099 : move32();
4605 945099 : BREAK;
4606 0 : case L_SUBFRAME_32k:
4607 0 : tmp = Q31_BY_SUB_FRAME_180;
4608 0 : tmp1 = 179; /* L_SUBFRAME_32k - 1 */
4609 0 : move32();
4610 0 : move32();
4611 0 : BREAK;
4612 0 : case L_SUBFRAME_16k:
4613 0 : tmp = Q31_BY_SUB_FRAME_80;
4614 0 : tmp1 = 79; /* L_SUBFRAME_16k - 1 */
4615 0 : move32();
4616 0 : move32();
4617 0 : BREAK;
4618 0 : case L_SUBFRAME_8k:
4619 0 : tmp = Q31_BY_SUB_FRAME_40;
4620 0 : tmp1 = 39; /* L_SUBFRAME_8k - 1 */
4621 0 : move32();
4622 0 : move32();
4623 0 : BREAK;
4624 0 : default:
4625 0 : BREAK;
4626 : }
4627 : /* Otherwise use weighted average between previous and current gain */
4628 1233823144 : DO
4629 : {
4630 1235819280 : IF( EQ_32( i, tmp1 ) )
4631 : {
4632 1996136 : fadeIn = ONE_IN_Q31;
4633 1996136 : move32();
4634 : }
4635 : ELSE
4636 : {
4637 1233823144 : fadeIn = UL_Mpy_32_32( i, tmp );
4638 : }
4639 1235819280 : fadeOut = L_sub( ONE_IN_Q31, fadeIn );
4640 :
4641 1235819280 : *outSmpl = L_add( Mpy_32_32( L_add( Mpy_32_32( fadeIn, currentGain ), Mpy_32_32( fadeOut, previousGain ) ), ( *inSmpl ) ), *outSmpl );
4642 1235819280 : move32();
4643 1235819280 : ++outSmpl;
4644 1235819280 : ++inSmpl;
4645 1235819280 : ++i;
4646 : }
4647 1235819280 : WHILE( inSmpl != lastInSmpl );
4648 : }
4649 : }
4650 : }
4651 :
4652 5282295 : return;
4653 : }
4654 : /* Take one channel from input buffer and copy it to each channel
4655 : in output buffer, with different gain applied per output channel */
4656 4334795 : static void renderBufferChannel_fx(
4657 : const IVAS_REND_AudioBuffer inAudio,
4658 : const Word32 inChannelIdx,
4659 : const Word32 *const outputGains, /* Q31 */
4660 : IVAS_REND_AudioBuffer outAudio )
4661 : {
4662 4334795 : renderBufferChannelLerp_fx( inAudio, inChannelIdx, outputGains, NULL, outAudio );
4663 :
4664 4334795 : return;
4665 : }
4666 :
4667 70522 : static ivas_error chooseCrossfade_fx(
4668 : const IVAS_REND_HeadRotData *headRotData,
4669 : const Word32 **pCrossfade /* Q31 */ )
4670 : {
4671 70522 : *pCrossfade = headRotData->crossfade_fx;
4672 :
4673 70522 : return IVAS_ERR_OK;
4674 : }
4675 :
4676 :
4677 25504 : static ivas_error rotateFrameMc_fx(
4678 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
4679 : AUDIO_CONFIG inConfig, /* i : Input Audio config */
4680 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs, /* i : Input Custom LS setup */
4681 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
4682 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
4683 : rotation_gains_Word32 gains_prev, /* i/o: Previous frame rotation gains */
4684 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
4685 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
4686 : )
4687 : {
4688 : Word16 i;
4689 : Word16 j;
4690 : const Word32 *crossfade; /* Q31 */
4691 : Word16 num_subframes;
4692 : Word16 subframe_idx, subframe_len;
4693 : Word32 azimuth_fx, elevation_fx; /* Q22 */
4694 : Word16 is_planar_setup, lfe_idx;
4695 : Word16 nchan;
4696 : Word16 ch_in, ch_out;
4697 : Word16 ch_in_woLFE, ch_out_woLFE;
4698 25504 : Word32 *readPtr, *writePtr = NULL;
4699 : const Word32 *ls_azimuth, *ls_elevation;
4700 : rotation_matrix_fx Rmat_fx;
4701 : rotation_gains_Word32 gains;
4702 : Word32 tmp_gains[MAX_INPUT_CHANNELS]; /* Q30 */
4703 : ivas_error error;
4704 25504 : push_wmops( "rotateFrameMc_fx" );
4705 25504 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
4706 : {
4707 0 : return error;
4708 : }
4709 25504 : IF( ( hCombinedOrientationData != NULL ) )
4710 : {
4711 25504 : num_subframes = ( *hCombinedOrientationData )->num_subframes;
4712 : }
4713 : ELSE
4714 : {
4715 0 : num_subframes = MAX_PARAM_SPATIAL_SUBFRAMES;
4716 : }
4717 25504 : move16();
4718 :
4719 25504 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
4720 : {
4721 12500 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ), IVAS_ERR_OK ) )
4722 : {
4723 0 : return error;
4724 : }
4725 : }
4726 : ELSE
4727 : {
4728 13004 : nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe );
4729 : }
4730 :
4731 25504 : IF( NE_32( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ), IVAS_ERR_OK ) )
4732 : {
4733 0 : return error;
4734 : }
4735 :
4736 : /* initialize gains to passthrough */
4737 319068 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
4738 : {
4739 293564 : set32_fx( gains[ch_in], 0, nchan );
4740 293564 : gains[ch_in][ch_in] = ONE_IN_Q30;
4741 293564 : move32();
4742 : }
4743 :
4744 : /* subframe loop */
4745 : Word16 tmp_e;
4746 25504 : Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e );
4747 25504 : tmp = shr( tmp, negate( add( 1, tmp_e ) ) );
4748 25504 : subframe_len = tmp;
4749 25504 : move16();
4750 :
4751 66314 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
4752 : {
4753 163240 : FOR( i = 0; i < 3; i++ )
4754 : {
4755 122430 : IF( hCombinedOrientationData != NULL )
4756 : {
4757 489720 : FOR( j = 0; j < 3; j++ )
4758 : {
4759 367290 : Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
4760 367290 : move32();
4761 : }
4762 : }
4763 : ELSE
4764 : {
4765 : /* Set to identity */
4766 0 : set32_fx( Rmat_fx[i], 0, 3 );
4767 0 : Rmat_fx[i][i] = ONE_IN_Q30;
4768 0 : move32();
4769 : }
4770 : }
4771 :
4772 510570 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
4773 : {
4774 : /* skip LFE */
4775 469760 : IF( EQ_16( ch_in, lfe_idx ) )
4776 : {
4777 20000 : CONTINUE;
4778 : }
4779 :
4780 : /* input channel index without LFE */
4781 449760 : test();
4782 449760 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_in, lfe_idx ) ) )
4783 : {
4784 85600 : ch_in_woLFE = sub( ch_in, 1 );
4785 : }
4786 : ELSE
4787 : {
4788 364160 : ch_in_woLFE = ch_in;
4789 364160 : move16();
4790 : }
4791 :
4792 :
4793 : /* gains for current subframe rotation */
4794 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 );
4795 :
4796 449760 : test();
4797 449760 : test();
4798 449760 : IF( hEFAPdata != NULL && ( NE_32( ls_azimuth[ch_in_woLFE], azimuth_fx ) || NE_32( ls_elevation[ch_in_woLFE], elevation_fx ) ) )
4799 : {
4800 144730 : efap_determine_gains_fx( hEFAPdata, tmp_gains, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
4801 :
4802 1444790 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
4803 : {
4804 : /* skip LFE */
4805 1300060 : IF( EQ_16( ch_out, lfe_idx ) )
4806 : {
4807 144730 : CONTINUE;
4808 : }
4809 :
4810 : /* output channel index without LFE */
4811 1155330 : test();
4812 1155330 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_out, lfe_idx ) ) )
4813 : {
4814 721140 : ch_out_woLFE = sub( ch_out, 1 );
4815 : }
4816 : ELSE
4817 : {
4818 434190 : ch_out_woLFE = ch_out;
4819 434190 : move16();
4820 : }
4821 :
4822 1155330 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
4823 1155330 : move32();
4824 : }
4825 : }
4826 : }
4827 :
4828 : /* apply panning gains by mtx multiplication */
4829 510570 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
4830 : {
4831 6541120 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
4832 : {
4833 6071360 : writePtr = getSmplPtr_fx( outAudio, ch_out, imult1616( subframe_idx, subframe_len ) ); /* Qx */
4834 6071360 : readPtr = getSmplPtr_fx( inAudio, ch_in, imult1616( subframe_idx, subframe_len ) ); /* Qx */
4835 : /* crossfade with previous rotation gains */
4836 1463197760 : FOR( i = 0; i < subframe_len; i++ )
4837 : {
4838 1457126400 : *writePtr =
4839 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] ) ),
4840 1457126400 : Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); /* Qx - 1 */
4841 1457126400 : move32();
4842 1457126400 : readPtr++;
4843 1457126400 : writePtr++;
4844 : }
4845 : }
4846 : }
4847 :
4848 : /* move gains to gains_prev */
4849 510570 : FOR( i = 0; i < nchan; i++ )
4850 : {
4851 469760 : MVR2R_WORD32( gains[i], gains_prev[i], nchan );
4852 : }
4853 : }
4854 :
4855 25504 : pop_wmops();
4856 25504 : return IVAS_ERR_OK;
4857 : }
4858 :
4859 :
4860 45018 : static ivas_error rotateFrameSba_fx(
4861 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
4862 : const AUDIO_CONFIG inConfig, /* i : Input Audio config */
4863 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
4864 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
4865 : Word16 gains_prev[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS], /* i/o: Previous frame rotation gains Q14 */
4866 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
4867 : )
4868 : {
4869 : Word16 i, l, n, m;
4870 : Word16 m1, m2;
4871 : Word16 shd_rot_max_order;
4872 : const Word32 *crossfade; /* Q31 */
4873 : Word16 num_subframes;
4874 : Word16 subframe_idx, subframe_len;
4875 : Word32 *writePtr;
4876 : Word32 tmpRot[2 * HEADROT_ORDER + 1];
4877 : Word16 gains[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; /* Q14 */
4878 : Word32 temp;
4879 : Word32 Rmat[3][3]; /* Q30 */
4880 : ivas_error error;
4881 : Word16 idx, exp;
4882 : Word32 cf, oneminuscf; /* Q31 */
4883 : Word32 val;
4884 :
4885 45018 : push_wmops( "rotateFrameSba" );
4886 :
4887 45018 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
4888 : {
4889 0 : return error;
4890 : }
4891 45018 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
4892 45018 : move16();
4893 :
4894 45018 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inConfig, &shd_rot_max_order ) ), IVAS_ERR_OK ) )
4895 : {
4896 0 : return error;
4897 : }
4898 :
4899 : // subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
4900 45018 : subframe_len = BASOP_Util_Divide1616_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &exp );
4901 45018 : subframe_len = shr( subframe_len, sub( 15, exp ) );
4902 117063 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
4903 : {
4904 : /* initialize rotation matrices with zeros */
4905 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
4906 : {
4907 1152720 : set16_fx( gains[i], 0, HEADROT_SHMAT_DIM );
4908 : }
4909 :
4910 288180 : FOR( i = 0; i < 3; i++ )
4911 : {
4912 216135 : IF( hCombinedOrientationData != NULL )
4913 : {
4914 864540 : FOR( l = 0; l < 3; l++ )
4915 : {
4916 648405 : Rmat[i][l] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][l]; /* Q30 */
4917 648405 : move32();
4918 : }
4919 : }
4920 : ELSE
4921 : {
4922 : /* Set to identity */
4923 0 : set32_fx( Rmat[i], 0, 3 );
4924 0 : Rmat[i][i] = ONE_IN_Q30;
4925 0 : move32();
4926 : }
4927 : }
4928 : /* calculate ambisonics rotation matrices for the previous and current frames */
4929 72045 : SHrotmatgen_fx( gains, Rmat, shd_rot_max_order );
4930 :
4931 : #ifdef DEBUGGING
4932 : dbgwrite_txt( (const float *) ( gains[0] ), HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_code_gains.txt", NULL );
4933 : dbgwrite_txt( (const float *) ( Rmat[0] ), 3 * 3, "Fixed_code_Rmat.txt", NULL );
4934 : #endif
4935 17362845 : FOR( i = 0; i < subframe_len; i++ )
4936 : {
4937 17290800 : idx = add( imult1616( subframe_idx, subframe_len ), i );
4938 : // cf = crossfade[i];
4939 17290800 : cf = crossfade[i];
4940 17290800 : move32();
4941 17290800 : oneminuscf = L_sub( ONE_IN_Q31, cf );
4942 : /* As the rotation matrix becomes block diagonal in a SH basis, we can*/
4943 : /* apply each angular-momentum block individually to save complexity. */
4944 :
4945 : /* loop over l blocks */
4946 17290800 : m1 = 1;
4947 17290800 : m2 = 4;
4948 17290800 : move16();
4949 17290800 : move16();
4950 51872400 : FOR( l = 1; l <= shd_rot_max_order; l++ )
4951 : {
4952 : /* compute mtx-vector product for this l */
4953 184435200 : FOR( n = m1; n < m2; n++ )
4954 : {
4955 149853600 : tmpRot[n - m1] = 0;
4956 149853600 : move32();
4957 876067200 : FOR( m = m1; m < m2; m++ )
4958 : {
4959 726213600 : val = inAudio.data_fx[m * inAudio.config.numSamplesPerChannel + idx];
4960 : /* crossfade with previous rotation gains */
4961 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 );
4962 726213600 : tmpRot[n - m1] = L_add( L_shl( temp, 1 ), tmpRot[n - m1] );
4963 726213600 : move32();
4964 726213600 : move32();
4965 : }
4966 : }
4967 : /* write back the result */
4968 184435200 : FOR( n = m1; n < m2; n++ )
4969 : {
4970 149853600 : writePtr = getSmplPtr_fx( outAudio, n, idx );
4971 149853600 : ( *writePtr ) = tmpRot[n - m1];
4972 149853600 : move32();
4973 : }
4974 34581600 : m1 = m2;
4975 34581600 : move16();
4976 34581600 : m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
4977 : }
4978 : }
4979 :
4980 : /* move SHrotmat to SHrotmat_prev */
4981 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
4982 : {
4983 1152720 : Copy( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
4984 : }
4985 : }
4986 45018 : pop_wmops();
4987 :
4988 45018 : return IVAS_ERR_OK;
4989 : }
4990 :
4991 150000 : static ivas_error renderIsmToBinaural(
4992 : input_ism *ismInput,
4993 : IVAS_REND_AudioBuffer outAudio )
4994 : {
4995 : Word32 tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
4996 : ivas_error error;
4997 : Word16 ism_md_subframe_update_ext;
4998 : Word16 i;
4999 150000 : Word16 exp = *outAudio.pq_fact;
5000 150000 : move16();
5001 150000 : push_wmops( "renderIsmToBinaural" );
5002 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5003 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 */ ) );
5004 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer );
5005 :
5006 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5007 : {
5008 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5009 : }
5010 :
5011 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,
5012 : *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer, &exp ) ),
5013 : IVAS_ERR_OK ) )
5014 : {
5015 0 : return error;
5016 : }
5017 :
5018 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5019 : {
5020 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5021 : }
5022 :
5023 150000 : IF( ismInput->hReverb != NULL )
5024 : {
5025 0 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
5026 : {
5027 0 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
5028 : {
5029 0 : tmpTDRendBuffer[i][j] = L_shl( tmpTDRendBuffer[i][j], Q2 ); /* Q(exp + 2) */
5030 0 : move32();
5031 : }
5032 : }
5033 : }
5034 150000 : accumulate2dArrayToBuffer_fx( tmpTDRendBuffer, &outAudio );
5035 :
5036 150000 : pop_wmops();
5037 :
5038 150000 : return IVAS_ERR_OK;
5039 : }
5040 :
5041 302544 : static Word16 getNumSubframesInBuffer(
5042 : const IVAS_REND_AudioBuffer *buffer,
5043 : const Word32 sampleRate )
5044 : {
5045 302544 : Word16 scale, temp = extract_l( Mpy_32_32( sampleRate, 10737418 /* 1 / FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
5046 302544 : temp = BASOP_Util_Divide1616_Scale( buffer->config.numSamplesPerChannel, temp, &scale );
5047 302544 : temp = shr( temp, sub( 15, scale ) ); /* Q0 */
5048 302544 : return temp;
5049 : }
5050 :
5051 :
5052 150000 : static ivas_error renderIsmToBinauralRoom(
5053 : input_ism *ismInput,
5054 : IVAS_REND_AudioBuffer outAudio,
5055 : Word16 *exp )
5056 : {
5057 : Word16 position_changed;
5058 : Word16 i, j;
5059 : Word32 azi_rot, ele_rot; /* Q22 */
5060 : Word16 subframe_idx;
5061 : Word16 tmp;
5062 : rotation_matrix_fx Rmat;
5063 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5064 : ivas_error error;
5065 : pan_vector_fx currentPanGains;
5066 : IVAS_REND_AudioBuffer tmpMcBuffer;
5067 : IVAS_ISM_METADATA rotatedPosPrev;
5068 : IVAS_ISM_METADATA rotatedPos;
5069 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5070 : Word8 combinedOrientationEnabled;
5071 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
5072 :
5073 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5074 : {
5075 2400000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
5076 : }
5077 :
5078 150000 : push_wmops( "renderIsmToBinauralRoom" );
5079 :
5080 150000 : rotatedPosPrev = defaultObjectPosition();
5081 150000 : rotatedPos = defaultObjectPosition();
5082 :
5083 150000 : hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
5084 150000 : combinedOrientationEnabled = 0;
5085 150000 : move16();
5086 150000 : IF( hCombinedOrientationData != NULL )
5087 : {
5088 270000 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5089 : {
5090 195000 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5091 : {
5092 75000 : combinedOrientationEnabled = 1;
5093 75000 : move16();
5094 75000 : BREAK;
5095 : }
5096 : }
5097 : }
5098 :
5099 150000 : IF( combinedOrientationEnabled )
5100 : {
5101 150000 : FOR( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
5102 : {
5103 300000 : FOR( i = 0; i < 3; i++ )
5104 : {
5105 225000 : test();
5106 225000 : IF( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
5107 : {
5108 900000 : FOR( j = 0; j < 3; j++ )
5109 : {
5110 675000 : Rmat[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
5111 675000 : move32();
5112 : }
5113 : }
5114 : ELSE
5115 : {
5116 : /* Set to identity */
5117 0 : set_zero_fx( Rmat[i], 3 );
5118 0 : Rmat[i][i] = ONE_IN_Q30;
5119 0 : move32();
5120 : }
5121 : }
5122 : }
5123 : }
5124 :
5125 : /* get previous position */
5126 150000 : IF( combinedOrientationEnabled )
5127 : {
5128 75000 : rotateAziEle_fx_frac_az_el( ismInput->previousPos.azimuth_fx, ismInput->previousPos.elevation_fx, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
5129 75000 : rotatedPosPrev.azimuth_fx = azi_rot;
5130 75000 : move32();
5131 75000 : rotatedPosPrev.elevation_fx = ele_rot;
5132 75000 : move32();
5133 : }
5134 : ELSE
5135 : {
5136 75000 : rotatedPosPrev.azimuth_fx = ismInput->previousPos.azimuth_fx;
5137 75000 : move32();
5138 75000 : rotatedPosPrev.elevation_fx = ismInput->previousPos.elevation_fx;
5139 75000 : move32();
5140 : }
5141 :
5142 : /* get current position */
5143 150000 : IF( combinedOrientationEnabled )
5144 : {
5145 75000 : rotateAziEle_fx_frac_az_el( ismInput->currentPos.azimuth_fx, ismInput->currentPos.elevation_fx, &azi_rot, &ele_rot, Rmat, 0 );
5146 75000 : rotatedPos.azimuth_fx = azi_rot;
5147 75000 : move32();
5148 75000 : rotatedPos.elevation_fx = ele_rot;
5149 75000 : move32();
5150 : }
5151 : ELSE
5152 : {
5153 75000 : rotatedPos.azimuth_fx = ismInput->currentPos.azimuth_fx;
5154 75000 : move32();
5155 75000 : rotatedPos.elevation_fx = ismInput->currentPos.elevation_fx;
5156 75000 : move32();
5157 : }
5158 :
5159 150000 : test();
5160 150000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &rotatedPos, &rotatedPosPrev );
5161 150000 : move16();
5162 :
5163 : /* set previous gains if this is the first frame */
5164 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 ) )
5165 : {
5166 0 : return error;
5167 : }
5168 :
5169 : /* compute gains only if position changed */
5170 150000 : IF( position_changed )
5171 : {
5172 64693 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
5173 : rotatedPos.azimuth_fx,
5174 : rotatedPos.elevation_fx,
5175 : currentPanGains ) ),
5176 : IVAS_ERR_OK ) )
5177 : {
5178 0 : return error;
5179 : }
5180 : }
5181 :
5182 : /* intermediate rendering to 7_1_4 */
5183 150000 : tmpMcBuffer = ismInput->base.inputBuffer;
5184 :
5185 150000 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
5186 : {
5187 0 : return error;
5188 : }
5189 :
5190 150000 : tmpMcBuffer.config.numChannels = tmp;
5191 150000 : move16();
5192 150000 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
5193 150000 : set_zero_fx( tmpMcBuffer.data_fx, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
5194 :
5195 150000 : IF( position_changed )
5196 : {
5197 64693 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5198 : currentPanGains,
5199 64693 : ismInput->prev_pan_gains_fx,
5200 : tmpMcBuffer );
5201 : }
5202 : ELSE
5203 : {
5204 85307 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5205 85307 : ismInput->prev_pan_gains_fx,
5206 : NULL,
5207 : tmpMcBuffer );
5208 : }
5209 :
5210 150000 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpRendBuffer );
5211 :
5212 : /* save gains for next frame */
5213 600000 : FOR( i = 0; i < 3; i++ )
5214 : {
5215 450000 : Copy32( Rmat[i], ismInput->rot_mat_prev[i], 3 );
5216 : }
5217 :
5218 150000 : IF( position_changed )
5219 : {
5220 64693 : Copy32( currentPanGains, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
5221 : }
5222 : // Crend_process porting
5223 : CREND_HANDLE hCrend;
5224 150000 : hCrend = ismInput->crendWrapper->hCrend;
5225 150000 : IF( hCrend->reflections != NULL )
5226 : {
5227 0 : test();
5228 0 : IF( EQ_32( hCrend->reflections->use_er, 1 ) && EQ_32( hCrend->reflections->is_ready, 1 ) )
5229 : {
5230 0 : FOR( i = 0; i < 150; i++ )
5231 : {
5232 0 : hCrend->reflections->shoebox_data.gains.data_fx[i] = L_shl( hCrend->reflections->shoebox_data.gains.data_fx[i], Q9 );
5233 0 : move32();
5234 : }
5235 : }
5236 : }
5237 :
5238 150000 : move16();
5239 :
5240 : /* render 7_1_4 with BRIRs */
5241 150000 : IF( NE_32( ( error = ivas_rend_crendProcess( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR,
5242 : NULL, NULL, NULL, NULL, p_tmpRendBuffer, *ismInput->base.ctx.pOutSampleRate,
5243 : getNumSubframesInBuffer( &outAudio, *ismInput->base.ctx.pOutSampleRate ) ) ),
5244 : IVAS_ERR_OK ) )
5245 :
5246 : {
5247 0 : return error;
5248 : }
5249 150000 : IF( hCrend->hReverb != NULL )
5250 : {
5251 0 : *exp = sub( *exp, 2 );
5252 0 : move16();
5253 : }
5254 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
5255 :
5256 150000 : free( tmpMcBuffer.data_fx );
5257 :
5258 150000 : pop_wmops();
5259 :
5260 150000 : return IVAS_ERR_OK;
5261 : }
5262 150000 : static ivas_error renderIsmToBinauralReverb(
5263 : input_ism *ismInput,
5264 : IVAS_REND_AudioBuffer outAudio )
5265 : {
5266 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5267 : ivas_error error;
5268 : Word16 ism_md_subframe_update_ext, i;
5269 150000 : Word16 exp = *outAudio.pq_fact;
5270 150000 : move16();
5271 :
5272 150000 : push_wmops( "renderIsmToBinauralRoom" );
5273 :
5274 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5275 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 */ ) );
5276 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
5277 :
5278 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5279 : {
5280 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5281 : }
5282 :
5283 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 ) )
5284 : {
5285 0 : return error;
5286 : }
5287 :
5288 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5289 : {
5290 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( 11, exp ) ) ); /* Q(exp) */
5291 : }
5292 :
5293 150000 : IF( ismInput->hReverb != NULL )
5294 : {
5295 450000 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
5296 : {
5297 115500000 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
5298 : {
5299 115200000 : tmpRendBuffer_fx[i][j] = L_shl( tmpRendBuffer_fx[i][j], 2 ); /* Q(exp + 2) */
5300 115200000 : move16();
5301 : }
5302 : }
5303 : }
5304 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
5305 150000 : pop_wmops();
5306 :
5307 150000 : return IVAS_ERR_OK;
5308 : }
5309 :
5310 569500 : static ivas_error renderIsmToMc(
5311 : input_ism *ismInput,
5312 : const IVAS_REND_AudioBuffer outAudio )
5313 : {
5314 : Word8 position_changed;
5315 : pan_vector_fx currentPanGains_fx; /* Q31 */
5316 : ivas_error error;
5317 :
5318 569500 : push_wmops( "renderIsmToMc" );
5319 :
5320 569500 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5321 569500 : move32();
5322 569500 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5323 569500 : move32();
5324 569500 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5325 569500 : move32();
5326 569500 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5327 569500 : move32();
5328 :
5329 569500 : test();
5330 569500 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
5331 569500 : move16();
5332 569500 : IF( EQ_32( *ismInput->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_STEREO ) )
5333 : {
5334 83500 : IF( ismInput->nonDiegeticPan )
5335 : {
5336 7500 : currentPanGains_fx[0] = L_add( L_shr( ismInput->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); /* Q31 */
5337 7500 : currentPanGains_fx[1] = L_sub( ONE_IN_Q31, currentPanGains_fx[0] ); /* Q31 */
5338 7500 : ismInput->prev_pan_gains_fx[0] = currentPanGains_fx[0]; /* Q31 */
5339 7500 : ismInput->prev_pan_gains_fx[1] = currentPanGains_fx[1]; /* Q31 */
5340 7500 : move32();
5341 7500 : move32();
5342 7500 : move32();
5343 7500 : move32();
5344 : }
5345 : ELSE
5346 : {
5347 76000 : set32_fx( currentPanGains_fx, 0, MAX_OUTPUT_CHANNELS );
5348 :
5349 : Word16 gains_fx[2];
5350 : Word16 azimuth_tmp, elevation_tmp;
5351 :
5352 76000 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
5353 76000 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
5354 :
5355 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
5356 76000 : currentPanGains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
5357 76000 : currentPanGains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
5358 76000 : move32();
5359 76000 : move32();
5360 :
5361 76000 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
5362 76000 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
5363 :
5364 76000 : set32_fx( ismInput->prev_pan_gains_fx, 0, MAX_OUTPUT_CHANNELS );
5365 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
5366 76000 : ismInput->prev_pan_gains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
5367 76000 : ismInput->prev_pan_gains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
5368 76000 : move32();
5369 76000 : move32();
5370 : }
5371 : }
5372 : ELSE
5373 : {
5374 : /* compute gains only if position changed */
5375 486000 : IF( position_changed )
5376 : {
5377 : // TODO tmu review when #215 is resolved
5378 207304 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
5379 : ismInput->currentPos.azimuth_fx,
5380 : ismInput->currentPos.elevation_fx,
5381 : currentPanGains_fx ) ),
5382 : IVAS_ERR_OK ) )
5383 : {
5384 0 : return error;
5385 : }
5386 : }
5387 :
5388 : /* set previous gains if this is the first frame */
5389 486000 : IF( !ismInput->firstFrameRendered )
5390 : {
5391 : // TODO tmu review when #215 is resolved
5392 188 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
5393 : ismInput->previousPos.azimuth_fx,
5394 : ismInput->previousPos.elevation_fx,
5395 : ismInput->prev_pan_gains_fx ) ),
5396 : IVAS_ERR_OK ) )
5397 : {
5398 0 : return error;
5399 : }
5400 : /* fix2float to be removed */
5401 : }
5402 : }
5403 :
5404 : /* Assume num channels in audio buffer to be 1.
5405 : * This should have been validated in IVAS_REND_FeedInputAudio() */
5406 569500 : IF( position_changed )
5407 : {
5408 244300 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5409 : currentPanGains_fx,
5410 244300 : ismInput->prev_pan_gains_fx,
5411 : outAudio );
5412 : }
5413 : ELSE
5414 : {
5415 325200 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5416 325200 : ismInput->prev_pan_gains_fx,
5417 : NULL,
5418 : outAudio );
5419 : }
5420 :
5421 569500 : IF( position_changed )
5422 : {
5423 244300 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
5424 : }
5425 :
5426 569500 : pop_wmops();
5427 :
5428 :
5429 569500 : return IVAS_ERR_OK;
5430 : }
5431 228000 : static ivas_error renderIsmToSba(
5432 : input_ism *ismInput,
5433 : const AUDIO_CONFIG outConfig,
5434 : const IVAS_REND_AudioBuffer outAudio )
5435 : {
5436 : Word16 i;
5437 : Word8 position_changed;
5438 : Word16 ambiOrderOut;
5439 : Word16 numOutChannels;
5440 : pan_vector_fx currentPanGains_fx;
5441 : ivas_error error;
5442 228000 : error = IVAS_ERR_OK;
5443 228000 : move32();
5444 :
5445 228000 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5446 228000 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5447 228000 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5448 228000 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
5449 228000 : move32();
5450 228000 : move32();
5451 228000 : move32();
5452 228000 : move32();
5453 :
5454 228000 : push_wmops( "renderIsmToSba" );
5455 :
5456 228000 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
5457 : {
5458 0 : return error;
5459 : }
5460 :
5461 228000 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &ambiOrderOut ) ), IVAS_ERR_OK ) )
5462 : {
5463 0 : return error;
5464 : }
5465 :
5466 228000 : test();
5467 228000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
5468 228000 : move16();
5469 :
5470 : /* set previous gains if this is the first frame */
5471 : Word16 azimuth_tmp, elevation_tmp;
5472 228000 : IF( !ismInput->firstFrameRendered )
5473 : {
5474 : // TODO tmu review when #215 is resolved
5475 84 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
5476 84 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
5477 84 : ivas_dirac_dec_get_response_fx( azimuth_tmp,
5478 : elevation_tmp,
5479 84 : ismInput->prev_pan_gains_fx,
5480 : ambiOrderOut,
5481 : Q29 );
5482 1428 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5483 : {
5484 1344 : ismInput->prev_pan_gains_fx[i] = L_shl_sat( ismInput->prev_pan_gains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
5485 1344 : move32();
5486 : }
5487 : }
5488 :
5489 : /* compute gains only if position changed */
5490 228000 : IF( position_changed )
5491 : {
5492 : // TODO tmu review when #215 is resolved
5493 88848 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
5494 88848 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
5495 88848 : ivas_dirac_dec_get_response_fx( azimuth_tmp,
5496 : elevation_tmp,
5497 : currentPanGains_fx,
5498 : ambiOrderOut,
5499 : Q29 );
5500 1510416 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5501 : {
5502 1421568 : currentPanGains_fx[i] = L_shl_sat( currentPanGains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
5503 1421568 : move32();
5504 : }
5505 : }
5506 :
5507 : /* Assume num channels in audio buffer to be 1.
5508 : * This should have been validated in IVAS_REND_FeedInputAudio() */
5509 228000 : IF( position_changed )
5510 : {
5511 88848 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5512 : currentPanGains_fx,
5513 88848 : ismInput->prev_pan_gains_fx,
5514 : outAudio );
5515 : }
5516 : ELSE
5517 : {
5518 139152 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
5519 139152 : ismInput->prev_pan_gains_fx,
5520 : NULL,
5521 : outAudio );
5522 : }
5523 :
5524 228000 : IF( position_changed )
5525 : {
5526 88848 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
5527 : }
5528 228000 : pop_wmops();
5529 :
5530 228000 : return error;
5531 : }
5532 :
5533 150 : static void renderIsmToMasa(
5534 : input_ism *ismInput,
5535 : IVAS_REND_AudioBuffer outAudio,
5536 : Word16 *exp )
5537 : {
5538 : Word32 tmpRendBuffer_fx[MAX_NUM_OBJECTS][L_FRAME48k];
5539 : Word16 i, guard_bits, q_min, q_diff;
5540 :
5541 150 : push_wmops( "renderIsmToMasa" );
5542 :
5543 150 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
5544 :
5545 150 : q_min = MAX_16;
5546 150 : move16();
5547 :
5548 750 : FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
5549 : {
5550 600 : q_min = s_min( q_min, L_norm_arr( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel ) );
5551 : }
5552 :
5553 150 : guard_bits = find_guarded_bits_fx( ismInput->base.inputBuffer.config.numSamplesPerChannel );
5554 150 : q_min = sub( add( q_min, *outAudio.pq_fact ), guard_bits );
5555 150 : q_diff = sub( q_min, *outAudio.pq_fact );
5556 :
5557 750 : FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
5558 : {
5559 600 : scale_sig32( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel, q_diff ); // *outAudio.pq_fact -> q_min
5560 : }
5561 :
5562 150 : ivas_omasa_ana_fx( ismInput->hOMasa, tmpRendBuffer_fx, &q_min, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
5563 :
5564 150 : *exp = q_min;
5565 150 : move16();
5566 :
5567 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
5568 :
5569 150 : pop_wmops();
5570 :
5571 150 : return;
5572 : }
5573 :
5574 1247650 : static ivas_error renderInputIsm(
5575 : input_ism *ismInput,
5576 : const AUDIO_CONFIG outConfig,
5577 : const IVAS_REND_AudioBuffer outAudio )
5578 : {
5579 : ivas_error error;
5580 : IVAS_REND_AudioBuffer inAudio;
5581 1247650 : Word16 exp = *outAudio.pq_fact;
5582 1247650 : move16();
5583 :
5584 1247650 : error = IVAS_ERR_OK;
5585 1247650 : move32();
5586 1247650 : inAudio = ismInput->base.inputBuffer;
5587 :
5588 1247650 : IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
5589 : {
5590 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" );
5591 : }
5592 1247650 : ismInput->base.numNewSamplesPerChannel = 0;
5593 1247650 : move32();
5594 :
5595 : /* Apply input gain to new audio */
5596 1247650 : v_multc_fixed( inAudio.data_fx, ismInput->base.gain_fx, inAudio.data_fx, imult1616( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
5597 1247650 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 );
5598 1247650 : move16();
5599 1247650 : exp = *outAudio.pq_fact;
5600 1247650 : move16();
5601 :
5602 : /* set combined orientation subframe info to start info */
5603 1247650 : ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
5604 :
5605 :
5606 1247650 : SWITCH( getAudioConfigType( outConfig ) )
5607 : {
5608 569500 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
5609 569500 : error = renderIsmToMc( ismInput, outAudio );
5610 569500 : BREAK;
5611 228000 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
5612 228000 : error = renderIsmToSba( ismInput, outConfig, outAudio );
5613 228000 : BREAK;
5614 450000 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
5615 : SWITCH( outConfig )
5616 : {
5617 150000 : case IVAS_AUDIO_CONFIG_BINAURAL:
5618 150000 : error = renderIsmToBinaural( ismInput, outAudio );
5619 150000 : BREAK;
5620 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
5621 150000 : error = renderIsmToBinauralRoom( ismInput, outAudio, &exp );
5622 150000 : BREAK;
5623 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
5624 150000 : error = renderIsmToBinauralReverb( ismInput, outAudio );
5625 150000 : BREAK;
5626 0 : default:
5627 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
5628 : }
5629 450000 : BREAK;
5630 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
5631 150 : renderIsmToMasa( ismInput, outAudio, &exp );
5632 150 : BREAK;
5633 0 : default:
5634 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
5635 : }
5636 :
5637 : /* Check error here to keep switch statement more compact */
5638 1247650 : IF( NE_32( error, IVAS_ERR_OK ) )
5639 : {
5640 0 : return error;
5641 : }
5642 :
5643 1247650 : ismInput->firstFrameRendered = TRUE;
5644 1247650 : move16();
5645 :
5646 1247650 : *outAudio.pq_fact = exp;
5647 1247650 : move16();
5648 :
5649 1247650 : return error;
5650 : }
5651 :
5652 1126140 : static ivas_error renderActiveInputsIsm(
5653 : IVAS_REND_HANDLE hIvasRend,
5654 : IVAS_REND_AudioBuffer outAudio )
5655 : {
5656 : Word16 i;
5657 : input_ism *pCurrentInput;
5658 : ivas_error error;
5659 1126140 : Word16 input_q = Q8;
5660 1126140 : move16();
5661 5630700 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
5662 : {
5663 4504560 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5664 : {
5665 : /* Skip inactive inputs */
5666 3256910 : CONTINUE;
5667 : }
5668 :
5669 1247650 : *outAudio.pq_fact = Q8;
5670 1247650 : move16();
5671 1247650 : IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
5672 : {
5673 0 : return error;
5674 : }
5675 2925119650 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
5676 : {
5677 2923872000 : outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
5678 2923872000 : move32();
5679 : }
5680 1247650 : *outAudio.pq_fact = sub( input_q, 1 );
5681 1247650 : move16();
5682 : }
5683 1126140 : return IVAS_ERR_OK;
5684 : }
5685 87012 : static ivas_error renderLfeToBinaural_fx(
5686 : const input_mc *mcInput,
5687 : IVAS_REND_AudioBuffer outAudio,
5688 : Word16 in_q,
5689 : Word16 out_q )
5690 : {
5691 : Word16 lfe_idx;
5692 : Word32 gain_fx;
5693 : Word16 ear_idx, i, r_shift;
5694 : Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL];
5695 : Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
5696 : const Word32 *lfeInput;
5697 : Word32 *writePtr;
5698 :
5699 87012 : assert( ( outAudio.config.numChannels == 2 ) && "Must be binaural output" );
5700 :
5701 87012 : push_wmops( "renderLfeToBinaural" );
5702 87012 : gain_fx = GAIN_LFE_WORD32; /* 1.88364911f in Q30 */
5703 87012 : move32();
5704 :
5705 87012 : IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
5706 : {
5707 48000 : lfe_idx = LFE_CHANNEL;
5708 48000 : move16();
5709 : }
5710 39012 : ELSE IF( mcInput->customLsInput.num_lfe > 0 )
5711 : {
5712 0 : lfe_idx = mcInput->customLsInput.lfe_idx[0];
5713 0 : move16();
5714 : }
5715 : ELSE
5716 : {
5717 : /* no LFE to render */
5718 : #ifdef FIX_1740_MISING_POP_WMOPS
5719 39012 : pop_wmops();
5720 : #endif
5721 39012 : return IVAS_ERR_OK;
5722 : }
5723 :
5724 : /* --- Prepare LFE signal to be added to binaural output --- */
5725 48000 : lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 );
5726 48000 : frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
5727 48000 : move16();
5728 48000 : num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
5729 48000 : move16();
5730 48000 : num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame );
5731 :
5732 : /* Assuming LFE should be delayed by less that the duration of one frame */
5733 48000 : assert( mcInput->binauralDelaySmp < frame_size );
5734 :
5735 : /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
5736 48000 : v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
5737 :
5738 : /* Continue filling tmp buffer, now with LFE signal from current frame */
5739 48000 : v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); /* Qx - 1 */
5740 :
5741 : /* Save remaining LFE samples of current frame for next frame */
5742 48000 : MVR2R_WORD32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame );
5743 48000 : r_shift = sub( sub( in_q, 1 ), out_q );
5744 :
5745 48000 : IF( r_shift != 0 )
5746 : {
5747 14533750 : FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ )
5748 : {
5749 14496000 : tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); /* Q(out_q) */
5750 14496000 : move32();
5751 : }
5752 : }
5753 : /* Copy LFE to left and right ears */
5754 144000 : FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
5755 : {
5756 96000 : writePtr = getSmplPtr_fx( outAudio, ear_idx, 0 );
5757 96000 : move32();
5758 96000 : v_add_fixed_no_hdrm( writePtr, tmpLfeBuffer, writePtr, frame_size ); /* Q(out_q) */
5759 : }
5760 :
5761 48000 : pop_wmops();
5762 :
5763 48000 : return IVAS_ERR_OK;
5764 : }
5765 29004 : static ivas_error renderMcToBinaural(
5766 : input_mc *mcInput,
5767 : const AUDIO_CONFIG outConfig,
5768 : IVAS_REND_AudioBuffer outAudio )
5769 : {
5770 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5771 : AUDIO_CONFIG inConfig;
5772 : ivas_error error;
5773 : IVAS_REND_AudioBuffer tmpRotBuffer;
5774 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5775 : Word8 combinedOrientationEnabled;
5776 : Word16 subframe_idx;
5777 : Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS];
5778 : Word16 i;
5779 29004 : Word16 exp = *outAudio.pq_fact;
5780 29004 : move16();
5781 493068 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5782 : {
5783 464064 : p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i];
5784 : }
5785 29004 : push_wmops( "renderMcToBinaural" );
5786 29004 : inConfig = mcInput->base.inConfig;
5787 29004 : move32();
5788 29004 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
5789 29004 : combinedOrientationEnabled = 0;
5790 29004 : move16();
5791 29004 : IF( hCombinedOrientationData != NULL )
5792 : {
5793 52209 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5794 : {
5795 37707 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5796 : {
5797 14502 : combinedOrientationEnabled = 1;
5798 14502 : move16();
5799 14502 : BREAK;
5800 : }
5801 : }
5802 : }
5803 :
5804 29004 : test();
5805 29004 : test();
5806 29004 : test();
5807 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 ) ) ) )
5808 : {
5809 18754 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
5810 :
5811 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5812 : {
5813 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5814 : }
5815 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,
5816 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ),
5817 : IVAS_ERR_OK ) )
5818 : {
5819 0 : return error;
5820 : }
5821 :
5822 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5823 : {
5824 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5825 : }
5826 : }
5827 : ELSE
5828 : {
5829 : /* apply rotation */
5830 10250 : IF( combinedOrientationEnabled )
5831 : {
5832 2250 : tmpRotBuffer = mcInput->base.inputBuffer;
5833 2250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
5834 2250 : set32_fx( tmpRotBuffer.data_fx, 0, imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
5835 :
5836 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 ) )
5837 : {
5838 0 : return error;
5839 : }
5840 :
5841 2250 : exp = sub( *outAudio.pq_fact, 1 );
5842 :
5843 2250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx );
5844 :
5845 2250 : free( tmpRotBuffer.data_fx );
5846 : }
5847 : ELSE
5848 : {
5849 8000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
5850 : }
5851 : // Porting Crend_process function
5852 : CREND_HANDLE hCrend;
5853 10250 : hCrend = mcInput->crendWrapper->hCrend;
5854 :
5855 : /* call CREND */
5856 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,
5857 : getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
5858 : IVAS_ERR_OK ) )
5859 : {
5860 0 : return error;
5861 : }
5862 10250 : IF( hCrend->hReverb != NULL )
5863 : {
5864 0 : exp = sub( exp, 2 );
5865 : }
5866 : }
5867 :
5868 29004 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
5869 :
5870 29004 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
5871 :
5872 : {
5873 0 : return error;
5874 : }
5875 29004 : *outAudio.pq_fact = exp;
5876 29004 : move16();
5877 29004 : pop_wmops();
5878 29004 : return IVAS_ERR_OK;
5879 : }
5880 32000 : static ivas_error renderMcToBinauralRoom(
5881 : input_mc *mcInput,
5882 : const AUDIO_CONFIG outConfig,
5883 : IVAS_REND_AudioBuffer outAudio )
5884 : {
5885 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5886 : AUDIO_CONFIG inConfig;
5887 : ivas_error error;
5888 : IVAS_REND_AudioBuffer tmpRotBuffer;
5889 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
5890 : Word16 i;
5891 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5892 : Word8 combinedOrientationEnabled;
5893 : Word16 subframe_idx;
5894 32000 : Word16 exp = *outAudio.pq_fact;
5895 32000 : move16();
5896 544000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5897 : {
5898 512000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
5899 : }
5900 :
5901 32000 : push_wmops( "renderMcToBinauralRoom" );
5902 32000 : inConfig = mcInput->base.inConfig;
5903 32000 : move32();
5904 32000 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
5905 32000 : combinedOrientationEnabled = 0;
5906 32000 : move16();
5907 32000 : IF( hCombinedOrientationData != NULL )
5908 : {
5909 57600 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5910 : {
5911 41600 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5912 : {
5913 16000 : combinedOrientationEnabled = 1;
5914 16000 : move16();
5915 16000 : BREAK;
5916 : }
5917 : }
5918 : }
5919 :
5920 32000 : test();
5921 32000 : test();
5922 32000 : test();
5923 32000 : test();
5924 32000 : test();
5925 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 ) ) ) ) )
5926 : {
5927 5750 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
5928 :
5929 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5930 : {
5931 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5932 : }
5933 :
5934 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,
5935 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ),
5936 : IVAS_ERR_OK ) )
5937 : {
5938 0 : return error;
5939 : }
5940 :
5941 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5942 : {
5943 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5944 : }
5945 : }
5946 : ELSE
5947 : {
5948 : /* apply rotation */
5949 26250 : IF( combinedOrientationEnabled )
5950 : {
5951 10250 : tmpRotBuffer = mcInput->base.inputBuffer;
5952 10250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
5953 10250 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
5954 :
5955 10250 : IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData,
5956 : mcInput->rot_gains_prev_fx,
5957 : mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
5958 : IVAS_ERR_OK ) )
5959 : {
5960 0 : return error;
5961 : }
5962 :
5963 10250 : exp = sub( *outAudio.pq_fact, 1 );
5964 :
5965 10250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
5966 10250 : free( tmpRotBuffer.data_fx );
5967 : }
5968 : ELSE
5969 : {
5970 16000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
5971 : }
5972 : // Porting Crend_process function
5973 : CREND_HANDLE hCrend;
5974 26250 : hCrend = mcInput->crendWrapper->hCrend;
5975 :
5976 : /* call CREND */
5977 26250 : IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate,
5978 : getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
5979 : IVAS_ERR_OK ) )
5980 : {
5981 0 : return error;
5982 : }
5983 26250 : IF( hCrend->hReverb != NULL )
5984 : {
5985 10250 : exp = sub( exp, Q2 );
5986 : }
5987 : }
5988 :
5989 32000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
5990 :
5991 32000 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
5992 : {
5993 0 : return error;
5994 : }
5995 32000 : *outAudio.pq_fact = exp;
5996 32000 : move16();
5997 32000 : pop_wmops();
5998 32000 : return IVAS_ERR_OK;
5999 : }
6000 26008 : static ivas_error renderMcCustomLsToBinauralRoom(
6001 : input_mc *mcInput,
6002 : const AUDIO_CONFIG outConfig,
6003 : IVAS_REND_AudioBuffer outAudio )
6004 : {
6005 : Word16 i;
6006 : Word16 tmp;
6007 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6008 : ivas_error error;
6009 : IVAS_REND_AudioBuffer tmpRotBuffer;
6010 : IVAS_REND_AudioBuffer tmpMcBuffer;
6011 : IVAS_REND_AudioBuffer *tmpBufPtr;
6012 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6013 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6014 : Word8 combinedOrientationEnabled;
6015 : Word16 subframe_idx;
6016 26008 : Word16 exp = *outAudio.pq_fact;
6017 26008 : move16();
6018 26008 : push_wmops( "renderMcCustomLsToBinauralRoom" );
6019 26008 : tmpRotBuffer = outAudio; /* avoid compilation warning */
6020 :
6021 442136 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6022 : {
6023 416128 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6024 : }
6025 :
6026 26008 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6027 26008 : combinedOrientationEnabled = 0;
6028 26008 : move16();
6029 26008 : IF( hCombinedOrientationData != NULL )
6030 : {
6031 46818 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6032 : {
6033 33814 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6034 : {
6035 13004 : combinedOrientationEnabled = 1;
6036 13004 : move16();
6037 13004 : BREAK;
6038 : }
6039 : }
6040 : }
6041 :
6042 : /* apply rotation */
6043 26008 : IF( combinedOrientationEnabled )
6044 : {
6045 13004 : tmpRotBuffer = mcInput->base.inputBuffer;
6046 13004 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
6047 13004 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6048 :
6049 13004 : IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData,
6050 : mcInput->rot_gains_prev_fx,
6051 : mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
6052 : IVAS_ERR_OK ) )
6053 : {
6054 0 : return error;
6055 : }
6056 13004 : exp = sub( *outAudio.pq_fact, Q1 );
6057 : }
6058 :
6059 : /* intermediate conversion to 7_1_4 */
6060 26008 : tmpMcBuffer = mcInput->base.inputBuffer;
6061 :
6062 26008 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
6063 : {
6064 0 : return error;
6065 : }
6066 :
6067 26008 : tmpMcBuffer.config.numChannels = tmp;
6068 26008 : move16();
6069 26008 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
6070 26008 : set32_fx( tmpMcBuffer.data_fx, 0, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
6071 :
6072 26008 : IF( combinedOrientationEnabled )
6073 : {
6074 13004 : tmpBufPtr = &tmpRotBuffer;
6075 : }
6076 : ELSE
6077 : {
6078 13004 : tmpBufPtr = &mcInput->base.inputBuffer;
6079 : }
6080 406136 : FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
6081 : {
6082 380128 : renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer );
6083 : }
6084 26008 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
6085 :
6086 : CREND_HANDLE hCrend;
6087 26008 : hCrend = mcInput->crendWrapper->hCrend;
6088 : /* call CREND */
6089 26008 : IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL,
6090 : p_tmpCrendBuffer, *mcInput->base.ctx.pOutSampleRate, getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
6091 : IVAS_ERR_OK ) )
6092 : {
6093 0 : return error;
6094 : }
6095 26008 : IF( hCrend->hReverb != NULL )
6096 : {
6097 13004 : exp = sub( exp, 2 );
6098 : }
6099 :
6100 26008 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
6101 :
6102 26008 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
6103 : {
6104 0 : return error;
6105 : }
6106 26008 : *outAudio.pq_fact = exp;
6107 26008 : move16();
6108 26008 : IF( combinedOrientationEnabled )
6109 : {
6110 13004 : free( tmpRotBuffer.data_fx );
6111 : }
6112 26008 : free( tmpMcBuffer.data_fx );
6113 :
6114 26008 : pop_wmops();
6115 26008 : return IVAS_ERR_OK;
6116 : }
6117 196617 : static void renderMcToMc(
6118 : const input_mc *mcInput,
6119 : IVAS_REND_AudioBuffer outAudio )
6120 : {
6121 : Word16 i;
6122 : IVAS_REND_AudioBuffer inAudio;
6123 :
6124 196617 : push_wmops( "renderMcToMc" );
6125 196617 : inAudio = mcInput->base.inputBuffer;
6126 :
6127 1507289 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6128 : {
6129 1310672 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
6130 : }
6131 :
6132 196617 : pop_wmops();
6133 196617 : return;
6134 : }
6135 75756 : static void renderMcToSba(
6136 : const input_mc *mcInput,
6137 : IVAS_REND_AudioBuffer outAudio )
6138 : {
6139 : Word16 i;
6140 : IVAS_REND_AudioBuffer inAudio;
6141 :
6142 75756 : push_wmops( "renderMcToSba" );
6143 75756 : inAudio = mcInput->base.inputBuffer;
6144 :
6145 591852 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6146 : {
6147 516096 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
6148 : }
6149 75756 : pop_wmops();
6150 75756 : return;
6151 : }
6152 :
6153 150 : static void renderMcToMasa(
6154 : input_mc *mcInput,
6155 : IVAS_REND_AudioBuffer outAudio )
6156 : {
6157 150 : push_wmops( "renderMcToMasa" );
6158 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6159 150 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
6160 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 );
6161 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6162 :
6163 150 : pop_wmops();
6164 150 : return;
6165 : }
6166 :
6167 359535 : static ivas_error renderInputMc(
6168 : input_mc *mcInput,
6169 : const AUDIO_CONFIG outConfig,
6170 : IVAS_REND_AudioBuffer outAudio )
6171 : {
6172 : ivas_error error;
6173 : IVAS_REND_AudioBuffer inAudio;
6174 359535 : error = IVAS_ERR_OK;
6175 359535 : move32();
6176 :
6177 359535 : inAudio = mcInput->base.inputBuffer;
6178 :
6179 359535 : IF( NE_32( mcInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6180 : {
6181 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" );
6182 : }
6183 359535 : mcInput->base.numNewSamplesPerChannel = 0;
6184 359535 : move32();
6185 359535 : v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
6186 359535 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 ); // reducing the Q by 1 compensating for the v_mult_fixed done
6187 359535 : move16();
6188 : /* set combined orientation subframe info to start info */
6189 359535 : ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
6190 :
6191 359535 : SWITCH( getAudioConfigType( outConfig ) )
6192 : {
6193 196617 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6194 196617 : renderMcToMc( mcInput, outAudio );
6195 196617 : BREAK;
6196 75756 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6197 75756 : renderMcToSba( mcInput, outAudio );
6198 75756 : BREAK;
6199 87012 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6200 : SWITCH( outConfig )
6201 : {
6202 29004 : case IVAS_AUDIO_CONFIG_BINAURAL:
6203 29004 : error = renderMcToBinaural( mcInput, outConfig, outAudio );
6204 29004 : BREAK;
6205 58008 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6206 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6207 58008 : IF( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
6208 : {
6209 26008 : error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
6210 : }
6211 : ELSE
6212 : {
6213 32000 : error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
6214 : }
6215 58008 : BREAK;
6216 0 : default:
6217 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6218 : }
6219 87012 : BREAK;
6220 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6221 150 : renderMcToMasa( mcInput, outAudio );
6222 150 : BREAK;
6223 0 : default:
6224 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6225 : }
6226 359535 : return error;
6227 : }
6228 1126140 : static ivas_error renderActiveInputsMc(
6229 : IVAS_REND_HANDLE hIvasRend,
6230 : IVAS_REND_AudioBuffer outAudio )
6231 : {
6232 : Word16 i;
6233 : input_mc *pCurrentInput;
6234 : ivas_error error;
6235 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMc ); i < RENDERER_MAX_MC_INPUTS; ( ++i, ++pCurrentInput ) )
6236 : {
6237 1126140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6238 : {
6239 : /* Skip inactive inputs */
6240 766605 : CONTINUE;
6241 : }
6242 :
6243 359535 : *outAudio.pq_fact = Q8;
6244 359535 : move16();
6245 359535 : IF( NE_32( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6246 : {
6247 0 : return error;
6248 : }
6249 : }
6250 :
6251 1126140 : return IVAS_ERR_OK;
6252 : }
6253 115801 : static void renderSbaToMc(
6254 : const input_sba *sbaInput,
6255 : IVAS_REND_AudioBuffer outAudio )
6256 : {
6257 : Word16 i;
6258 : IVAS_REND_AudioBuffer inAudio;
6259 :
6260 115801 : push_wmops( "renderSbaToMc" );
6261 115801 : inAudio = sbaInput->base.inputBuffer;
6262 :
6263 1225294 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6264 : {
6265 1109493 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
6266 : }
6267 :
6268 115801 : pop_wmops();
6269 115801 : return;
6270 : }
6271 :
6272 :
6273 45768 : static void renderSbaToSba(
6274 : const input_sba *sbaInput,
6275 : IVAS_REND_AudioBuffer outAudio )
6276 : {
6277 : Word16 i;
6278 : IVAS_REND_AudioBuffer inAudio;
6279 :
6280 45768 : push_wmops( "renderSbaToSba" );
6281 45768 : inAudio = sbaInput->base.inputBuffer;
6282 :
6283 483942 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
6284 : {
6285 438174 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
6286 : }
6287 :
6288 45768 : pop_wmops();
6289 45768 : return;
6290 : }
6291 30012 : static ivas_error renderSbaToBinaural(
6292 : input_sba *sbaInput,
6293 : const AUDIO_CONFIG outConfig,
6294 : IVAS_REND_AudioBuffer outAudio )
6295 : {
6296 : ivas_error error;
6297 : IVAS_REND_AudioBuffer tmpRotBuffer;
6298 : Word16 i;
6299 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6300 : Word8 combinedOrientationEnabled;
6301 : Word16 subframe_idx;
6302 : Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6303 : Word32 *output_fx[MAX_OUTPUT_CHANNELS];
6304 :
6305 30012 : push_wmops( "renderSbaToBinaural" );
6306 : {
6307 :
6308 510204 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6309 : {
6310 480192 : output_fx[i] = output_buffer_fx[i];
6311 : }
6312 :
6313 30012 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
6314 30012 : combinedOrientationEnabled = 0;
6315 30012 : move16();
6316 30012 : IF( hCombinedOrientationData != NULL )
6317 : {
6318 54027 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6319 : {
6320 39021 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6321 : {
6322 15006 : combinedOrientationEnabled = 1;
6323 15006 : move16();
6324 15006 : BREAK;
6325 : }
6326 : }
6327 : }
6328 : /* apply rotation */
6329 30012 : IF( combinedOrientationEnabled )
6330 : {
6331 15006 : tmpRotBuffer = sbaInput->base.inputBuffer;
6332 :
6333 15006 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
6334 : /* copy input for in-place rotation */
6335 :
6336 15006 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
6337 :
6338 15006 : IF( NE_16( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
6339 : sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx, tmpRotBuffer ) ),
6340 : IVAS_ERR_OK ) )
6341 : {
6342 0 : return error;
6343 : }
6344 :
6345 15006 : copyBufferTo2dArray_fx( tmpRotBuffer, output_buffer_fx );
6346 15006 : free( tmpRotBuffer.data_fx );
6347 : }
6348 : ELSE
6349 : {
6350 15006 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, output_buffer_fx );
6351 : }
6352 : // Porting Crend_process function
6353 : CREND_HANDLE hCrend;
6354 30012 : hCrend = sbaInput->crendWrapper->hCrend;
6355 :
6356 : /* call CREND */
6357 30012 : IF( NE_32( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, output_fx, *sbaInput->base.ctx.pOutSampleRate,
6358 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ),
6359 : IVAS_ERR_OK ) )
6360 : {
6361 0 : return error;
6362 : }
6363 30012 : IF( hCrend->hReverb != NULL )
6364 : {
6365 0 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
6366 0 : move16();
6367 : }
6368 30012 : accumulate2dArrayToBuffer_fx( output_buffer_fx, &outAudio );
6369 : }
6370 :
6371 30012 : pop_wmops();
6372 30012 : return IVAS_ERR_OK;
6373 : }
6374 60024 : static ivas_error renderSbaToBinauralRoom(
6375 : input_sba *sbaInput,
6376 : const AUDIO_CONFIG outConfig,
6377 : IVAS_REND_AudioBuffer outAudio )
6378 : {
6379 : Word16 i;
6380 : Word16 tmp;
6381 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6382 : ivas_error error;
6383 : IVAS_REND_AudioBuffer tmpRotBuffer;
6384 : IVAS_REND_AudioBuffer tmpMcBuffer;
6385 : IVAS_REND_AudioBuffer *tmpBufPtr;
6386 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6387 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6388 : Word8 combinedOrientationEnabled;
6389 : Word16 subframe_idx;
6390 :
6391 60024 : tmpRotBuffer = outAudio; /* avoid compilation warning */
6392 60024 : push_wmops( "renderSbaToBinauralRoom" );
6393 : Word16 nchan_out;
6394 : CREND_HANDLE hCrend;
6395 :
6396 60024 : hCrend = sbaInput->crendWrapper->hCrend;
6397 :
6398 60024 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ), IVAS_ERR_OK ) )
6399 : {
6400 0 : return error;
6401 : }
6402 :
6403 1020408 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6404 : {
6405 960384 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6406 : }
6407 :
6408 60024 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
6409 60024 : combinedOrientationEnabled = 0;
6410 60024 : move16();
6411 60024 : IF( hCombinedOrientationData != NULL )
6412 : {
6413 108054 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6414 : {
6415 78042 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6416 : {
6417 30012 : combinedOrientationEnabled = 1;
6418 30012 : move16();
6419 30012 : BREAK;
6420 : }
6421 : }
6422 : }
6423 :
6424 : /* apply rotation */
6425 60024 : IF( combinedOrientationEnabled )
6426 : {
6427 30012 : tmpRotBuffer = sbaInput->base.inputBuffer;
6428 30012 : tmpRotBuffer.data_fx = malloc( imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) * sizeof( Word32 ) );
6429 :
6430 : /* copy input for in-place rotation */
6431 30012 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
6432 :
6433 30012 : IF( NE_32( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
6434 : sbaInput->base.ctx.pCombinedOrientationData,
6435 : sbaInput->rot_gains_prev_fx,
6436 : tmpRotBuffer ) ),
6437 : IVAS_ERR_OK ) )
6438 : {
6439 0 : return error;
6440 : }
6441 : }
6442 :
6443 : /* intermediate rendering to 7_1_4 */
6444 60024 : tmpMcBuffer = sbaInput->base.inputBuffer;
6445 :
6446 60024 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
6447 : {
6448 0 : return error;
6449 : }
6450 :
6451 60024 : tmpMcBuffer.config.numChannels = tmp;
6452 60024 : move16();
6453 60024 : tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) );
6454 60024 : set32_fx( tmpMcBuffer.data_fx, 0, i_mult( tmpMcBuffer.config.numChannels, tmpMcBuffer.config.numSamplesPerChannel ) );
6455 :
6456 60024 : IF( combinedOrientationEnabled )
6457 : {
6458 30012 : tmpBufPtr = &tmpRotBuffer;
6459 : }
6460 : ELSE
6461 : {
6462 30012 : tmpBufPtr = &sbaInput->base.inputBuffer;
6463 : }
6464 640256 : FOR( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
6465 : {
6466 580232 : renderBufferChannel_fx( *tmpBufPtr, i, sbaInput->hoaDecMtx_fx[i], tmpMcBuffer );
6467 : }
6468 60024 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
6469 : // Porting Crend_process function
6470 :
6471 : /* call CREND */
6472 60024 : IF( NE_32( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig,
6473 : NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *sbaInput->base.ctx.pOutSampleRate,
6474 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ),
6475 : IVAS_ERR_OK ) )
6476 : {
6477 0 : return error;
6478 : }
6479 60024 : IF( hCrend->hReverb != NULL )
6480 : {
6481 30012 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 2 );
6482 30012 : move16();
6483 : }
6484 :
6485 60024 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
6486 :
6487 60024 : IF( combinedOrientationEnabled )
6488 : {
6489 30012 : free( tmpRotBuffer.data_fx );
6490 : }
6491 60024 : free( tmpMcBuffer.data_fx );
6492 :
6493 60024 : pop_wmops();
6494 60024 : return IVAS_ERR_OK;
6495 : }
6496 150 : static void renderSbaToMasa(
6497 : input_sba *sbaInput,
6498 : IVAS_REND_AudioBuffer outAudio )
6499 : {
6500 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6501 :
6502 150 : push_wmops( "renderMcToMasa" );
6503 150 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, tmpRendBuffer );
6504 150 : ivas_dirac_ana_fx( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels );
6505 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
6506 :
6507 150 : pop_wmops();
6508 150 : return;
6509 : }
6510 251755 : static ivas_error renderInputSba(
6511 : input_sba *sbaInput,
6512 : const AUDIO_CONFIG outConfig,
6513 : IVAS_REND_AudioBuffer outAudio )
6514 : {
6515 : ivas_error error;
6516 : IVAS_REND_AudioBuffer inAudio;
6517 251755 : error = IVAS_ERR_OK;
6518 251755 : move32();
6519 251755 : inAudio = sbaInput->base.inputBuffer;
6520 :
6521 251755 : IF( NE_32( sbaInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6522 : {
6523 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" );
6524 : }
6525 251755 : sbaInput->base.numNewSamplesPerChannel = 0;
6526 251755 : move32();
6527 251755 : *outAudio.pq_fact = outAudio.q_factor;
6528 251755 : move16();
6529 : /* Apply input gain to new audio */
6530 251755 : v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
6531 251755 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
6532 251755 : move16();
6533 :
6534 : /* set combined orientation subframe info to start info */
6535 251755 : ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
6536 :
6537 251755 : SWITCH( getAudioConfigType( outConfig ) )
6538 : {
6539 115801 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6540 115801 : renderSbaToMc( sbaInput, outAudio );
6541 115801 : BREAK;
6542 45768 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6543 45768 : renderSbaToSba( sbaInput, outAudio );
6544 45768 : BREAK;
6545 90036 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6546 : SWITCH( outConfig )
6547 : {
6548 30012 : case IVAS_AUDIO_CONFIG_BINAURAL:
6549 30012 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
6550 30012 : BREAK;
6551 60024 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6552 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6553 60024 : error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
6554 60024 : BREAK;
6555 0 : default:
6556 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6557 : }
6558 90036 : BREAK;
6559 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6560 150 : renderSbaToMasa( sbaInput, outAudio );
6561 150 : BREAK;
6562 0 : default:
6563 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6564 : }
6565 :
6566 251755 : return error;
6567 : }
6568 1126140 : static ivas_error renderActiveInputsSba(
6569 : IVAS_REND_HANDLE hIvasRend,
6570 : IVAS_REND_AudioBuffer outAudio )
6571 : {
6572 : Word16 i;
6573 : input_sba *pCurrentInput;
6574 : ivas_error error;
6575 :
6576 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsSba ); i < RENDERER_MAX_SBA_INPUTS; ( ++i, ++pCurrentInput ) )
6577 : {
6578 1126140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6579 : {
6580 : /* Skip inactive inputs */
6581 874385 : CONTINUE;
6582 : }
6583 251755 : *outAudio.pq_fact = Q8;
6584 251755 : move16();
6585 251755 : IF( NE_32( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6586 : {
6587 0 : return error;
6588 : }
6589 : }
6590 1126140 : return IVAS_ERR_OK;
6591 : }
6592 :
6593 :
6594 17250 : static void copyMasaMetadataToDiracRenderer_fx(
6595 : MASA_METADATA_FRAME *meta,
6596 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
6597 : const Word16 maxBin )
6598 : {
6599 : Word16 band, sf, bin;
6600 : Word16 meta_write_index;
6601 :
6602 17250 : hSpatParamRendCom->numParametricDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
6603 17250 : hSpatParamRendCom->numSimultaneousDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
6604 17250 : move16();
6605 17250 : move16();
6606 :
6607 86250 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
6608 : {
6609 69000 : meta_write_index = add( hSpatParamRendCom->dirac_bs_md_write_idx, sf ) % hSpatParamRendCom->dirac_md_buffer_length;
6610 :
6611 1725000 : FOR( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
6612 : {
6613 5796000 : FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
6614 : {
6615 4140000 : hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6616 4140000 : move16();
6617 4140000 : hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6618 4140000 : move16();
6619 4140000 : hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band];
6620 4140000 : move32();
6621 4140000 : hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( ONE_IN_Q30, meta->directional_meta[0].energy_ratio_fx[sf][band] );
6622 4140000 : move32();
6623 4140000 : hSpatParamRendCom->spreadCoherence_fx[meta_write_index][bin] = meta->directional_meta[0].spread_coherence_fx[sf][band];
6624 4140000 : move16();
6625 4140000 : hSpatParamRendCom->surroundingCoherence_fx[meta_write_index][bin] = meta->common_meta.surround_coherence_fx[sf][band];
6626 4140000 : move16();
6627 :
6628 4140000 : IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) )
6629 : {
6630 2160000 : hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6631 2160000 : move16();
6632 2160000 : hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
6633 2160000 : move16();
6634 2160000 : hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band];
6635 2160000 : move32();
6636 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] );
6637 2160000 : move32();
6638 2160000 : hSpatParamRendCom->spreadCoherence2_fx[meta_write_index][bin] = meta->directional_meta[1].spread_coherence_fx[sf][band];
6639 2160000 : move16();
6640 : }
6641 : }
6642 : }
6643 : }
6644 :
6645 17250 : hSpatParamRendCom->dirac_bs_md_write_idx = add( hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
6646 17250 : move16();
6647 :
6648 17250 : return;
6649 : }
6650 :
6651 :
6652 150 : static void renderMasaToMasa(
6653 : input_masa *masaInput,
6654 : IVAS_REND_AudioBuffer outAudio )
6655 : {
6656 : Word16 sf, band, dir, numDirs;
6657 : Word32 ratioSum_fx; /* Q30 */
6658 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
6659 : MASA_METADATA_FRAME *inMeta;
6660 : Word32 tmpBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6661 : Word16 ts, i, j, l_ts;
6662 : Word32 Chan_RealBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
6663 : Word32 Chan_ImagBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
6664 : Word16 band_m_idx, block_m_idx;
6665 : Word16 mrange[2];
6666 : Word16 brange[2];
6667 : Word16 numAnalysisChannels;
6668 150 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_fx );
6669 150 : Word16 q_cldfb = *outAudio.pq_fact;
6670 150 : Word16 q_cldfb_out = *outAudio.pq_fact;
6671 150 : Word16 scale_factor = 31;
6672 : Word16 scale_fac_arr[MASA_MAX_TRANSPORT_CHANNELS];
6673 150 : move16();
6674 150 : move16();
6675 150 : move16();
6676 : /* Calculate energy */
6677 : // l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
6678 150 : l_ts = shr( masaInput->base.inputBuffer.config.numSamplesPerChannel, 4 );
6679 150 : numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
6680 150 : move16();
6681 : /* do processing over all CLDFB time slots */
6682 750 : FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
6683 : {
6684 600 : mrange[0] = DirAC_block_grouping[block_m_idx];
6685 600 : mrange[1] = DirAC_block_grouping[block_m_idx + 1];
6686 600 : move16();
6687 600 : move16();
6688 :
6689 600 : set_zero_fx( masaInput->hMasaPrerend->energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
6690 600 : set16_fx( masaInput->hMasaPrerend->energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
6691 :
6692 3000 : FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
6693 : {
6694 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
6695 : {
6696 4800 : scale_factor = 31;
6697 4800 : move16();
6698 4800 : masaInput->hMasaPrerend->cldfbAnaEnc[i]->Q_cldfb_state = q_cldfb;
6699 4800 : q_cldfb_out = q_cldfb;
6700 4800 : move16();
6701 4800 : move16();
6702 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 );
6703 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 ) ) );
6704 4800 : scale_factor = sub( scale_factor, 1 );
6705 4800 : scale_sig32( Chan_RealBuffer_fx[i], CLDFB_NO_CHANNELS_MAX, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
6706 4800 : scale_sig32( Chan_ImagBuffer_fx[i], CLDFB_NO_CHANNELS_MAX, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
6707 4800 : scale_fac_arr[i] = scale_factor;
6708 4800 : move16();
6709 : }
6710 :
6711 2400 : scale_factor = MAX_16;
6712 2400 : move16();
6713 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
6714 : {
6715 4800 : scale_factor = s_min( scale_factor, scale_fac_arr[i] );
6716 : }
6717 :
6718 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
6719 : {
6720 4800 : IF( NE_16( scale_factor, scale_fac_arr[i] ) )
6721 : {
6722 48861 : FOR( j = 0; j < CLDFB_NO_CHANNELS_MAX; j++ )
6723 : {
6724 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) */
6725 48060 : move32();
6726 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) */
6727 48060 : move32();
6728 : }
6729 : }
6730 : }
6731 :
6732 2400 : Word16 q_add = sub( 31, add( scale_factor, q_cldfb_out ) );
6733 : /* Compute channel energy for metadata processing */
6734 60000 : FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
6735 : {
6736 57600 : brange[0] = MASA_band_grouping_24[band_m_idx];
6737 57600 : move16();
6738 57600 : brange[1] = MASA_band_grouping_24[band_m_idx + 1];
6739 57600 : move16();
6740 201600 : FOR( j = brange[0]; j < brange[1]; j++ )
6741 : {
6742 432000 : FOR( i = 0; i < numAnalysisChannels; i++ )
6743 : {
6744 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 */
6745 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], masaInput->hMasaPrerend->energy_e[block_m_idx][band_m_idx], temp, shl( q_add, 1 ), &masaInput->hMasaPrerend->energy_e[block_m_idx][band_m_idx] );
6746 288000 : move32();
6747 : }
6748 : }
6749 : }
6750 : }
6751 : }
6752 :
6753 : /* Copy audio channels if mismatch in number of transports */
6754 150 : test();
6755 150 : test();
6756 150 : IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 1 ) && EQ_16( outAudio.config.numChannels, 2 ) )
6757 : {
6758 0 : Copy32( tmpBuffer_fx[0], tmpBuffer_fx[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
6759 : }
6760 150 : ELSE IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 2 ) && EQ_16( outAudio.config.numChannels, 1 ) )
6761 : {
6762 : // v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
6763 0 : v_add_fixed_no_hdrm( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
6764 : }
6765 :
6766 : /* Copy metadata */
6767 150 : outMeta = masaInput->hMasaPrerend->hMasaOut;
6768 150 : inMeta = &masaInput->masaMetadata;
6769 150 : numDirs = add( inMeta->descriptive_meta.numberOfDirections, 1 );
6770 :
6771 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
6772 : {
6773 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
6774 : {
6775 : /* Remainder is always set to zero and energy removal is compensated in following steps
6776 : * to other ratios. */
6777 : // inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
6778 14400 : inMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0;
6779 14400 : move32();
6780 14400 : ratioSum_fx = 0;
6781 14400 : move32();
6782 43200 : FOR( dir = 0; dir < numDirs; dir++ )
6783 : {
6784 28800 : ratioSum_fx = L_add( ratioSum_fx, inMeta->directional_meta[dir].energy_ratio_fx[sf][band] );
6785 : }
6786 14400 : ratioSum_fx = L_add( ratioSum_fx, inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
6787 :
6788 14400 : IF( ratioSum_fx == 0 )
6789 : {
6790 0 : FOR( dir = 0; dir < numDirs; dir++ )
6791 : {
6792 0 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0;
6793 0 : move32();
6794 : }
6795 0 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30;
6796 0 : move32();
6797 : }
6798 14400 : ELSE IF( NE_32( ratioSum_fx, ONE_IN_Q30 ) )
6799 : {
6800 14400 : Word16 tmp_e = 0;
6801 14400 : move16();
6802 14400 : Word32 tmp = 0;
6803 14400 : move32();
6804 43200 : FOR( dir = 0; dir < numDirs; dir++ )
6805 : {
6806 28800 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
6807 28800 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
6808 28800 : move32();
6809 : }
6810 14400 : tmp_e = 0;
6811 14400 : move16();
6812 14400 : tmp = 0;
6813 14400 : move32();
6814 14400 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
6815 14400 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
6816 14400 : move32();
6817 : }
6818 : }
6819 : }
6820 :
6821 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
6822 : {
6823 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
6824 : {
6825 14400 : outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
6826 14400 : move16();
6827 43200 : FOR( dir = 0; dir < numDirs; dir++ )
6828 : {
6829 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 );
6830 28800 : outMeta->directToTotalRatio[dir][sf][band] = (UWord8) L_shr( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], Q22 );
6831 28800 : outMeta->diffuseToTotalRatio[sf][band] = (UWord8) sub( outMeta->diffuseToTotalRatio[sf][band], outMeta->directToTotalRatio[dir][sf][band] );
6832 28800 : outMeta->spreadCoherence[dir][sf][band] = (UWord8) shr( inMeta->directional_meta[dir].spread_coherence_fx[sf][band], Q7 );
6833 :
6834 28800 : move16();
6835 28800 : move16();
6836 28800 : move16();
6837 28800 : move16();
6838 : }
6839 14400 : outMeta->surroundCoherence[sf][band] = (UWord8) shr( inMeta->common_meta.surround_coherence_fx[sf][band], Q7 );
6840 14400 : move16();
6841 : }
6842 : }
6843 :
6844 150 : copy_masa_descriptive_meta_fx( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
6845 :
6846 150 : accumulate2dArrayToBuffer_fx( tmpBuffer_fx, &outAudio );
6847 :
6848 150 : return;
6849 : }
6850 :
6851 18150 : static ivas_error renderInputMasa(
6852 : input_masa *masaInput,
6853 : const AUDIO_CONFIG outConfig,
6854 : IVAS_REND_AudioBuffer outAudio )
6855 : {
6856 : IVAS_REND_AudioBuffer inAudio;
6857 : Word16 ch;
6858 : Word16 maxBin;
6859 : Word32 *tmpBuffer_fx[MAX_OUTPUT_CHANNELS];
6860 : Word32 tmpBuffer_buff_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6861 :
6862 18150 : IF( !masaInput->metadataHasBeenFed )
6863 : {
6864 0 : return IVAS_ERR_MISSING_METADATA;
6865 : }
6866 :
6867 18150 : inAudio = masaInput->base.inputBuffer;
6868 18150 : IF( NE_32( masaInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6869 : {
6870 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" );
6871 : }
6872 18150 : masaInput->base.numNewSamplesPerChannel = 0;
6873 18150 : move32();
6874 :
6875 18150 : *outAudio.pq_fact = outAudio.q_factor;
6876 18150 : move16();
6877 : /* Apply input gain to new audio */
6878 18150 : v_multc_fixed( inAudio.data_fx, masaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
6879 18150 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
6880 18150 : move16();
6881 :
6882 18150 : maxBin = extract_l( Mpy_32_32( *masaInput->base.ctx.pOutSampleRate, INV_CLDFB_BANDWIDTH_Q31 ) ); /* Q0 */
6883 :
6884 : /* set combined orientation subframe info to start info */
6885 18150 : ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
6886 :
6887 18150 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
6888 : {
6889 : /* MASA prerendering path for MASA -> MASA */
6890 150 : renderMasaToMasa( masaInput, outAudio );
6891 : }
6892 : ELSE
6893 : {
6894 : /* MASA external renderer -> other formats */
6895 : Word16 num_subframes, exp;
6896 306000 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
6897 : {
6898 288000 : tmpBuffer_fx[ch] = tmpBuffer_buff_fx[ch];
6899 : }
6900 18000 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_buff_fx );
6901 :
6902 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 );
6903 18000 : num_subframes = shr( num_subframes, sub( 15, exp ) ); /* Q0 */
6904 :
6905 18000 : SWITCH( masaInput->hMasaExtRend->renderer_type )
6906 : {
6907 12750 : case RENDERER_DIRAC:
6908 :
6909 12750 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
6910 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 1 );
6911 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
6912 : {
6913 110250 : masaInput->hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state = Q11;
6914 110250 : move16();
6915 : }
6916 216750 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
6917 : {
6918 204000 : Scale_sig32( tmpBuffer_buff_fx[ch], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6919 : }
6920 :
6921 12750 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6922 :
6923 12750 : ivas_masa_ext_dirac_render_fx( masaInput->hMasaExtRend, tmpBuffer_fx, num_subframes );
6924 :
6925 12750 : *outAudio.pq_fact = Q11;
6926 12750 : move16();
6927 :
6928 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
6929 : {
6930 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 */
6931 110250 : masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
6932 110250 : move16();
6933 : }
6934 :
6935 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 0 );
6936 12750 : BREAK;
6937 4500 : case RENDERER_STEREO_PARAMETRIC:
6938 : case RENDERER_BINAURAL_PARAMETRIC:
6939 : case RENDERER_BINAURAL_PARAMETRIC_ROOM:
6940 :
6941 4500 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
6942 :
6943 4500 : Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6944 4500 : Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
6945 :
6946 4500 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
6947 :
6948 4500 : ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes );
6949 4500 : *outAudio.pq_fact = Q11;
6950 4500 : move16();
6951 4500 : BREAK;
6952 750 : case RENDERER_DISABLE:
6953 750 : BREAK; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
6954 0 : default:
6955 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
6956 : }
6957 :
6958 18000 : accumulate2dArrayToBuffer_fx( tmpBuffer_buff_fx, &outAudio );
6959 : }
6960 :
6961 18150 : return IVAS_ERR_OK;
6962 : }
6963 1126140 : static ivas_error renderActiveInputsMasa(
6964 : IVAS_REND_HANDLE hIvasRend,
6965 : IVAS_REND_AudioBuffer outAudio )
6966 : {
6967 : Word16 i;
6968 : input_masa *pCurrentInput;
6969 : ivas_error error;
6970 :
6971 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMasa ); i < RENDERER_MAX_MASA_INPUTS; ( ++i, ++pCurrentInput ) )
6972 : {
6973 1126140 : IF( EQ_16( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6974 : {
6975 : /* Skip inactive inputs */
6976 1107990 : CONTINUE;
6977 : }
6978 :
6979 18150 : *outAudio.pq_fact = Q8;
6980 18150 : move16();
6981 :
6982 18150 : IF( NE_32( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6983 : {
6984 0 : return error;
6985 : }
6986 : }
6987 :
6988 1126140 : return IVAS_ERR_OK;
6989 : }
6990 :
6991 : /*---------------------------------------------------------------------*
6992 : * IVAS_REND_GetMasaMetadata( )
6993 : *
6994 : * Get metadata of the estimated MASA frame
6995 : *---------------------------------------------------------------------*/
6996 :
6997 0 : ivas_error IVAS_REND_GetMasaMetadata(
6998 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
6999 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to analyzed MASA metadata */
7000 : const IVAS_REND_AudioConfigType inputType /* i : Input type */
7001 : )
7002 : {
7003 0 : IF( hIvasRend == NULL )
7004 : {
7005 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7006 : }
7007 :
7008 : /* Get the metadata handle */
7009 0 : IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
7010 : {
7011 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7012 : }
7013 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
7014 : {
7015 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7016 : }
7017 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
7018 : {
7019 0 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7020 : }
7021 : ELSE
7022 : {
7023 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7024 : }
7025 :
7026 0 : return IVAS_ERR_OK;
7027 : }
7028 :
7029 :
7030 : /*---------------------------------------------------------------------*
7031 : * IVAS_REND_MergeMasaMetadata( )
7032 : *
7033 : * Merge MASA metadata from two formats
7034 : *---------------------------------------------------------------------*/
7035 :
7036 450 : ivas_error IVAS_REND_MergeMasaMetadata(
7037 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7038 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to merged metadata */
7039 : const IVAS_REND_AudioConfigType inputType1, /* i : Input type 1 */
7040 : const IVAS_REND_AudioConfigType inputType2 /* i : Input type 2 */
7041 : )
7042 : {
7043 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
7044 : Word32( *inEne1_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7045 : Word32( *inEne2_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7046 : Word16( *inEne1_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7047 : Word16( *inEne2_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7048 :
7049 450 : IF( hIvasRend == NULL )
7050 : {
7051 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7052 : }
7053 :
7054 : /* Input1 metadata and energy */
7055 450 : IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
7056 : {
7057 :
7058 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7059 0 : inEne1_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
7060 0 : inEne1_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
7061 : }
7062 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
7063 : {
7064 :
7065 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7066 0 : inEne1_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
7067 0 : inEne1_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
7068 : }
7069 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
7070 : {
7071 :
7072 450 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7073 450 : inEne1_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
7074 450 : inEne1_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
7075 : }
7076 0 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
7077 : {
7078 :
7079 0 : *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7080 0 : inEne1_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
7081 0 : inEne1_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
7082 : }
7083 : ELSE
7084 : {
7085 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7086 : }
7087 :
7088 : /* Input2 metadata and energy */
7089 450 : IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
7090 : {
7091 150 : inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7092 150 : inEne2_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
7093 150 : inEne2_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
7094 : }
7095 300 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
7096 : {
7097 150 : inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7098 150 : inEne2_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
7099 150 : inEne2_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
7100 : }
7101 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
7102 : {
7103 0 : inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
7104 0 : inEne2_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
7105 0 : inEne2_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
7106 : }
7107 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
7108 : {
7109 :
7110 150 : inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7111 150 : inEne2_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
7112 150 : inEne2_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
7113 : }
7114 : ELSE
7115 : {
7116 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7117 : }
7118 :
7119 : /* Merge metadata */
7120 450 : ivas_prerend_merge_masa_metadata_fx( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1_fx, *inEne1_e, inMeta2, inputType2, *inEne2_fx, *inEne2_e );
7121 :
7122 :
7123 450 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
7124 : {
7125 0 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 0u;
7126 0 : move16();
7127 : }
7128 : ELSE
7129 : {
7130 450 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 1u;
7131 450 : move16();
7132 : }
7133 :
7134 450 : return IVAS_ERR_OK;
7135 : }
7136 :
7137 :
7138 : /*---------------------------------------------------------------------*
7139 : * IVAS_REND_SetTotalNumberOfObjects( )
7140 : *
7141 : * Set the total number of objects to the first object data
7142 : *---------------------------------------------------------------------*/
7143 :
7144 182 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
7145 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7146 : const UWord16 total_num_objects /* i : total number of objects */
7147 : )
7148 : {
7149 182 : IF( hIvasRend == NULL )
7150 : {
7151 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7152 : }
7153 :
7154 182 : hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
7155 182 : move16();
7156 :
7157 182 : return IVAS_ERR_OK;
7158 : }
7159 :
7160 :
7161 : /*---------------------------------------------------------------------*
7162 : * IVAS_REND_SetIsmMetadataDelay( )
7163 : *
7164 : * Set the Metadata Delay in ms in order to sync with audio delay
7165 : *---------------------------------------------------------------------*/
7166 182 : ivas_error IVAS_REND_SetIsmMetadataDelay(
7167 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7168 : const Word32 sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */
7169 : )
7170 : {
7171 : Word16 i;
7172 :
7173 182 : IF( hIvasRend == NULL )
7174 : {
7175 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7176 : }
7177 910 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
7178 : {
7179 728 : hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay;
7180 728 : move32();
7181 : }
7182 :
7183 182 : return IVAS_ERR_OK;
7184 : }
7185 :
7186 : /*-------------------------------------------------------------------*
7187 : * getSamplesInternal()
7188 : *
7189 : *
7190 : *-------------------------------------------------------------------*/
7191 :
7192 1126140 : static ivas_error getSamplesInternal(
7193 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7194 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7195 : )
7196 : {
7197 : ivas_error error;
7198 : Word16 numOutChannels;
7199 : /* Validate function arguments */
7200 1126140 : test();
7201 1126140 : IF( hIvasRend == NULL || outAudio.data_fx == NULL )
7202 : {
7203 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7204 : }
7205 :
7206 1126140 : test();
7207 1126140 : IF( outAudio.config.numSamplesPerChannel <= 0 || LT_16( MAX_BUFFER_LENGTH_PER_CHANNEL, outAudio.config.numSamplesPerChannel ) )
7208 : {
7209 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
7210 : }
7211 :
7212 1126140 : test();
7213 1126140 : IF( outAudio.config.numChannels <= 0 || LT_16( MAX_OUTPUT_CHANNELS, outAudio.config.numChannels ) )
7214 : {
7215 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7216 : }
7217 :
7218 1126140 : test();
7219 1126140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
7220 : NE_32( L_mult0( outAudio.config.numSamplesPerChannel, 1000 ), imult3216( hIvasRend->sampleRateOut, i_mult( hIvasRend->num_subframes, BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ) )
7221 : {
7222 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
7223 : }
7224 :
7225 : /* Check that there is allowed configuration for MASA format output */
7226 1126140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
7227 : {
7228 : Word16 i;
7229 150 : Word16 numMasaInputs = 0;
7230 150 : move16();
7231 150 : Word16 numOtherInputs = 0;
7232 150 : move16();
7233 :
7234 300 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
7235 : {
7236 : // numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7237 :
7238 150 : IF( EQ_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7239 : {
7240 0 : numMasaInputs = add( numMasaInputs, 0 );
7241 : }
7242 : ELSE
7243 : {
7244 150 : numMasaInputs = add( numMasaInputs, 1 );
7245 : }
7246 : }
7247 :
7248 300 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
7249 : {
7250 : // numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7251 :
7252 150 : IF( EQ_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7253 : {
7254 0 : numOtherInputs = add( numOtherInputs, 0 );
7255 : }
7256 : ELSE
7257 : {
7258 150 : numOtherInputs = add( numOtherInputs, 1 );
7259 : }
7260 : }
7261 :
7262 300 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
7263 : {
7264 : // numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7265 :
7266 150 : IF( EQ_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7267 : {
7268 0 : numOtherInputs = add( numOtherInputs, 0 );
7269 : }
7270 : ELSE
7271 : {
7272 150 : numOtherInputs = add( numOtherInputs, 1 );
7273 : }
7274 : }
7275 :
7276 : /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
7277 : // numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7278 150 : IF( EQ_32( hIvasRend->inputsIsm[0].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7279 : {
7280 0 : numOtherInputs = add( numOtherInputs, 0 );
7281 : }
7282 : ELSE
7283 : {
7284 150 : numOtherInputs = add( numOtherInputs, 1 );
7285 : }
7286 :
7287 150 : test();
7288 150 : IF( numMasaInputs == 0 || numOtherInputs == 0 )
7289 : {
7290 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
7291 : }
7292 : }
7293 :
7294 1126140 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
7295 : {
7296 0 : return error;
7297 : }
7298 :
7299 1126140 : IF( NE_16( numOutChannels, outAudio.config.numChannels ) )
7300 : {
7301 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7302 : }
7303 :
7304 : /* Clear original output buffer */
7305 1126140 : set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) );
7306 :
7307 1126140 : IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7308 : {
7309 0 : return error;
7310 : }
7311 1126140 : IF( NE_32( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7312 : {
7313 0 : return error;
7314 : }
7315 1126140 : IF( NE_32( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7316 : {
7317 0 : return error;
7318 : }
7319 1126140 : IF( NE_32( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
7320 : {
7321 0 : return error;
7322 : }
7323 :
7324 1126140 : test();
7325 1126140 : test();
7326 :
7327 1126140 : Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact );
7328 1126140 : limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact );
7329 :
7330 : /* update global cominbed orientation start index */
7331 1126140 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
7332 :
7333 1126140 : return IVAS_ERR_OK;
7334 : }
7335 :
7336 : /*-------------------------------------------------------------------*
7337 : * IVAS_REND_GetSamples()
7338 : *
7339 : *
7340 : *-------------------------------------------------------------------*/
7341 :
7342 1126140 : ivas_error IVAS_REND_GetSamples(
7343 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7344 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7345 : )
7346 : {
7347 :
7348 1126140 : return getSamplesInternal( hIvasRend, outAudio );
7349 : }
7350 :
7351 :
7352 : /*-------------------------------------------------------------------*
7353 : * IVAS_REND_Close()
7354 : *
7355 : *
7356 : *-------------------------------------------------------------------*/
7357 :
7358 :
7359 666 : void IVAS_REND_Close(
7360 : IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
7361 : )
7362 : {
7363 : UWord16 i;
7364 : IVAS_REND_HANDLE hIvasRend;
7365 :
7366 : /* Validate function arguments */
7367 666 : test();
7368 666 : IF( phIvasRend == NULL || *phIvasRend == NULL )
7369 : {
7370 0 : return;
7371 : }
7372 666 : hIvasRend = *phIvasRend;
7373 :
7374 666 : IF( hIvasRend->efapOutWrapper.hEfap != NULL )
7375 : {
7376 471 : efap_free_data_fx( &hIvasRend->efapOutWrapper.hEfap );
7377 : }
7378 :
7379 : /* clear inputs */
7380 3330 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
7381 : {
7382 2664 : clearInputIsm( &hIvasRend->inputsIsm[i] );
7383 : }
7384 1332 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
7385 : {
7386 666 : clearInputMc( &hIvasRend->inputsMc[i] );
7387 : }
7388 1332 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
7389 : {
7390 666 : clearInputSba( &hIvasRend->inputsSba[i] );
7391 : }
7392 1332 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
7393 : {
7394 666 : clearInputMasa( &hIvasRend->inputsMasa[i] );
7395 : }
7396 :
7397 : /* clear Config. Renderer */
7398 666 : ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
7399 :
7400 666 : ivas_limiter_close_fx( &hIvasRend->hLimiter );
7401 :
7402 :
7403 666 : closeHeadRotation( hIvasRend );
7404 :
7405 666 : ivas_external_orientation_close_fx( &hIvasRend->hExternalOrientationData );
7406 666 : ivas_combined_orientation_close_fx( &hIvasRend->hCombinedOrientationData );
7407 :
7408 666 : free( hIvasRend );
7409 666 : *phIvasRend = NULL;
7410 :
7411 666 : return;
7412 : }
7413 :
7414 34 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
7415 : input_masa *inputMasa )
7416 : {
7417 : Word16 nchan_out_woLFE;
7418 : Word16 nchan_transport;
7419 : UWord16 i, j, k;
7420 : Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
7421 : Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
7422 : Word32 output_Fs;
7423 : ivas_error error;
7424 : DIRAC_REND_HANDLE hDirACRend;
7425 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
7426 :
7427 34 : error = IVAS_ERR_OK;
7428 34 : move32();
7429 :
7430 34 : hDirACRend = NULL;
7431 34 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
7432 34 : move32();
7433 :
7434 34 : hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
7435 :
7436 : /*-----------------------------------------------------------------*
7437 : * prepare library opening
7438 : *-----------------------------------------------------------------*/
7439 :
7440 34 : IF( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
7441 : {
7442 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
7443 : }
7444 :
7445 34 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
7446 : {
7447 18 : nchan_transport = 2;
7448 18 : move16();
7449 : }
7450 : ELSE
7451 : {
7452 16 : nchan_transport = 1;
7453 16 : move16();
7454 : }
7455 :
7456 : /*-----------------------------------------------------------------*
7457 : * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
7458 : *-----------------------------------------------------------------*/
7459 :
7460 34 : ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
7461 :
7462 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
7463 : {
7464 : /* Copy from ivas_ls_custom_setup */
7465 0 : hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
7466 0 : move16();
7467 0 : hDirACRend->hOutSetup.ls_azimuth_fx = inputMasa->base.ctx.pCustomLsOut->ls_azimuth_fx;
7468 0 : hDirACRend->hOutSetup.ls_elevation_fx = inputMasa->base.ctx.pCustomLsOut->ls_elevation_fx;
7469 :
7470 0 : hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
7471 0 : move16();
7472 0 : hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
7473 0 : move16();
7474 :
7475 0 : hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
7476 0 : move16();
7477 0 : hDirACRend->hOutSetup.is_planar_setup = (Word8) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
7478 0 : move16();
7479 : }
7480 :
7481 34 : nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
7482 34 : move16();
7483 :
7484 34 : test();
7485 34 : IF( hDirACRend->hOutSetup.ls_azimuth_fx != NULL && hDirACRend->hOutSetup.ls_elevation_fx != NULL )
7486 : {
7487 20 : Copy32( hDirACRend->hOutSetup.ls_azimuth_fx, ls_azimuth_fx, nchan_out_woLFE );
7488 20 : Copy32( hDirACRend->hOutSetup.ls_elevation_fx, ls_elevation_fx, nchan_out_woLFE );
7489 : }
7490 :
7491 34 : IF( EQ_16( hDirACRend->hOutSetup.ambisonics_order, -1 ) )
7492 : {
7493 22 : hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
7494 22 : move16();
7495 22 : test();
7496 22 : if ( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_STEREO ) )
7497 : {
7498 2 : hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
7499 2 : move16();
7500 : }
7501 : }
7502 12 : ELSE IF( GE_16( hDirACRend->hOutSetup.ambisonics_order, SBA_FOA_ORDER ) )
7503 : {
7504 12 : Copy32( ls_azimuth_4d4_fx, ls_azimuth_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
7505 12 : Copy32( ls_elevation_4d4_fx, ls_elevation_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
7506 : }
7507 :
7508 : /*-----------------------------------------------------------------*
7509 : * set input parameters
7510 : *-----------------------------------------------------------------*/
7511 :
7512 34 : test();
7513 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
7514 : {
7515 2 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
7516 2 : move32();
7517 2 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
7518 2 : move32();
7519 2 : nchan_out_woLFE = 1;
7520 2 : move16();
7521 : }
7522 32 : ELSE IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
7523 : {
7524 20 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
7525 20 : hDirACRend->panningConf = DIRAC_PANNING_VBAP;
7526 20 : move32();
7527 20 : move32();
7528 : }
7529 12 : ELSE IF( !hDirACRend->hOutSetup.is_loudspeaker_setup && GT_16( nchan_transport, 1 ) )
7530 : {
7531 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
7532 6 : move32();
7533 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
7534 6 : move32();
7535 : }
7536 : ELSE
7537 : {
7538 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
7539 6 : move32();
7540 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
7541 6 : move32();
7542 : }
7543 :
7544 34 : IF( ( hDirACRend->frequency_axis_fx = (Word16 *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( Word16 ) ) ) == NULL )
7545 : {
7546 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7547 : }
7548 34 : set16_fx( hDirACRend->frequency_axis_fx, 0, hSpatParamRendCom->num_freq_bands );
7549 34 : ivas_dirac_dec_get_frequency_axis_fx( hDirACRend->frequency_axis_fx, output_Fs, hSpatParamRendCom->num_freq_bands );
7550 :
7551 :
7552 34 : test();
7553 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) && EQ_16( nchan_transport, 2 ) )
7554 : {
7555 8 : IF( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
7556 : {
7557 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7558 : }
7559 8 : ivas_masa_init_stereotype_detection_fx( hDirACRend->masa_stereo_type_detect );
7560 : }
7561 : ELSE
7562 : {
7563 26 : hDirACRend->masa_stereo_type_detect = NULL;
7564 : }
7565 :
7566 34 : hSpatParamRendCom->numIsmDirections = 0;
7567 34 : move16();
7568 :
7569 : /*-----------------------------------------------------------------*
7570 : * (re)configure sub-modules
7571 : *-----------------------------------------------------------------*/
7572 :
7573 : /* prototype signal computation */
7574 : /* allocate output setup related arrays */
7575 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
7576 : {
7577 : /* Directional and diffuses components in output LS format */
7578 20 : hDirACRend->num_outputs_diff = nchan_out_woLFE;
7579 20 : move16();
7580 20 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
7581 20 : move16();
7582 : }
7583 14 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7584 : {
7585 : /* Directional and diffuses components in SHD */
7586 : /* Diffuseness components up to 1st order */
7587 6 : hDirACRend->num_outputs_diff = imult1616( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ), ( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ) ) );
7588 6 : hDirACRend->num_outputs_dir = ivas_sba_get_nchan_fx( hDirACRend->hOutSetup.ambisonics_order, 0 );
7589 : }
7590 8 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
7591 : {
7592 6 : hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
7593 6 : move16();
7594 6 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
7595 6 : move16();
7596 : }
7597 2 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
7598 : {
7599 2 : hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
7600 2 : move16();
7601 2 : hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
7602 2 : move16();
7603 : }
7604 : ELSE
7605 : {
7606 0 : assert( 0 && "DirAC: not existing synthesis methods!" );
7607 : }
7608 :
7609 34 : IF( ( hDirACRend->proto_index_dir = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
7610 : {
7611 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7612 : }
7613 :
7614 34 : IF( ( hDirACRend->proto_index_diff = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_diff ) ) == NULL )
7615 : {
7616 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7617 : }
7618 :
7619 34 : set16_fx( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
7620 34 : set16_fx( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
7621 :
7622 34 : hDirACRend->sba_map_tc = sba_map_tc;
7623 :
7624 34 : IF( EQ_16( nchan_transport, 1 ) )
7625 : {
7626 16 : hDirACRend->num_protos_ambi = 1;
7627 16 : move16();
7628 16 : hDirACRend->num_protos_dir = 1;
7629 16 : move16();
7630 16 : hDirACRend->num_protos_diff = 1;
7631 16 : move16();
7632 : }
7633 18 : ELSE IF( EQ_16( nchan_transport, 2 ) )
7634 : {
7635 18 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7636 : {
7637 0 : hDirACRend->num_protos_ambi = 2;
7638 0 : move16();
7639 0 : hDirACRend->num_protos_diff = 1;
7640 0 : move16();
7641 0 : hDirACRend->num_protos_dir = 2;
7642 0 : move16();
7643 0 : hDirACRend->proto_index_dir[1] = 1;
7644 0 : move16();
7645 : }
7646 18 : ELSE IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
7647 : {
7648 : /* Following the foa rendering for code compatibility */
7649 2 : hDirACRend->num_protos_ambi = 2;
7650 2 : move16();
7651 2 : hDirACRend->num_protos_dir = 2;
7652 2 : move16();
7653 2 : hDirACRend->num_protos_diff = 3;
7654 2 : move16();
7655 2 : hDirACRend->proto_index_dir[0] = 0;
7656 2 : move16();
7657 2 : hDirACRend->proto_index_diff[0] = 0;
7658 2 : move16();
7659 : }
7660 : ELSE
7661 : {
7662 16 : hDirACRend->num_protos_ambi = 2;
7663 16 : move16();
7664 16 : hDirACRend->num_protos_diff = 3;
7665 16 : move16();
7666 :
7667 142 : FOR( k = 0; k < hDirACRend->num_outputs_diff; k++ )
7668 : {
7669 126 : IF( ls_azimuth_fx[k] > 0 )
7670 : {
7671 58 : hDirACRend->proto_index_diff[k] = 1;
7672 : }
7673 68 : ELSE IF( ls_azimuth_fx[k] < 0 )
7674 : {
7675 58 : hDirACRend->proto_index_diff[k] = 2;
7676 : }
7677 : ELSE
7678 : {
7679 10 : hDirACRend->proto_index_diff[k] = 0;
7680 : }
7681 126 : move16();
7682 : }
7683 :
7684 16 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
7685 : {
7686 10 : hDirACRend->num_protos_dir = 3;
7687 10 : move16();
7688 10 : Copy( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
7689 : }
7690 : ELSE
7691 : {
7692 6 : hDirACRend->num_protos_dir = 2;
7693 6 : move16();
7694 6 : hDirACRend->proto_index_dir[1] = 1;
7695 6 : move16();
7696 : }
7697 : }
7698 : }
7699 :
7700 : /* direct/diffuse responses */
7701 :
7702 34 : IF( ( hDirACRend->diffuse_response_function_fx = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
7703 : {
7704 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7705 : }
7706 :
7707 34 : test();
7708 34 : test();
7709 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 ) )
7710 : {
7711 28 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
7712 28 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
7713 : }
7714 : ELSE
7715 : {
7716 6 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
7717 6 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
7718 : }
7719 :
7720 34 : hDirACRend->hoa_encoder_fx = NULL;
7721 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
7722 : {
7723 6 : IF( ( hDirACRend->hoa_encoder_fx = (Word32 *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( Word32 ) ) ) == NULL )
7724 : {
7725 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7726 : }
7727 :
7728 6 : set32_fx( hDirACRend->hoa_encoder_fx, 0, imult1616( nchan_out_woLFE, hDirACRend->num_outputs_diff ) );
7729 6 : compute_hoa_encoder_mtx_fx( ls_azimuth_fx, ls_elevation_fx, hDirACRend->hoa_encoder_fx, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
7730 : }
7731 :
7732 : /* VBAP */
7733 34 : inputMasa->hMasaExtRend->hVBAPdata = NULL;
7734 :
7735 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_VBAP ) )
7736 : {
7737 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 ) )
7738 : {
7739 0 : return error;
7740 : }
7741 : }
7742 :
7743 : /* HOA panning/dec */
7744 34 : hDirACRend->hoa_decoder = NULL;
7745 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) )
7746 : {
7747 14 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
7748 : {
7749 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 ) )
7750 : {
7751 0 : return error;
7752 : }
7753 :
7754 2 : hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
7755 : }
7756 : }
7757 :
7758 : /* decorrelation */
7759 34 : hDirACRend->proto_signal_decorr_on = 1;
7760 34 : move16();
7761 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
7762 : {
7763 2 : hDirACRend->proto_signal_decorr_on = 0;
7764 2 : move16();
7765 : }
7766 :
7767 34 : IF( hDirACRend->proto_signal_decorr_on )
7768 : {
7769 32 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDirACRend->h_freq_domain_decorr_ap_params ),
7770 : &( hDirACRend->h_freq_domain_decorr_ap_state ),
7771 : hSpatParamRendCom->num_freq_bands,
7772 : hDirACRend->num_outputs_diff,
7773 : hDirACRend->num_protos_diff,
7774 : hDirACRend->synthesisConf,
7775 : hDirACRend->frequency_axis_fx,
7776 : nchan_transport,
7777 : output_Fs ) ),
7778 : IVAS_ERR_OK ) )
7779 : {
7780 0 : return error;
7781 : }
7782 : }
7783 :
7784 : /* output synthesis */
7785 34 : IF( NE_32( ( ivas_dirac_dec_output_synthesis_open_fx( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ), IVAS_ERR_OK ) )
7786 : {
7787 0 : return error;
7788 : }
7789 34 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
7790 34 : move16();
7791 :
7792 34 : test();
7793 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7794 : {
7795 12 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
7796 12 : move16();
7797 : }
7798 :
7799 : /*-----------------------------------------------------------------*
7800 : * memory allocation
7801 : *-----------------------------------------------------------------*/
7802 :
7803 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
7804 : {
7805 6 : hDirACRend->proto_frame_f_fx = NULL;
7806 : }
7807 : ELSE
7808 : {
7809 28 : IF( ( hDirACRend->proto_frame_f_fx = (Word32 *) malloc( sizeof( Word32 ) * shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 ) ) ) == NULL )
7810 : {
7811 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
7812 : }
7813 28 : hDirACRend->proto_frame_f_len = shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 );
7814 28 : move16();
7815 : }
7816 :
7817 :
7818 34 : hDirACRend->buffer_energy_fx = NULL;
7819 136 : FOR( i = 0; i < DIRAC_NUM_DIMS; i++ )
7820 : {
7821 3366 : FOR( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
7822 : {
7823 3264 : hDirACRend->buffer_intensity_real_fx[i][j] = NULL;
7824 : }
7825 : }
7826 :
7827 : /* output synthesis */
7828 34 : ivas_dirac_dec_output_synthesis_init_fx( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
7829 :
7830 : /* Allocate stack memory */
7831 34 : IF( NE_32( ( error = ivas_dirac_alloc_mem_fx( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ), IVAS_ERR_OK ) )
7832 : {
7833 0 : return error;
7834 : }
7835 :
7836 34 : inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
7837 :
7838 34 : return error;
7839 : }
7840 :
7841 :
7842 12 : static ivas_error ivas_masa_ext_rend_parambin_init(
7843 : input_masa *inputMasa /* i/o: MASA external renderer structure */
7844 : )
7845 : {
7846 : DIRAC_DEC_BIN_HANDLE hDiracDecBin;
7847 : HRTFS_PARAMBIN_HANDLE hHrtfParambin;
7848 : Word16 nBins;
7849 : Word32 output_Fs;
7850 : RENDERER_TYPE renderer_type;
7851 : Word16 j, k, bin;
7852 : Word32 binCenterFreq_fx;
7853 : Word16 tmpFloat_fx;
7854 : ivas_error error;
7855 : Word16 frequency_axis_fx[CLDFB_NO_CHANNELS_MAX];
7856 : Word16 tmp;
7857 : Word16 tmp_e;
7858 : Word16 tmp2;
7859 :
7860 12 : error = IVAS_ERR_OK;
7861 12 : move32();
7862 :
7863 12 : hHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
7864 :
7865 : /* Set common variables and defaults */
7866 12 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
7867 12 : move32();
7868 12 : nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
7869 12 : move16();
7870 12 : renderer_type = inputMasa->hMasaExtRend->renderer_type;
7871 12 : move32();
7872 :
7873 12 : hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin;
7874 :
7875 : /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
7876 12 : IF( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
7877 : {
7878 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
7879 : }
7880 :
7881 12 : hDiracDecBin->hTdDecorr = NULL;
7882 12 : hDiracDecBin->hReverb = NULL;
7883 12 : hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
7884 12 : hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
7885 12 : hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
7886 12 : hDiracDecBin->useTdDecorr = 0; /* Always use frequency domain decorrelator in external renderer */
7887 12 : move16();
7888 :
7889 36 : FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
7890 : {
7891 168 : FOR( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
7892 : {
7893 144 : set16_fx( hDiracDecBin->processMtxRe_fx[j][k], 0, nBins );
7894 144 : set16_fx( hDiracDecBin->processMtxIm_fx[j][k], 0, nBins );
7895 : }
7896 :
7897 72 : FOR( k = 0; k < BINAURAL_CHANNELS; k++ )
7898 : {
7899 48 : set16_fx( hDiracDecBin->processMtxDecRe_fx[j][k], 0, nBins );
7900 48 : set16_fx( hDiracDecBin->processMtxDecIm_fx[j][k], 0, nBins );
7901 : }
7902 24 : hDiracDecBin->q_processMtx = Q15;
7903 24 : hDiracDecBin->q_processMtxSCCR = Q15;
7904 24 : hDiracDecBin->q_processMtxPrev = Q15;
7905 24 : hDiracDecBin->q_processMtxPrevSCCR = Q15;
7906 24 : hDiracDecBin->q_processMtxDec = Q15;
7907 24 : hDiracDecBin->q_processMtxDecPrev = Q15;
7908 24 : move16();
7909 24 : move16();
7910 24 : move16();
7911 24 : move16();
7912 24 : move16();
7913 24 : move16();
7914 24 : set_zero_fx( hDiracDecBin->ChEnePrev_fx[j], nBins );
7915 24 : set_zero_fx( hDiracDecBin->ChEneOutPrev_fx[j], nBins );
7916 24 : set16_fx( hDiracDecBin->ChEnePrev_e[j], 0, nBins );
7917 24 : set16_fx( hDiracDecBin->ChEneOutPrev_e[j], 0, nBins );
7918 : }
7919 12 : set_zero_fx( hDiracDecBin->ChCrossRePrev_fx, nBins );
7920 12 : set_zero_fx( hDiracDecBin->ChCrossImPrev_fx, nBins );
7921 12 : set_zero_fx( hDiracDecBin->ChCrossReOutPrev_fx, nBins );
7922 12 : set_zero_fx( hDiracDecBin->ChCrossImOutPrev_fx, nBins );
7923 12 : set16_fx( hDiracDecBin->ChCrossRePrev_e, 0, nBins );
7924 12 : set16_fx( hDiracDecBin->ChCrossImPrev_e, 0, nBins );
7925 12 : set16_fx( hDiracDecBin->ChCrossReOutPrev_e, 0, nBins );
7926 12 : set16_fx( hDiracDecBin->ChCrossImOutPrev_e, 0, nBins );
7927 12 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
7928 12 : move16();
7929 :
7930 732 : FOR( bin = 0; bin < nBins; bin++ )
7931 : {
7932 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*/
7933 : /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
7934 720 : tmp = BASOP_Util_Divide3232_Scale( binCenterFreq_fx, L_shl( 2700, Q15 ), &tmp_e );
7935 720 : IF( tmp_e < 0 )
7936 : {
7937 36 : tmp = shl( tmp, tmp_e ); /*q15*/
7938 36 : tmp_e = 0;
7939 36 : move16();
7940 : }
7941 720 : tmpFloat_fx = s_max( 0, sub( shl_sat( 1, sub( 15, tmp_e ) ), tmp ) ) /*max( 0.0f, 1.0f - binCenterFreq / 2700.0f )*/; /*Q30*/
7942 720 : tmp2 = extract_l( Mult_32_32( binCenterFreq_fx, 1952258 /*=2^31*180/(550)/360*/ ) % 32767 ); //*binCenterFreq_fx * EVS_PI / 550.0f*/
7943 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 );*/
7944 720 : hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( hDiracDecBin->diffuseFieldCoherence_fx[bin], 1 ); /* Q31 */
7945 720 : move32();
7946 720 : move32();
7947 : }
7948 :
7949 : /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
7950 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceX_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
7951 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceY_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
7952 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceZ_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
7953 :
7954 12 : IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC ) ) /* Indication of binaural rendering without room effect */
7955 : {
7956 8 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
7957 8 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
7958 8 : move16();
7959 8 : hDiracDecBin->hReverb = NULL;
7960 : }
7961 4 : ELSE IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) /* Indication of binaural rendering with room effect */
7962 : {
7963 0 : Copy32( hHrtfParambin->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
7964 0 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
7965 0 : move16();
7966 :
7967 0 : IF( hDiracDecBin->hReverb == NULL )
7968 : {
7969 : /* 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. */
7970 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 ) )
7971 : {
7972 0 : return error;
7973 : }
7974 : }
7975 : }
7976 4 : ELSE IF( EQ_16( renderer_type, RENDERER_STEREO_PARAMETRIC ) )
7977 : {
7978 4 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
7979 4 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
7980 4 : move16();
7981 4 : hDiracDecBin->hReverb = NULL;
7982 4 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
7983 4 : move16();
7984 : }
7985 : ELSE /* Not valid renderer type for this renderer */
7986 : {
7987 0 : assert( false );
7988 : }
7989 :
7990 : /* Always open frequency domain decorrelator */
7991 12 : ivas_dirac_dec_get_frequency_axis_fx( frequency_axis_fx, output_Fs, nBins );
7992 :
7993 12 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
7994 : &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
7995 : nBins,
7996 : BINAURAL_CHANNELS,
7997 : BINAURAL_CHANNELS,
7998 : DIRAC_SYNTHESIS_PSD_LS,
7999 : frequency_axis_fx,
8000 : BINAURAL_CHANNELS,
8001 : output_Fs ) ),
8002 : IVAS_ERR_OK ) )
8003 : {
8004 0 : return error;
8005 : }
8006 : /* External renderer uses constant regularization factor */
8007 12 : hDiracDecBin->reqularizationFactor_fx = 6554; /* 0.4f in Q14 */
8008 12 : move16();
8009 :
8010 12 : inputMasa->hMasaExtRend->hDiracDecBin = hDiracDecBin;
8011 :
8012 12 : return error;
8013 : }
8014 :
8015 48 : static ivas_error initMasaExtRenderer(
8016 : input_masa *inputMasa,
8017 : const AUDIO_CONFIG outConfig )
8018 : {
8019 : Word16 i;
8020 : ivas_error error;
8021 : MASA_EXT_REND_HANDLE hMasaExtRend;
8022 :
8023 48 : error = IVAS_ERR_OK;
8024 48 : move32();
8025 :
8026 48 : IF( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
8027 : {
8028 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
8029 : }
8030 :
8031 48 : inputMasa->hMasaExtRend = hMasaExtRend;
8032 :
8033 : /* Default init */
8034 48 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
8035 48 : move32();
8036 48 : hMasaExtRend->hDirACRend = NULL;
8037 48 : hMasaExtRend->hSpatParamRendCom = NULL;
8038 48 : hMasaExtRend->hDiracDecBin = NULL;
8039 48 : hMasaExtRend->hReverb = NULL;
8040 48 : hMasaExtRend->hHrtfParambin = NULL;
8041 48 : hMasaExtRend->hVBAPdata = NULL;
8042 48 : hMasaExtRend->hoa_dec_mtx = NULL;
8043 :
8044 48 : IF( NE_32( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ), IVAS_ERR_OK ) )
8045 : {
8046 0 : return error;
8047 : }
8048 :
8049 48 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ), IVAS_ERR_OK ) )
8050 : {
8051 0 : return error;
8052 : }
8053 :
8054 48 : SWITCH( outConfig )
8055 : {
8056 4 : case IVAS_AUDIO_CONFIG_MONO:
8057 4 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
8058 : {
8059 2 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
8060 2 : move32();
8061 : }
8062 : ELSE
8063 : {
8064 : /* 1TC MASA to mono does not need rendering. */
8065 2 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
8066 2 : move32();
8067 : }
8068 4 : BREAK;
8069 :
8070 4 : case IVAS_AUDIO_CONFIG_STEREO:
8071 4 : hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
8072 4 : move32();
8073 4 : BREAK;
8074 :
8075 32 : case IVAS_AUDIO_CONFIG_5_1:
8076 : case IVAS_AUDIO_CONFIG_7_1:
8077 : case IVAS_AUDIO_CONFIG_5_1_2:
8078 : case IVAS_AUDIO_CONFIG_5_1_4:
8079 : case IVAS_AUDIO_CONFIG_7_1_4:
8080 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
8081 : case IVAS_AUDIO_CONFIG_FOA:
8082 : case IVAS_AUDIO_CONFIG_HOA2:
8083 : case IVAS_AUDIO_CONFIG_HOA3:
8084 32 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
8085 32 : move32();
8086 32 : BREAK;
8087 :
8088 8 : case IVAS_AUDIO_CONFIG_BINAURAL:
8089 8 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
8090 8 : move32();
8091 8 : BREAK;
8092 :
8093 0 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
8094 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
8095 0 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
8096 0 : move32();
8097 0 : BREAK;
8098 :
8099 0 : default:
8100 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
8101 : }
8102 :
8103 48 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
8104 : {
8105 : Word16 subframe;
8106 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 ) )
8107 : {
8108 0 : return error;
8109 : }
8110 : /* Simple population of the metadata index map as no adaptation is present */
8111 46 : set16_fx( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
8112 230 : FOR( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
8113 : {
8114 184 : hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
8115 184 : move16();
8116 : }
8117 46 : hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
8118 46 : move16();
8119 : }
8120 :
8121 48 : IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_DIRAC ) )
8122 : {
8123 34 : IF( NE_32( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ), IVAS_ERR_OK ) )
8124 : {
8125 0 : return error;
8126 : }
8127 : }
8128 :
8129 48 : test();
8130 48 : test();
8131 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 ) )
8132 : {
8133 12 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
8134 : {
8135 8 : IF( NE_32( ( error = ivas_dirac_dec_binaural_copy_hrtfs_fx( &inputMasa->hMasaExtRend->hHrtfParambin ) ), IVAS_ERR_OK ) )
8136 : {
8137 0 : return error;
8138 : }
8139 : }
8140 :
8141 12 : IF( NE_32( ( error = ivas_masa_ext_rend_parambin_init( inputMasa ) ), IVAS_ERR_OK ) )
8142 : {
8143 0 : return error;
8144 : }
8145 : }
8146 :
8147 : /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
8148 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
8149 : {
8150 96 : hMasaExtRend->cldfbAnaRend[i] = NULL;
8151 : }
8152 :
8153 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
8154 : {
8155 768 : hMasaExtRend->cldfbSynRend[i] = NULL;
8156 : }
8157 :
8158 48 : IF( NE_32( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
8159 : {
8160 116 : FOR( i = 0; i < hMasaExtRend->nchan_input; i++ )
8161 : {
8162 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 ) )
8163 : {
8164 0 : return error;
8165 : }
8166 : }
8167 :
8168 364 : FOR( i = 0; i < hMasaExtRend->nchan_output; i++ )
8169 : {
8170 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 ) )
8171 : {
8172 0 : return error;
8173 : }
8174 : }
8175 : }
8176 :
8177 48 : inputMasa->hMasaExtRend = hMasaExtRend;
8178 :
8179 48 : return IVAS_ERR_OK;
8180 : }
8181 :
8182 666 : static void freeMasaExtRenderer(
8183 : MASA_EXT_REND_HANDLE *hMasaExtRendOut )
8184 : {
8185 : MASA_EXT_REND_HANDLE hMasaExtRend;
8186 : Word16 i;
8187 :
8188 666 : test();
8189 666 : IF( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
8190 : {
8191 618 : return;
8192 : }
8193 :
8194 48 : hMasaExtRend = *hMasaExtRendOut;
8195 :
8196 48 : IF( hMasaExtRend->hDirACRend != NULL )
8197 : {
8198 34 : ivas_dirac_rend_close_fx( &hMasaExtRend->hDirACRend );
8199 : }
8200 :
8201 48 : IF( hMasaExtRend->hSpatParamRendCom != NULL )
8202 : {
8203 46 : ivas_spat_hSpatParamRendCom_close_fx( &hMasaExtRend->hSpatParamRendCom );
8204 : }
8205 :
8206 48 : IF( hMasaExtRend->hDiracDecBin != NULL )
8207 : {
8208 12 : ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin );
8209 : }
8210 :
8211 48 : IF( hMasaExtRend->hReverb != NULL )
8212 : {
8213 0 : ivas_binaural_reverb_close_fx( &hMasaExtRend->hReverb );
8214 : }
8215 :
8216 48 : IF( hMasaExtRend->hHrtfParambin != NULL )
8217 : {
8218 8 : ivas_HRTF_parambin_binary_close_fx( &hMasaExtRend->hHrtfParambin );
8219 : }
8220 :
8221 48 : IF( hMasaExtRend->hVBAPdata != NULL )
8222 : {
8223 20 : vbap_free_data_fx( &hMasaExtRend->hVBAPdata );
8224 : }
8225 :
8226 48 : IF( hMasaExtRend->hoa_dec_mtx != NULL )
8227 : {
8228 2 : free( hMasaExtRend->hoa_dec_mtx );
8229 : }
8230 :
8231 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
8232 : {
8233 96 : IF( hMasaExtRend->cldfbAnaRend[i] != NULL )
8234 : {
8235 70 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbAnaRend[i] );
8236 : }
8237 : }
8238 :
8239 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
8240 : {
8241 768 : IF( hMasaExtRend->cldfbSynRend[i] != NULL )
8242 : {
8243 318 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbSynRend[i] );
8244 : }
8245 : }
8246 :
8247 48 : free( hMasaExtRend );
8248 48 : *hMasaExtRendOut = NULL;
8249 :
8250 48 : return;
8251 : }
8252 :
8253 25500 : static void intermidiate_ext_dirac_render(
8254 : MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure */
8255 : Word16 to_fix )
8256 : {
8257 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
8258 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
8259 : DIRAC_DEC_STACK_MEM DirAC_mem;
8260 : Word16 ch;
8261 : DIRAC_REND_HANDLE hDirACRend;
8262 : Word16 subframe_idx;
8263 : Word16 slot_idx;
8264 : Word16 nchan_transport;
8265 : Word16 tmp;
8266 :
8267 25500 : hDirACRend = hMasaExtRend->hDirACRend;
8268 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
8269 25500 : nchan_transport = hMasaExtRend->nchan_input;
8270 : DIRAC_OUTPUT_SYNTHESIS_STATE *h_dirac_output_synthesis_state;
8271 :
8272 25500 : h_dirac_output_synthesis_state = &( hDirACRend->h_output_synthesis_psd_state );
8273 :
8274 25500 : subframe_idx = hSpatParamRendCom->subframes_rendered;
8275 25500 : move16();
8276 :
8277 25500 : DirAC_mem = hDirACRend->stack_mem;
8278 :
8279 25500 : IF( to_fix )
8280 : {
8281 : #ifdef FIX_867_CLDFB_NRG_SCALE
8282 12750 : DirAC_mem.reference_power_smooth_q[0] = DirAC_mem.reference_power_q[0] = Q31;
8283 12750 : DirAC_mem.reference_power_smooth_q[1] = DirAC_mem.reference_power_q[1] = Q31;
8284 12750 : move16();
8285 12750 : move16();
8286 : #else
8287 : DirAC_mem.reference_power_smooth_q = DirAC_mem.reference_power_q = Q31;
8288 : move16();
8289 : #endif
8290 12750 : move16();
8291 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
8292 : {
8293 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 */
8294 30736 : hDirACRend->h_output_synthesis_psd_state.direct_responses_q = Q30;
8295 30736 : move16();
8296 : }
8297 :
8298 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx )
8299 : {
8300 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 );
8301 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) */
8302 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 );
8303 12750 : move16();
8304 : }
8305 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx )
8306 : {
8307 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 );
8308 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) */
8309 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 );
8310 12750 : move16();
8311 : }
8312 :
8313 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx )
8314 : {
8315 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 ) );
8316 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) */
8317 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 );
8318 10500 : move16();
8319 : }
8320 :
8321 12750 : Word16 num_channels_dir = hDirACRend->num_outputs_dir;
8322 12750 : move16();
8323 :
8324 12750 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
8325 : {
8326 7500 : num_channels_dir = hDirACRend->hOutSetup.nchan_out_woLFE;
8327 7500 : move16();
8328 : }
8329 :
8330 12750 : IF( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx )
8331 : {
8332 12750 : tmp = L_norm_arr( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, imult1616( num_channels_dir, hSpatParamRendCom->num_freq_bands ) );
8333 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) */
8334 12750 : h_dirac_output_synthesis_state->q_cy_auto_diff_smooth = add( h_dirac_output_synthesis_state->q_cy_auto_diff_smooth, tmp );
8335 12750 : move16();
8336 : }
8337 :
8338 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx )
8339 : {
8340 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 );
8341 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) */
8342 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 );
8343 12750 : move16();
8344 : }
8345 :
8346 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 */
8347 12750 : hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q = Q26;
8348 12750 : move16();
8349 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 */
8350 12750 : hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q = Q26;
8351 12750 : move16();
8352 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx )
8353 : {
8354 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 ) );
8355 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) */
8356 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 );
8357 10500 : move16();
8358 : }
8359 :
8360 12750 : IF( EQ_16( hDirACRend->proto_signal_decorr_on, 1 ) )
8361 : {
8362 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 );
8363 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) */
8364 12000 : hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer = add( hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer, tmp );
8365 12000 : move16();
8366 : }
8367 :
8368 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len > 0 )
8369 : {
8370 : Word16 shift, norm1, norm2;
8371 : Word32 tmp1, tmp2;
8372 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 );
8373 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 );
8374 :
8375 12000 : IF( tmp1 == 0 )
8376 : {
8377 32 : norm1 = 31;
8378 32 : move16();
8379 : }
8380 : ELSE
8381 : {
8382 11968 : norm1 = norm_l( tmp1 );
8383 : }
8384 :
8385 12000 : IF( tmp2 == 0 )
8386 : {
8387 32 : norm2 = 31;
8388 32 : move16();
8389 : }
8390 : ELSE
8391 : {
8392 11968 : norm2 = norm_l( tmp2 );
8393 : }
8394 :
8395 12000 : shift = s_min( norm1, norm2 );
8396 :
8397 12000 : Word16 hr_exp = sub( 31, shift );
8398 :
8399 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) */
8400 12000 : hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q = sub( 31, hr_exp );
8401 12000 : move16();
8402 : }
8403 :
8404 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
8405 : {
8406 : /* CLDFB Analysis*/
8407 77744 : FOR( ch = 0; ch < nchan_transport; ch++ )
8408 : {
8409 47008 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
8410 47008 : move16();
8411 : }
8412 : }
8413 12750 : hDirACRend->proto_frame_dec_f_q = sub( 31, hDirACRend->proto_frame_dec_f_q );
8414 12750 : move16();
8415 :
8416 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx )
8417 : {
8418 : #ifdef FIX_867_CLDFB_NRG_SCALE
8419 10500 : tmp = 0;
8420 10500 : move16();
8421 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 ) )
8422 : {
8423 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 ) ) );
8424 : }
8425 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 ) )
8426 : {
8427 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) */
8428 : }
8429 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 );
8430 10500 : move16();
8431 10500 : tmp = 0;
8432 10500 : move16();
8433 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 ) )
8434 : {
8435 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 ) ) ) );
8436 : }
8437 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 ) )
8438 : {
8439 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) */
8440 : }
8441 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 );
8442 10500 : move16();
8443 : #else
8444 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx, imult1616( hDirACRend->num_protos_dir, hSpatParamRendCom->num_freq_bands ) );
8445 : 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) */
8446 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q, tmp );
8447 : move16();
8448 : #endif
8449 : #ifdef FIX_867_CLDFB_NRG_SCALE
8450 10500 : tmp = 0;
8451 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 ) )
8452 : {
8453 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 ) ) );
8454 : }
8455 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 ) )
8456 : {
8457 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) */
8458 : }
8459 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] );
8460 10500 : move16();
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 : 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 ) ) ) );
8464 : }
8465 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 ) )
8466 : {
8467 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) */
8468 : }
8469 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] );
8470 10500 : move16();
8471 : #else
8472 : tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, imult1616( hDirACRend->num_protos_dir, hSpatParamRendCom->num_freq_bands ) );
8473 : 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) */
8474 : hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q );
8475 : move16();
8476 : #endif
8477 : }
8478 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx != NULL )
8479 : {
8480 :
8481 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 );
8482 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) */
8483 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 );
8484 10500 : move16();
8485 : }
8486 :
8487 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx != NULL )
8488 : {
8489 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 );
8490 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) */
8491 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 );
8492 9750 : move16();
8493 : }
8494 : }
8495 : ELSE
8496 : {
8497 43350 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[hSpatParamRendCom->subframes_rendered]; slot_idx++ )
8498 : {
8499 : /* CLDFB Analysis*/
8500 77400 : FOR( ch = 0; ch < nchan_transport; ch++ )
8501 : {
8502 46800 : scale_sig32( hMasaExtRend->cldfbAnaRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbAnaRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state ) ); /* Q11 */
8503 46800 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
8504 46800 : move16();
8505 : }
8506 : }
8507 :
8508 123000 : FOR( ch = 0; ch < hDirACRend->hOutSetup.nchan_out_woLFE + hDirACRend->hOutSetup.num_lfe; ch++ )
8509 : {
8510 110250 : scale_sig32( hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbSynRend[0]->Q_cldfb_state ) ); /* Q11 */
8511 110250 : hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
8512 110250 : move16();
8513 : }
8514 : }
8515 25500 : }
8516 :
8517 666 : static ivas_error printConfigInfo_rend(
8518 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
8519 : )
8520 : {
8521 : ivas_error error;
8522 : Word8 config_str[50];
8523 :
8524 : /*-----------------------------------------------------------------*
8525 : * Print output audio configuration
8526 : *-----------------------------------------------------------------*/
8527 :
8528 666 : IF( NE_32( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ), IVAS_ERR_OK ) )
8529 : {
8530 0 : return error;
8531 : }
8532 :
8533 666 : fprintf( stdout, "Output configuration: %s\n", config_str );
8534 :
8535 : /*-----------------------------------------------------------------*
8536 : * Print renderer configurations
8537 : *-----------------------------------------------------------------*/
8538 :
8539 666 : fprintf( stdout, "Output sampling rate: %d Hz\n", hIvasRend->sampleRateOut );
8540 :
8541 666 : if ( hIvasRend->headRotData.headRotEnabled )
8542 : {
8543 666 : fprintf( stdout, "Head-tracking: ON\n" );
8544 : }
8545 :
8546 666 : IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) ||
8547 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) ||
8548 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ||
8549 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
8550 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8551 : {
8552 188 : fprintf( stdout, "Render framesize: %dms\n", mult( hIvasRend->num_subframes, 5 ) );
8553 : }
8554 :
8555 666 : return IVAS_ERR_OK;
8556 : }
8557 :
8558 :
8559 : /*---------------------------------------------------------------------*
8560 : * IVAS_REND_PrintInputConfig()
8561 : *
8562 : *
8563 : *---------------------------------------------------------------------*/
8564 :
8565 729 : void IVAS_REND_PrintInputConfig(
8566 : const IVAS_AUDIO_CONFIG inputConfig /* i : input audio configuration */
8567 : )
8568 : {
8569 : Word8 config_str[50];
8570 :
8571 729 : get_channel_config( inputConfig, &config_str[0] );
8572 729 : fprintf( stdout, "Input configuration: %s\n", config_str );
8573 :
8574 729 : return;
8575 : }
8576 :
8577 :
8578 : /*---------------------------------------------------------------------*
8579 : * IVAS_REND_PrintConfig()
8580 : *
8581 : *
8582 : *---------------------------------------------------------------------*/
8583 :
8584 666 : ivas_error IVAS_REND_PrintConfig(
8585 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
8586 : )
8587 : {
8588 666 : if ( hIvasRend == NULL )
8589 : {
8590 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8591 : }
8592 :
8593 666 : return printConfigInfo_rend( hIvasRend );
8594 : }
8595 :
8596 :
8597 : /*---------------------------------------------------------------------*
8598 : * IVAS_REND_PrintDisclaimer()
8599 : *
8600 : * Print IVAS disclaimer to console
8601 : *---------------------------------------------------------------------*/
8602 :
8603 666 : void IVAS_REND_PrintDisclaimer( void )
8604 : {
8605 666 : print_disclaimer( stderr );
8606 :
8607 666 : return;
8608 : }
|