Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : #include "basop_util.h"
34 : #include "options.h"
35 : #include "lib_rend.h"
36 : #include "prot_fx.h"
37 : #include "ivas_prot_fx.h"
38 : #include "ivas_prot_rend_fx.h"
39 : #include "isar_prot.h"
40 : #include "isar_stat.h"
41 : #include "lib_isar_pre_rend.h"
42 : #include "ivas_cnst.h"
43 : #include "ivas_rom_com.h"
44 : #include "ivas_rom_rend.h"
45 : #include <assert.h>
46 : #include <math.h>
47 : #include <stdbool.h>
48 : #include "wmc_auto.h"
49 : #ifdef DEBUGGING
50 : #include "debug.h"
51 : #endif
52 :
53 : /*-------------------------------------------------------------------*
54 : * Local constants
55 : *-------------------------------------------------------------------*/
56 :
57 : /* Maximum buffer length (total) in samples. */
58 : #define MAX_BUFFER_LENGTH ( MAX_BUFFER_LENGTH_PER_CHANNEL * MAX_INPUT_CHANNELS )
59 : #define MAX_BIN_DELAY_SAMPLES 150 /* Maximum supported rendering latency for binaural IRs */
60 :
61 : /*-------------------------------------------------------------------*
62 : * Local types
63 : *-------------------------------------------------------------------*/
64 :
65 : typedef float pan_vector[MAX_OUTPUT_CHANNELS];
66 : typedef float pan_matrix[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
67 : typedef float rotation_gains[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
68 : typedef Word32 pan_vector_fx[MAX_OUTPUT_CHANNELS];
69 : typedef Word32 pan_matrix_fx[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
70 : typedef Word16 rotation_gains_fx[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
71 : typedef Word32 rotation_gains_Word32[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
72 : typedef Word32 rotation_matrix_fx[3][3];
73 : typedef float rotation_matrix[3][3];
74 :
75 : /* EFAP wrapper to simplify writing panning gains to a vector that includes LFE channels */
76 : typedef struct
77 : {
78 : EFAP_HANDLE hEfap;
79 : AUDIO_CONFIG speakerConfig;
80 : const LSSETUP_CUSTOM_STRUCT *pCustomLsSetup; /* Pointer to main custom LS struct from renderer handle - doesn't need freeing */
81 : } EFAP_WRAPPER;
82 :
83 : /* Lightweight helper struct that gathers all information required for rendering
84 : * any config to any other config. Used to simplify signatures of rendering functions.
85 : *
86 : * This struct should store ONLY CONST POINTERS to data existing elsewhere.
87 : * Storing pointers instead of data itself ensures that no additional updates
88 : * are required when any of these are changed in the renderer. Making the pointers
89 : * const ensures that this data is only read, but not modified by the rendering functions. */
90 : typedef struct
91 : {
92 : const Word32 *pOutSampleRate;
93 : const AUDIO_CONFIG *pOutConfig;
94 : const LSSETUP_CUSTOM_STRUCT *pCustomLsOut;
95 : const EFAP_WRAPPER *pEfapOutWrapper;
96 : IVAS_REND_HeadRotData *pHeadRotData; // for now removing the const qualifier TODO: will modify later
97 : const RENDER_CONFIG_HANDLE *hhRendererConfig;
98 : const Word16 *pSplitRendBFI;
99 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
100 : const COMBINED_ORIENTATION_HANDLE *pCombinedOrientationData;
101 : } rendering_context;
102 :
103 : /* Common base for input structs */
104 : typedef struct
105 : {
106 : AUDIO_CONFIG inConfig;
107 : IVAS_REND_InputId id;
108 : IVAS_REND_AudioBuffer inputBuffer;
109 : Word32 gain_fx; /* Linear, not in dB Q30 */
110 : rendering_context ctx;
111 : Word32 numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */
112 : } input_base;
113 :
114 : typedef struct
115 : {
116 : input_base base;
117 : IVAS_ISM_METADATA currentPos;
118 : IVAS_ISM_METADATA previousPos;
119 : TDREND_WRAPPER tdRendWrapper;
120 : CREND_WRAPPER_HANDLE crendWrapper;
121 : REVERB_HANDLE hReverb;
122 : rotation_matrix_fx rot_mat_prev;
123 : pan_vector_fx prev_pan_gains_fx;
124 : rotation_matrix_fx rot_mat_prev_fx;
125 : pan_vector prev_pan_gains;
126 : Word8 firstFrameRendered;
127 : TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */
128 : Word32 *bufferData_fx;
129 : Word16 nonDiegeticPan;
130 : Word32 nonDiegeticPanGain_fx; /* Q31 */
131 : OMASA_ANA_HANDLE hOMasa;
132 : UWord16 total_num_objects;
133 : #ifdef NONBE_1377_REND_DIRATT_CONF
134 : Word16 object_id;
135 : #endif
136 : Word32 ism_metadata_delay_ms_fx; /* Q0 */
137 : } input_ism;
138 :
139 : typedef struct
140 : {
141 : Word16 numLfeChannels;
142 : bool pan_lfe;
143 : // float lfeInputGain;
144 : Word32 lfeInputGain_fx; /* Q31 */
145 : // float lfeOutputAzimuth;
146 : Word16 lfeOutputAzimuth_fx;
147 : // float lfeOutputElevation;
148 : Word16 lfeOutputElevation_fx;
149 : // IVAS_REND_LfePanMtx lfePanMtx;
150 : IVAS_REND_LfePanMtx_fx lfePanMtx_fx; /* Q31 */
151 : } lfe_routing;
152 :
153 : typedef struct
154 : {
155 : input_base base;
156 :
157 : /* Full panning matrix. 1st index is input channel, 2nd index is output channel.
158 : All LFE channels should be included, both for inputs and outputs */
159 : pan_matrix_fx panGains_fx; /* Q31 */
160 :
161 : LSSETUP_CUSTOM_STRUCT customLsInput;
162 : EFAP_WRAPPER efapInWrapper;
163 : TDREND_WRAPPER tdRendWrapper;
164 : CREND_WRAPPER_HANDLE crendWrapper;
165 : TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */
166 : REVERB_HANDLE hReverb;
167 : rotation_gains_Word32 rot_gains_prev_fx[MAX_HEAD_ROT_POSES];
168 : Word16 nonDiegeticPan;
169 : Word32 nonDiegeticPanGain_fx;
170 : lfe_routing lfeRouting;
171 : Word32 *bufferData_fx;
172 : Word16 binauralDelaySmp;
173 : Word32 *lfeDelayBuffer_fx;
174 : MCMASA_ANA_HANDLE hMcMasa;
175 : } input_mc;
176 :
177 : typedef struct
178 : {
179 : input_base base;
180 : // pan_matrix hoaDecMtx;
181 : pan_matrix_fx hoaDecMtx_fx;
182 : CLDFB_REND_WRAPPER cldfbRendWrapper;
183 : CREND_WRAPPER_HANDLE crendWrapper;
184 : rotation_gains_fx rot_gains_prev_fx[MAX_HEAD_ROT_POSES];
185 : Word32 *bufferData_fx;
186 : DIRAC_ANA_HANDLE hDirAC;
187 : } input_sba;
188 :
189 : typedef struct
190 : {
191 : input_base base;
192 : MASA_METADATA_FRAME masaMetadata;
193 : bool metadataHasBeenFed;
194 : Word32 *bufferData_fx;
195 : MASA_EXT_REND_HANDLE hMasaExtRend;
196 : MASA_PREREND_HANDLE hMasaPrerend;
197 : } input_masa;
198 :
199 : typedef struct hrtf_handles
200 : {
201 : #ifdef FIX_CREND_SIMPLIFY_CODE
202 : IVAS_DEC_HRTF_CREND_HANDLE hHrtfCrend;
203 : #else
204 : IVAS_DEC_HRTF_CREND_HANDLE hSetOfHRTF;
205 : #endif
206 : IVAS_DEC_HRTF_FASTCONV_HANDLE hHrtfFastConv;
207 : IVAS_DEC_HRTF_PARAMBIN_HANDLE hHrtfParambin;
208 : IVAS_DEC_HRTF_TD_HANDLE hHrtfTD;
209 : IVAS_DEC_HRTF_STATISTICS_HANDLE hHrtfStatistics;
210 : } hrtf_handles;
211 :
212 :
213 : struct IVAS_REND
214 : {
215 : Word32 sampleRateOut;
216 : IVAS_LIMITER_HANDLE hLimiter;
217 :
218 : input_ism inputsIsm[RENDERER_MAX_ISM_INPUTS];
219 : input_mc inputsMc[RENDERER_MAX_MC_INPUTS];
220 : input_sba inputsSba[RENDERER_MAX_SBA_INPUTS];
221 : input_masa inputsMasa[RENDERER_MAX_MASA_INPUTS];
222 :
223 : AUDIO_CONFIG inputConfig;
224 : AUDIO_CONFIG outputConfig;
225 : EFAP_WRAPPER efapOutWrapper;
226 : IVAS_LSSETUP_CUSTOM_STRUCT customLsOut;
227 :
228 : SPLIT_REND_WRAPPER *splitRendWrapper;
229 : IVAS_REND_AudioBuffer splitRendEncBuffer;
230 : IVAS_REND_HeadRotData headRotData;
231 : Word16 splitRendBFI;
232 :
233 : EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData;
234 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData;
235 :
236 : Word8 rendererConfigEnabled;
237 : RENDER_CONFIG_DATA *hRendererConfig; /* Renderer config pointer */
238 :
239 : Word16 num_subframes;
240 : hrtf_handles hHrtfs;
241 : };
242 :
243 :
244 : /*-------------------------------------------------------------------*
245 : * Local function prototypes
246 : *-------------------------------------------------------------------*/
247 :
248 : static ivas_error initMasaExtRenderer( input_masa *inputMasa, const AUDIO_CONFIG outConfig, const RENDER_CONFIG_DATA *hRendCfg, hrtf_handles *hHrtfs );
249 :
250 : static void freeMasaExtRenderer( MASA_EXT_REND_HANDLE *hMasaExtRendOut );
251 :
252 : static void intermidiate_ext_dirac_render( MASA_EXT_REND_HANDLE hMasaExtRend, Word16 to_fix );
253 :
254 : static ivas_error renderSbaToMultiBinauralCldfb( input_sba *sbaInput, Word32 Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], Word32 Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], const Word16 low_res_pre_rend_rot, const Word16 num_subframes, const Word16 Q_in );
255 : static ivas_error renderSbaToMultiBinaural( input_sba *sbaInput, const AUDIO_CONFIG outConfig, Word32 out[][L_FRAME48k], const Word16 *pq_fact );
256 :
257 :
258 : /*-------------------------------------------------------------------*
259 : * Local functions
260 : *-------------------------------------------------------------------*/
261 :
262 973 : static ivas_error allocateInputBaseBufferData_fx(
263 : Word32 **data, /* Qx */
264 : const Word16 data_size )
265 : {
266 973 : *data = (Word32 *) malloc( data_size * sizeof( Word32 ) );
267 973 : IF( *data == NULL )
268 : {
269 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for input base buffer data" );
270 : }
271 :
272 973 : return IVAS_ERR_OK;
273 : }
274 4662 : static void freeInputBaseBufferData_fx(
275 : Word32 **data /* Qx */ )
276 : {
277 4662 : IF( *data != NULL )
278 : {
279 973 : free( *data );
280 973 : *data = NULL;
281 : }
282 :
283 4662 : return;
284 : }
285 372 : static ivas_error allocateMcLfeDelayBuffer_fx(
286 : Word32 **lfeDelayBuffer, /* Qx */
287 : const Word16 data_size )
288 : {
289 372 : *lfeDelayBuffer = (Word32 *) malloc( data_size * sizeof( Word32 ) );
290 372 : IF( *lfeDelayBuffer == NULL )
291 : {
292 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" );
293 : }
294 :
295 372 : return IVAS_ERR_OK;
296 : }
297 666 : static void freeMcLfeDelayBuffer_fx(
298 : Word32 **lfeDelayBuffer /* Qx */ )
299 : {
300 666 : IF( *lfeDelayBuffer != NULL )
301 : {
302 372 : free( *lfeDelayBuffer );
303 372 : *lfeDelayBuffer = NULL;
304 : }
305 :
306 666 : return;
307 : }
308 :
309 :
310 235 : static IVAS_QUATERNION quaternionInit_fx(
311 : void )
312 : {
313 : IVAS_QUATERNION q;
314 235 : q.w_fx = ONE_IN_Q29;
315 235 : move32();
316 235 : q.x_fx = q.y_fx = q.z_fx = 0;
317 235 : move32();
318 235 : move32();
319 235 : move32();
320 :
321 235 : q.q_fact = Q29;
322 235 : move16();
323 235 : move16();
324 235 : move16();
325 235 : move16();
326 :
327 235 : return q;
328 : }
329 :
330 215021437 : static Word32 *getSmplPtr_fx(
331 : IVAS_REND_AudioBuffer buffer,
332 : const UWord32 chnlIdx,
333 : const UWord32 smplIdx )
334 : {
335 215021437 : return buffer.data_fx + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx;
336 : }
337 :
338 0 : static void convertBitsBufferToInternalBitsBuff(
339 : const IVAS_REND_BitstreamBuffer outBits,
340 : ISAR_SPLIT_REND_BITS_HANDLE hBits )
341 : {
342 0 : hBits->bits_buf = outBits.bits;
343 0 : hBits->bits_read = outBits.config.bitsRead;
344 0 : hBits->bits_written = outBits.config.bitsWritten;
345 0 : hBits->buf_len = outBits.config.bufLenInBytes;
346 0 : hBits->codec = outBits.config.codec;
347 0 : hBits->pose_correction = outBits.config.poseCorrection;
348 0 : hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
349 :
350 0 : move16();
351 0 : move32();
352 0 : move32();
353 0 : move32();
354 0 : move32();
355 0 : move32();
356 0 : move32();
357 :
358 0 : return;
359 : }
360 :
361 0 : static void convertInternalBitsBuffToBitsBuffer(
362 : IVAS_REND_BitstreamBuffer *hOutBits,
363 : const ISAR_SPLIT_REND_BITS_DATA bits )
364 : {
365 0 : hOutBits->bits = bits.bits_buf;
366 0 : hOutBits->config.bitsRead = bits.bits_read;
367 0 : hOutBits->config.bitsWritten = bits.bits_written;
368 0 : hOutBits->config.bufLenInBytes = bits.buf_len;
369 0 : hOutBits->config.codec = bits.codec;
370 0 : hOutBits->config.poseCorrection = bits.pose_correction;
371 0 : hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
372 :
373 0 : return;
374 : }
375 :
376 0 : static void copyBufferToCLDFBarray_fx(
377 : const IVAS_REND_AudioBuffer buffer,
378 : Word32 re[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
379 : Word32 im[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] )
380 : {
381 : UWord32 smplIdx, slotIdx;
382 : UWord32 numCldfbSamples, num_bands;
383 : UWord32 chnlIdx;
384 : const Word32 *readPtr;
385 :
386 0 : assert( ( buffer.config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
387 0 : readPtr = buffer.data_fx;
388 0 : numCldfbSamples = (UWord32) shr( buffer.config.numSamplesPerChannel, 1 );
389 0 : num_bands = (UWord32) Mpy_32_32( numCldfbSamples, ONE_BY_CLDFB_NO_COL_MAX_Q31 );
390 0 : FOR( chnlIdx = 0; chnlIdx < (UWord32) buffer.config.numChannels; ++chnlIdx )
391 : {
392 0 : FOR( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
393 : {
394 0 : FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
395 : {
396 0 : re[chnlIdx][slotIdx][smplIdx] = *readPtr++;
397 : }
398 0 : FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
399 : {
400 0 : im[chnlIdx][slotIdx][smplIdx] = *readPtr++;
401 : }
402 : }
403 : }
404 :
405 0 : return;
406 : }
407 :
408 0 : static void accumulateCLDFBArrayToBuffer_fx(
409 : Word32 re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
410 : Word32 im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
411 : IVAS_REND_AudioBuffer *buffer )
412 : {
413 : UWord32 smplIdx, slotIdx;
414 : UWord32 numCldfbSamples, num_bands;
415 : Word16 chnlIdx;
416 : Word32 *writePtr;
417 :
418 0 : assert( ( buffer->config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
419 0 : writePtr = buffer->data_fx;
420 0 : numCldfbSamples = (UWord32) shr( buffer->config.numSamplesPerChannel, 1 );
421 0 : num_bands = (UWord32) Mpy_32_32( numCldfbSamples, ONE_BY_CLDFB_NO_COL_MAX_Q31 );
422 :
423 0 : FOR( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
424 : {
425 0 : FOR( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
426 : {
427 0 : FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
428 : {
429 0 : *writePtr++ += re[chnlIdx][slotIdx][smplIdx];
430 : }
431 0 : FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
432 : {
433 0 : *writePtr++ += im[chnlIdx][slotIdx][smplIdx];
434 : }
435 : }
436 : }
437 :
438 0 : return;
439 : }
440 :
441 645648 : static void copyBufferTo2dArray_fx(
442 : const IVAS_REND_AudioBuffer buffer,
443 : Word32 array[][L_FRAME48k] )
444 : {
445 : UWord32 smplIdx;
446 : UWord32 chnlIdx;
447 : const Word32 *readPtr;
448 :
449 645648 : assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
450 :
451 645648 : readPtr = buffer.data_fx;
452 :
453 4569484 : FOR( chnlIdx = 0; chnlIdx < (UWord32) buffer.config.numChannels; ++chnlIdx )
454 : {
455 1512693436 : FOR( smplIdx = 0; smplIdx < (UWord32) buffer.config.numSamplesPerChannel; ++smplIdx )
456 : {
457 1508769600 : array[chnlIdx][smplIdx] = *readPtr++;
458 1508769600 : move32();
459 : }
460 : }
461 :
462 645648 : return;
463 : }
464 645648 : static void accumulate2dArrayToBuffer_fx(
465 : Word32 array[][L_FRAME48k],
466 : const IVAS_REND_AudioBuffer *buffer )
467 : {
468 : Word16 smplIdx, chnlIdx;
469 : Word32 *writePtr;
470 :
471 645648 : writePtr = buffer->data_fx;
472 2020944 : FOR( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
473 : {
474 530200896 : FOR( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
475 : {
476 528825600 : *writePtr = L_add( *writePtr, array[chnlIdx][smplIdx] );
477 528825600 : move32();
478 528825600 : writePtr++;
479 : }
480 : }
481 :
482 645648 : return;
483 : }
484 : /*-------------------------------------------------------------------*
485 : * limitRendererOutput()
486 : *
487 : * In-place saturation control for multichannel buffers with adaptive release time
488 : *-------------------------------------------------------------------*/
489 :
490 : #ifndef DISABLE_LIMITER
491 : /*! r: number of clipped output samples */
492 1126140 : static Word32 limitRendererOutput_fx(
493 : IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */
494 : Word32 *output, /* i/o: I/O buffer Q(q_factor) */
495 : const Word16 output_frame, /* i : number of samples per channel in the buffer */
496 : const Word32 threshold, /* i : signal amplitude above which limiting starts to be applied */
497 : Word16 q_factor ) /* i : q factor of output samples */
498 : {
499 : Word16 i;
500 : Word32 **channels;
501 : Word16 num_channels;
502 1126140 : Word32 numClipping = 0;
503 1126140 : move32();
504 :
505 : /* return early if given bad parameters */
506 1126140 : test();
507 1126140 : test();
508 1126140 : IF( hLimiter == NULL || output == NULL || output_frame <= 0 )
509 : {
510 0 : return 0;
511 : }
512 :
513 1126140 : channels = hLimiter->channel_ptrs_fx;
514 1126140 : num_channels = hLimiter->num_channels;
515 1126140 : move16();
516 :
517 7755488 : FOR( i = 0; i < num_channels; ++i )
518 : {
519 6629348 : channels[i] = output + imult1616( i, output_frame );
520 : }
521 :
522 1126140 : limiter_process_fx( hLimiter, output_frame, threshold, 0, NULL, q_factor );
523 :
524 : /* Apply clipping to buffer in case the limiter let through some samples > 1.0f */
525 2809398780 : FOR( i = 0; i < output_frame * num_channels; ++i )
526 : {
527 :
528 2808272640 : output[i] = L_min( L_max( L_shl( INT16_MIN, q_factor ), output[i] ), L_shl( INT16_MAX, q_factor ) );
529 2808272640 : move32();
530 : }
531 :
532 1126140 : return numClipping;
533 : }
534 : #endif
535 :
536 : /*-------------------------------------------------------------------*
537 : * validateOutputAudioConfig()
538 : *
539 : *
540 : *-------------------------------------------------------------------*/
541 :
542 666 : static ivas_error validateOutputAudioConfig(
543 : const AUDIO_CONFIG outConfig )
544 : {
545 666 : SWITCH( outConfig )
546 : {
547 666 : case IVAS_AUDIO_CONFIG_MONO:
548 : case IVAS_AUDIO_CONFIG_STEREO:
549 : case IVAS_AUDIO_CONFIG_5_1:
550 : case IVAS_AUDIO_CONFIG_7_1:
551 : case IVAS_AUDIO_CONFIG_5_1_2:
552 : case IVAS_AUDIO_CONFIG_5_1_4:
553 : case IVAS_AUDIO_CONFIG_7_1_4:
554 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
555 : case IVAS_AUDIO_CONFIG_FOA:
556 : case IVAS_AUDIO_CONFIG_HOA2:
557 : case IVAS_AUDIO_CONFIG_HOA3:
558 : case IVAS_AUDIO_CONFIG_BINAURAL:
559 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
560 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
561 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
562 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
563 : case IVAS_AUDIO_CONFIG_MASA1:
564 : case IVAS_AUDIO_CONFIG_MASA2:
565 666 : return IVAS_ERR_OK;
566 0 : default:
567 0 : BREAK;
568 : }
569 :
570 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
571 : }
572 :
573 : /*-------------------------------------------------------------------*
574 : * getAudioConfigType()
575 : *
576 : *
577 : *-------------------------------------------------------------------*/
578 :
579 8577357 : IVAS_REND_AudioConfigType getAudioConfigType(
580 : const AUDIO_CONFIG config )
581 : {
582 : IVAS_REND_AudioConfigType type;
583 :
584 8577357 : SWITCH( config )
585 : {
586 4218612 : case IVAS_AUDIO_CONFIG_MONO:
587 : case IVAS_AUDIO_CONFIG_STEREO:
588 : case IVAS_AUDIO_CONFIG_5_1:
589 : case IVAS_AUDIO_CONFIG_7_1:
590 : case IVAS_AUDIO_CONFIG_5_1_2:
591 : case IVAS_AUDIO_CONFIG_5_1_4:
592 : case IVAS_AUDIO_CONFIG_7_1_4:
593 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
594 4218612 : type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
595 4218612 : move16();
596 4218612 : BREAK;
597 1511617 : case IVAS_AUDIO_CONFIG_FOA:
598 : case IVAS_AUDIO_CONFIG_HOA2:
599 : case IVAS_AUDIO_CONFIG_HOA3:
600 1511617 : type = IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS;
601 1511617 : move16();
602 1511617 : BREAK;
603 301983 : case IVAS_AUDIO_CONFIG_OBA:
604 301983 : type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
605 301983 : move16();
606 301983 : BREAK;
607 2536040 : case IVAS_AUDIO_CONFIG_BINAURAL:
608 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
609 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
610 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
611 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
612 2536040 : type = IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL;
613 2536040 : move16();
614 2536040 : BREAK;
615 9105 : case IVAS_AUDIO_CONFIG_MASA1:
616 : case IVAS_AUDIO_CONFIG_MASA2:
617 9105 : type = IVAS_REND_AUDIO_CONFIG_TYPE_MASA;
618 9105 : move16();
619 9105 : BREAK;
620 0 : default:
621 0 : type = IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
622 0 : move16();
623 0 : BREAK;
624 : }
625 :
626 8577357 : return type;
627 : }
628 :
629 : /*-------------------------------------------------------------------*
630 : * validateOutputSampleRate()
631 : *
632 : *
633 : *-------------------------------------------------------------------*/
634 :
635 666 : static ivas_error validateOutputSampleRate(
636 : const Word32 sampleRate,
637 : const AUDIO_CONFIG outConfig )
638 : {
639 :
640 666 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
641 : {
642 : /* If no binaural rendering, any sampling rate is supported */
643 478 : return IVAS_ERR_OK;
644 : }
645 188 : ELSE IF( ( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) && NE_32( sampleRate, 48000 ) )
646 : {
647 0 : return IVAS_ERROR( IVAS_ERR_INVALID_SAMPLING_RATE, "Error: Only 48kHz output sampling rate is supported for split rendering." );
648 : }
649 : ELSE
650 : {
651 :
652 : /* Otherwise rendering to binaural, support the same set as IVAS decoder */
653 188 : SWITCH( sampleRate )
654 : {
655 188 : case 16000:
656 : case 32000:
657 : case 48000:
658 188 : return IVAS_ERR_OK;
659 : }
660 :
661 0 : return IVAS_ERR_INVALID_SAMPLING_RATE;
662 : }
663 : }
664 :
665 : /*-------------------------------------------------------------------*
666 : * getAudioConfigNumChannels()
667 : *
668 : *
669 : *-------------------------------------------------------------------*/
670 :
671 6102747 : ivas_error getAudioConfigNumChannels(
672 : const AUDIO_CONFIG config,
673 : Word16 *numChannels )
674 : {
675 6102747 : SWITCH( config )
676 : {
677 1484449 : case IVAS_AUDIO_CONFIG_MONO:
678 : case IVAS_AUDIO_CONFIG_OBA:
679 : case IVAS_AUDIO_CONFIG_MASA1:
680 1484449 : *numChannels = 1;
681 1484449 : move16();
682 1484449 : BREAK;
683 1528226 : case IVAS_AUDIO_CONFIG_STEREO:
684 : case IVAS_AUDIO_CONFIG_BINAURAL:
685 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
686 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
687 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
688 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
689 : case IVAS_AUDIO_CONFIG_MASA2:
690 1528226 : *numChannels = 2;
691 1528226 : move16();
692 1528226 : BREAK;
693 371308 : case IVAS_AUDIO_CONFIG_FOA:
694 371308 : *numChannels = 4;
695 371308 : move16();
696 371308 : BREAK;
697 403308 : case IVAS_AUDIO_CONFIG_5_1:
698 403308 : *numChannels = 6;
699 403308 : move16();
700 403308 : BREAK;
701 278307 : case IVAS_AUDIO_CONFIG_7_1:
702 : case IVAS_AUDIO_CONFIG_5_1_2:
703 278307 : *numChannels = 8;
704 278307 : move16();
705 278307 : BREAK;
706 365987 : case IVAS_AUDIO_CONFIG_HOA2:
707 365987 : *numChannels = 9;
708 365987 : move16();
709 365987 : BREAK;
710 149099 : case IVAS_AUDIO_CONFIG_5_1_4:
711 149099 : *numChannels = 10;
712 149099 : move16();
713 149099 : BREAK;
714 1155175 : case IVAS_AUDIO_CONFIG_7_1_4:
715 1155175 : *numChannels = 12;
716 1155175 : move16();
717 1155175 : BREAK;
718 366888 : case IVAS_AUDIO_CONFIG_HOA3:
719 366888 : *numChannels = 16;
720 366888 : move16();
721 366888 : BREAK;
722 0 : default:
723 0 : return IVAS_ERR_NUM_CHANNELS_UNKNOWN;
724 : }
725 :
726 6102747 : move16();
727 6102747 : return IVAS_ERR_OK;
728 : }
729 :
730 : /*-------------------------------------------------------------------*
731 : * Local functions
732 : *-------------------------------------------------------------------*/
733 :
734 713 : static ivas_error initLimiter(
735 : IVAS_LIMITER_HANDLE *phLimiter,
736 : const Word16 numChannels,
737 : const Word32 sampleRate )
738 : {
739 : ivas_error error;
740 :
741 : /* If re-initializing with unchanged values, return early */
742 713 : test();
743 713 : test();
744 713 : IF( *phLimiter != NULL && EQ_16( ( *phLimiter )->num_channels, numChannels ) && EQ_32( ( *phLimiter )->sampling_rate, sampleRate ) )
745 : {
746 0 : return IVAS_ERR_OK;
747 : }
748 :
749 : /* Support re-init: close if already allocated */
750 713 : IF( *phLimiter != NULL )
751 : {
752 47 : ivas_limiter_close_fx( phLimiter );
753 : }
754 :
755 713 : IF( NE_32( ( error = ivas_limiter_open_fx( phLimiter, numChannels, sampleRate ) ), IVAS_ERR_OK ) )
756 : {
757 0 : return error;
758 : }
759 :
760 713 : return IVAS_ERR_OK;
761 : }
762 1038 : static LSSETUP_CUSTOM_STRUCT defaultCustomLs(
763 : void )
764 : {
765 : LSSETUP_CUSTOM_STRUCT ls;
766 :
767 : /* Set mono by default. This simplifies initialization,
768 : since output config is never in an undefined state. */
769 1038 : ls.is_planar_setup = 1;
770 1038 : ls.num_spk = 1;
771 1038 : move16();
772 1038 : move16();
773 1038 : set32_fx( ls.ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS );
774 1038 : set32_fx( ls.ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS );
775 1038 : ls.num_lfe = 0;
776 1038 : move16();
777 1038 : set16_fx( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
778 1038 : ls.separate_ch_found = 0;
779 1038 : move16();
780 1038 : set16_fx( ls.separate_ch_gains_fx, 0, MAX_OUTPUT_CHANNELS );
781 :
782 1038 : return ls;
783 : }
784 :
785 :
786 13041 : static ivas_error getSpeakerAzimuths_fx(
787 : AUDIO_CONFIG config,
788 : const Word32 **azimuths /* Q22 */ )
789 : {
790 13041 : SWITCH( config )
791 : {
792 63 : case IVAS_AUDIO_CONFIG_MONO:
793 63 : *azimuths = ls_azimuth_CICP1_fx;
794 63 : BREAK;
795 67 : case IVAS_AUDIO_CONFIG_STEREO:
796 67 : *azimuths = ls_azimuth_CICP2_fx;
797 67 : BREAK;
798 5057 : case IVAS_AUDIO_CONFIG_5_1:
799 5057 : *azimuths = ls_azimuth_CICP6_fx;
800 5057 : BREAK;
801 807 : case IVAS_AUDIO_CONFIG_7_1:
802 807 : *azimuths = ls_azimuth_CICP12_fx;
803 807 : BREAK;
804 2307 : case IVAS_AUDIO_CONFIG_5_1_2:
805 2307 : *azimuths = ls_azimuth_CICP14_fx;
806 2307 : BREAK;
807 2313 : case IVAS_AUDIO_CONFIG_5_1_4:
808 2313 : *azimuths = ls_azimuth_CICP16_fx;
809 2313 : BREAK;
810 2427 : case IVAS_AUDIO_CONFIG_7_1_4:
811 2427 : *azimuths = ls_azimuth_CICP19_fx;
812 2427 : BREAK;
813 0 : default:
814 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
815 : }
816 :
817 13041 : return IVAS_ERR_OK;
818 : }
819 :
820 13041 : static ivas_error getSpeakerElevations_fx(
821 : AUDIO_CONFIG config,
822 : const Word32 **elevations /* Q22 */ )
823 : {
824 13041 : SWITCH( config )
825 : {
826 63 : case IVAS_AUDIO_CONFIG_MONO:
827 63 : *elevations = ls_elevation_CICP1_fx;
828 63 : BREAK;
829 67 : case IVAS_AUDIO_CONFIG_STEREO:
830 67 : *elevations = ls_elevation_CICP2_fx;
831 67 : BREAK;
832 5057 : case IVAS_AUDIO_CONFIG_5_1:
833 5057 : *elevations = ls_elevation_CICP6_fx;
834 5057 : BREAK;
835 807 : case IVAS_AUDIO_CONFIG_7_1:
836 807 : *elevations = ls_elevation_CICP12_fx;
837 807 : BREAK;
838 2307 : case IVAS_AUDIO_CONFIG_5_1_2:
839 2307 : *elevations = ls_elevation_CICP14_fx;
840 2307 : BREAK;
841 2313 : case IVAS_AUDIO_CONFIG_5_1_4:
842 2313 : *elevations = ls_elevation_CICP16_fx;
843 2313 : BREAK;
844 2427 : case IVAS_AUDIO_CONFIG_7_1_4:
845 2427 : *elevations = ls_elevation_CICP19_fx;
846 2427 : BREAK;
847 0 : default:
848 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
849 : }
850 :
851 13041 : return IVAS_ERR_OK;
852 : }
853 :
854 273185 : static ivas_error getAmbisonicsOrder_fx(
855 : AUDIO_CONFIG config,
856 : Word16 *order )
857 : {
858 273185 : SWITCH( config )
859 : {
860 91071 : case IVAS_AUDIO_CONFIG_FOA:
861 91071 : *order = 1;
862 91071 : move16();
863 91071 : BREAK;
864 91057 : case IVAS_AUDIO_CONFIG_HOA2:
865 91057 : *order = 2;
866 91057 : move16();
867 91057 : BREAK;
868 91057 : case IVAS_AUDIO_CONFIG_HOA3:
869 91057 : *order = 3;
870 91057 : move16();
871 91057 : BREAK;
872 0 : default:
873 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" );
874 : }
875 :
876 273185 : return IVAS_ERR_OK;
877 : }
878 :
879 :
880 0 : static Word16 getNumLfeChannels(
881 : input_mc *inputMc )
882 : {
883 0 : SWITCH( inputMc->base.inConfig )
884 : {
885 0 : case IVAS_AUDIO_CONFIG_5_1:
886 : case IVAS_AUDIO_CONFIG_7_1:
887 : case IVAS_AUDIO_CONFIG_5_1_2:
888 : case IVAS_AUDIO_CONFIG_5_1_4:
889 : case IVAS_AUDIO_CONFIG_7_1_4:
890 0 : return 1;
891 0 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
892 0 : return inputMc->customLsInput.num_lfe;
893 0 : default:
894 0 : BREAK;
895 : }
896 :
897 0 : return 0;
898 : }
899 541 : static ivas_error getNumNonLfeChannelsInSpeakerLayout(
900 : AUDIO_CONFIG config,
901 : Word16 *numNonLfeChannels )
902 : {
903 541 : SWITCH( config )
904 : {
905 63 : case IVAS_AUDIO_CONFIG_MONO:
906 63 : *numNonLfeChannels = 1;
907 63 : move16();
908 63 : BREAK;
909 67 : case IVAS_AUDIO_CONFIG_STEREO:
910 67 : *numNonLfeChannels = 2;
911 67 : move16();
912 67 : BREAK;
913 57 : case IVAS_AUDIO_CONFIG_5_1:
914 57 : *numNonLfeChannels = 5;
915 57 : move16();
916 57 : BREAK;
917 114 : case IVAS_AUDIO_CONFIG_5_1_2:
918 : case IVAS_AUDIO_CONFIG_7_1:
919 114 : *numNonLfeChannels = 7;
920 114 : move16();
921 114 : BREAK;
922 63 : case IVAS_AUDIO_CONFIG_5_1_4:
923 63 : *numNonLfeChannels = 9;
924 63 : move16();
925 63 : BREAK;
926 177 : case IVAS_AUDIO_CONFIG_7_1_4:
927 177 : *numNonLfeChannels = 11;
928 177 : move16();
929 177 : BREAK;
930 0 : default:
931 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
932 : }
933 :
934 541 : return IVAS_ERR_OK;
935 : }
936 25504 : static ivas_error getMcConfigValues_fx(
937 : AUDIO_CONFIG inConfig,
938 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs,
939 : const Word32 **azimuth, /* Q22 */
940 : const Word32 **elevation, /* Q22 */
941 : Word16 *lfe_idx,
942 : Word16 *is_planar )
943 : {
944 : Word16 i;
945 : ivas_error error;
946 :
947 25504 : *lfe_idx = -1;
948 25504 : *is_planar = 1;
949 25504 : move16();
950 25504 : move16();
951 25504 : SWITCH( inConfig )
952 : {
953 13004 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
954 13004 : *azimuth = (const Word32 *) &pInCustomLs->ls_azimuth_fx;
955 13004 : *elevation = (const Word32 *) &pInCustomLs->ls_elevation_fx;
956 13004 : IF( pInCustomLs->num_lfe > 0 )
957 : {
958 0 : *lfe_idx = pInCustomLs->lfe_idx[0];
959 0 : move16();
960 : }
961 99036 : FOR( i = 0; i < pInCustomLs->num_spk; i++ )
962 : {
963 99036 : IF( pInCustomLs->ls_elevation_fx[i] != 0 )
964 : {
965 13004 : *is_planar = 0;
966 13004 : move16();
967 13004 : BREAK;
968 : }
969 : }
970 13004 : BREAK;
971 0 : case IVAS_AUDIO_CONFIG_MONO:
972 : case IVAS_AUDIO_CONFIG_STEREO:
973 0 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inConfig, azimuth ) ), IVAS_ERR_OK ) )
974 : {
975 0 : return error;
976 : }
977 0 : IF( NE_32( error = getSpeakerElevations_fx( inConfig, elevation ), IVAS_ERR_OK ) )
978 : {
979 0 : return error;
980 : }
981 0 : BREAK;
982 12500 : case IVAS_AUDIO_CONFIG_5_1:
983 : case IVAS_AUDIO_CONFIG_7_1:
984 : case IVAS_AUDIO_CONFIG_5_1_2:
985 : case IVAS_AUDIO_CONFIG_5_1_4:
986 : case IVAS_AUDIO_CONFIG_7_1_4:
987 12500 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inConfig, azimuth ) ), IVAS_ERR_OK ) )
988 : {
989 0 : return error;
990 : }
991 12500 : IF( NE_32( ( error = getSpeakerElevations_fx( inConfig, elevation ) ), IVAS_ERR_OK ) )
992 : {
993 0 : return error;
994 : }
995 12500 : *lfe_idx = LFE_CHANNEL;
996 12500 : move16();
997 :
998 12500 : test();
999 12500 : IF( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
1000 : {
1001 5750 : *is_planar = 1;
1002 5750 : move16();
1003 : }
1004 : ELSE
1005 : {
1006 6750 : *is_planar = 0;
1007 6750 : move16();
1008 : }
1009 12500 : BREAK;
1010 0 : default:
1011 0 : assert( !"Invalid speaker config" );
1012 : return IVAS_ERR_WRONG_PARAMS;
1013 : }
1014 :
1015 25504 : return IVAS_ERR_OK;
1016 : }
1017 848 : static ivas_error initEfap(
1018 : EFAP_WRAPPER *pEfapWrapper,
1019 : AUDIO_CONFIG outConfig,
1020 : const LSSETUP_CUSTOM_STRUCT *pCustomLsOut )
1021 : {
1022 : ivas_error error;
1023 : const Word32 *azimuths; /* Q22 */
1024 : const Word32 *elevations; /* Q22 */
1025 : Word16 numNonLfeChannels;
1026 :
1027 848 : test();
1028 848 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
1029 : {
1030 120 : pEfapWrapper->speakerConfig = IVAS_AUDIO_CONFIG_7_1_4;
1031 120 : move32();
1032 : }
1033 : ELSE
1034 : {
1035 728 : pEfapWrapper->speakerConfig = outConfig;
1036 728 : move32();
1037 : }
1038 848 : pEfapWrapper->pCustomLsSetup = pCustomLsOut;
1039 :
1040 : /* If re-initializing, free existing EFAP handle. */
1041 848 : IF( pEfapWrapper->hEfap != NULL )
1042 : {
1043 47 : efap_free_data_fx( &pEfapWrapper->hEfap );
1044 : }
1045 :
1046 : /* Only initialize EFAP handle if output config is channel-based */
1047 848 : IF( NE_32( getAudioConfigType( pEfapWrapper->speakerConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
1048 : {
1049 195 : pEfapWrapper->hEfap = NULL;
1050 195 : return IVAS_ERR_OK;
1051 : }
1052 :
1053 653 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1054 : {
1055 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 ) )
1056 : {
1057 0 : return error;
1058 : }
1059 : }
1060 : ELSE
1061 : {
1062 454 : IF( NE_32( ( error = getSpeakerAzimuths_fx( pEfapWrapper->speakerConfig, &azimuths ) ), IVAS_ERR_OK ) )
1063 : {
1064 0 : return error;
1065 : }
1066 :
1067 454 : IF( NE_32( ( error = getSpeakerElevations_fx( pEfapWrapper->speakerConfig, &elevations ) ), IVAS_ERR_OK ) )
1068 : {
1069 0 : return error;
1070 : }
1071 :
1072 454 : IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( pEfapWrapper->speakerConfig, &numNonLfeChannels ) ), IVAS_ERR_OK ) )
1073 : {
1074 0 : return error;
1075 : }
1076 454 : IF( NE_32( ( error = efap_init_data_fx( &pEfapWrapper->hEfap, azimuths, elevations, numNonLfeChannels, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) )
1077 : {
1078 0 : return error;
1079 : }
1080 : }
1081 :
1082 653 : return IVAS_ERR_OK;
1083 : }
1084 :
1085 423262 : static ivas_error getEfapGains_fx(
1086 : EFAP_WRAPPER efapWrapper,
1087 : const Word32 azi, /* Q22 */
1088 : const Word32 ele, /* Q22 */
1089 : pan_vector_fx panGains /* Q31 */ )
1090 : {
1091 : pan_vector_fx tmpPanGains; /* tmp pan gain buffer without LFE channels */ /* Q30 */
1092 : Word32 *readPtr;
1093 : Word16 i;
1094 : Word16 lfeCount;
1095 : Word16 numChannels;
1096 : ivas_error error;
1097 :
1098 : /* EFAP returns an array of gains only for non-LFE speakers */
1099 423262 : efap_determine_gains_fx( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
1100 :
1101 : /* Now copy to buffer that includes LFE channels */
1102 423262 : IF( EQ_32( efapWrapper.speakerConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1103 : {
1104 29835 : numChannels = add( efapWrapper.pCustomLsSetup->num_spk, efapWrapper.pCustomLsSetup->num_lfe );
1105 29835 : readPtr = tmpPanGains;
1106 29835 : lfeCount = 0;
1107 29835 : move16();
1108 387823 : FOR( i = 0; i < numChannels; ++i )
1109 : {
1110 357988 : test();
1111 357988 : IF( LT_16( lfeCount, efapWrapper.pCustomLsSetup->num_lfe ) && EQ_16( i, efapWrapper.pCustomLsSetup->lfe_idx[lfeCount] ) )
1112 : {
1113 0 : panGains[i] = 0;
1114 0 : move32();
1115 0 : lfeCount = add( lfeCount, 1 );
1116 : }
1117 : ELSE
1118 : {
1119 357988 : IF( EQ_32( *readPtr, ONE_IN_Q30 ) )
1120 : {
1121 0 : panGains[i] = ONE_IN_Q31;
1122 : }
1123 : ELSE
1124 : {
1125 357988 : panGains[i] = L_shl( *readPtr, 1 );
1126 : }
1127 357988 : move32();
1128 357988 : ++readPtr;
1129 : }
1130 : }
1131 : }
1132 : ELSE
1133 : {
1134 393427 : IF( NE_32( ( error = getAudioConfigNumChannels( efapWrapper.speakerConfig, &numChannels ) ), IVAS_ERR_OK ) )
1135 : {
1136 0 : return error;
1137 : }
1138 :
1139 393427 : readPtr = tmpPanGains;
1140 :
1141 4311225 : FOR( i = 0; i < numChannels; ++i )
1142 : {
1143 3917798 : IF( EQ_16( i, LFE_CHANNEL ) )
1144 : {
1145 363625 : panGains[i] = 0;
1146 363625 : move32();
1147 : }
1148 : ELSE
1149 : {
1150 3554173 : IF( GE_32( *readPtr, ONE_IN_Q30 ) )
1151 : {
1152 14998 : panGains[i] = ONE_IN_Q31;
1153 : }
1154 : ELSE
1155 : {
1156 3539175 : panGains[i] = L_shl( *readPtr, 1 );
1157 : }
1158 :
1159 3554173 : move32();
1160 3554173 : ++readPtr;
1161 : }
1162 : }
1163 : }
1164 :
1165 423262 : return IVAS_ERR_OK;
1166 : }
1167 :
1168 94 : static ivas_error initHeadRotation_fx(
1169 : IVAS_REND_HANDLE hIvasRend )
1170 : {
1171 : Word16 i, crossfade_len;
1172 : Word32 tmp_fx; /* Q31 */
1173 : ivas_error error;
1174 :
1175 : /* Head rotation is enabled by default */
1176 94 : hIvasRend->headRotData.headRotEnabled = 1;
1177 94 : move16();
1178 :
1179 : /* Initialize 5ms crossfade */
1180 94 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
1181 94 : move16();
1182 94 : tmp_fx = Q31_BY_SUB_FRAME_240;
1183 94 : move16();
1184 :
1185 22654 : FOR( i = 0; i < crossfade_len; i++ )
1186 : {
1187 22560 : hIvasRend->headRotData.crossfade_fx[i] = UL_Mpy_32_32( i, tmp_fx );
1188 22560 : move32();
1189 : }
1190 :
1191 : /* Initialize with unit quaternions */
1192 329 : FOR( i = 0; i < hIvasRend->num_subframes; ++i )
1193 : {
1194 235 : hIvasRend->headRotData.headPositions[i] = quaternionInit_fx();
1195 : }
1196 :
1197 94 : hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
1198 94 : move32();
1199 :
1200 94 : IF( ( hIvasRend->headRotData.hOrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ) ) == NULL )
1201 : {
1202 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Orientation tracking" );
1203 : }
1204 :
1205 94 : IF( NE_32( ( error = ivas_orient_trk_Init_fx( hIvasRend->headRotData.hOrientationTracker ) ), IVAS_ERR_OK ) )
1206 : {
1207 0 : return error;
1208 : }
1209 :
1210 94 : return IVAS_ERR_OK;
1211 : }
1212 :
1213 :
1214 666 : static void closeHeadRotation(
1215 : IVAS_REND_HANDLE hIvasRend )
1216 : {
1217 666 : test();
1218 666 : test();
1219 666 : IF( hIvasRend != NULL && hIvasRend->headRotData.headRotEnabled && hIvasRend->headRotData.hOrientationTracker != NULL )
1220 : {
1221 94 : free( hIvasRend->headRotData.hOrientationTracker );
1222 : }
1223 :
1224 666 : return;
1225 : }
1226 :
1227 :
1228 426 : static void initRotMatrix_fx(
1229 : rotation_matrix_fx rot_mat )
1230 : {
1231 : Word16 i;
1232 :
1233 : /* Initialize rotation matrices */
1234 1704 : FOR( i = 0; i < 3; i++ )
1235 : {
1236 1278 : set_zero_fx( rot_mat[i], 3 );
1237 1278 : rot_mat[i][i] = ONE_IN_Q30;
1238 1278 : move32();
1239 : }
1240 :
1241 426 : return;
1242 : }
1243 :
1244 1008 : static void initRotGains_fx(
1245 : rotation_gains_fx rot_gains )
1246 : {
1247 : Word16 i;
1248 :
1249 : /* Set gains to passthrough */
1250 17136 : FOR( i = 0; i < MAX_INPUT_CHANNELS; i++ )
1251 : {
1252 16128 : set16_fx( rot_gains[i], 0, MAX_INPUT_CHANNELS );
1253 16128 : rot_gains[i][i] = ONE_IN_Q14;
1254 16128 : move16();
1255 : }
1256 :
1257 1008 : return;
1258 : }
1259 :
1260 2976 : static void initRotGainsWord32_fx(
1261 : rotation_gains_Word32 rot_gains )
1262 : {
1263 : Word16 i;
1264 :
1265 : /* Set gains to passthrough */
1266 50592 : FOR( i = 0; i < MAX_INPUT_CHANNELS; i++ )
1267 : {
1268 47616 : set32_fx( rot_gains[i], 0, MAX_INPUT_CHANNELS );
1269 47616 : rot_gains[i][i] = ONE_IN_Q30;
1270 47616 : move16();
1271 : }
1272 :
1273 2976 : return;
1274 : }
1275 10297 : static void initRendInputBase_fx(
1276 : input_base *inputBase,
1277 : const AUDIO_CONFIG inConfig,
1278 : const IVAS_REND_InputId id,
1279 : const rendering_context rendCtx,
1280 : Word32 *dataBuf,
1281 : const Word16 dataBufSize )
1282 : {
1283 10297 : inputBase->inConfig = inConfig;
1284 10297 : move32();
1285 10297 : inputBase->id = id;
1286 10297 : move16();
1287 10297 : inputBase->gain_fx = ONE_IN_Q30;
1288 10297 : move32();
1289 10297 : inputBase->ctx = rendCtx;
1290 10297 : inputBase->numNewSamplesPerChannel = 0;
1291 10297 : move32();
1292 :
1293 10297 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
1294 10297 : inputBase->inputBuffer.config.numChannels = 0;
1295 10297 : move16();
1296 10297 : move16();
1297 10297 : inputBase->inputBuffer.data_fx = dataBuf;
1298 10297 : IF( inputBase->inputBuffer.data_fx != NULL )
1299 : {
1300 973 : set32_fx( inputBase->inputBuffer.data_fx, 0, dataBufSize );
1301 : }
1302 :
1303 10297 : return;
1304 : }
1305 :
1306 300852 : static IVAS_ISM_METADATA defaultObjectPosition(
1307 : void )
1308 : {
1309 : IVAS_ISM_METADATA pos;
1310 :
1311 300852 : pos.azimuth_fx = 0;
1312 300852 : move32();
1313 300852 : pos.elevation_fx = 0;
1314 300852 : move32();
1315 300852 : pos.radius_fx = ONE_IN_Q9;
1316 300852 : move16();
1317 300852 : pos.spread_fx = 0;
1318 300852 : move32();
1319 300852 : pos.gainFactor_fx = ONE_IN_Q31;
1320 300852 : move32();
1321 300852 : pos.yaw_fx = 0;
1322 300852 : move32();
1323 300852 : pos.pitch_fx = 0;
1324 300852 : move32();
1325 300852 : return pos;
1326 : }
1327 :
1328 :
1329 947155 : static Word8 checkObjectPositionChanged_fx(
1330 : IVAS_ISM_METADATA *currentPos,
1331 : IVAS_ISM_METADATA *previousPos )
1332 : {
1333 947155 : test();
1334 1555417 : return !( LT_32( L_abs( L_sub( currentPos->azimuth_fx, previousPos->azimuth_fx ) ), EPSILLON_FX ) &&
1335 608262 : LT_32( L_abs( L_sub( currentPos->elevation_fx, previousPos->elevation_fx ) ), EPSILLON_FX ) );
1336 : }
1337 :
1338 4662 : static rendering_context getRendCtx(
1339 : IVAS_REND_HANDLE hIvasRend )
1340 : {
1341 : rendering_context ctx;
1342 :
1343 : /* Note: when refactoring this, always take the ADDRESS of a member of the
1344 : * renderer struct, so that the context stores a POINTER to the member, even
1345 : * if the member is a pointer or handle itself. */
1346 4662 : ctx.pOutConfig = &hIvasRend->outputConfig;
1347 4662 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
1348 4662 : ctx.pCustomLsOut = &hIvasRend->customLsOut;
1349 4662 : ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
1350 4662 : ctx.pHeadRotData = &hIvasRend->headRotData;
1351 4662 : ctx.hhRendererConfig = &hIvasRend->hRendererConfig;
1352 4662 : ctx.pSplitRendBFI = &hIvasRend->splitRendBFI;
1353 4662 : ctx.pSplitRendWrapper = hIvasRend->splitRendWrapper;
1354 4662 : ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
1355 :
1356 4662 : return ctx;
1357 : }
1358 :
1359 :
1360 798 : static TDREND_WRAPPER defaultTdRendWrapper(
1361 : void )
1362 : {
1363 : TDREND_WRAPPER w;
1364 :
1365 798 : w.binaural_latency_ns = 0;
1366 798 : move32();
1367 798 : w.hBinRendererTd = NULL;
1368 798 : w.hHrtfTD = NULL;
1369 :
1370 798 : return w;
1371 : }
1372 :
1373 :
1374 973 : static bool isIoConfigPairSupported(
1375 : const AUDIO_CONFIG inConfig,
1376 : const AUDIO_CONFIG outConfig )
1377 : {
1378 : /* Rendering mono or stereo to binaural is not supported */
1379 973 : test();
1380 973 : test();
1381 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 ) )
1382 : {
1383 0 : return false;
1384 : }
1385 :
1386 : /* If not returned so far, config pair is supported */
1387 973 : return true;
1388 : }
1389 :
1390 1 : static ivas_error initIsmMasaRendering(
1391 : input_ism *inputIsm,
1392 : const Word32 inSampleRate )
1393 : {
1394 : ivas_error error;
1395 : #ifndef FIX_CREND_SIMPLIFY_CODE
1396 : Word16 num_poses;
1397 :
1398 : num_poses = 1;
1399 : move16();
1400 : if ( inputIsm->base.ctx.pSplitRendWrapper != NULL )
1401 : {
1402 : num_poses = inputIsm->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
1403 : move16();
1404 : }
1405 : #endif
1406 :
1407 1 : IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1408 : {
1409 0 : ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
1410 : }
1411 :
1412 : #ifdef FIX_CREND_SIMPLIFY_CODE
1413 1 : ivas_rend_closeCrend_fx( &inputIsm->crendWrapper );
1414 : #else
1415 : ivas_rend_closeCrend_fx( &inputIsm->crendWrapper, num_poses );
1416 : #endif
1417 :
1418 1 : ivas_reverb_close_fx( &inputIsm->hReverb );
1419 :
1420 1 : IF( NE_32( ( error = ivas_omasa_ana_open( &inputIsm->hOMasa, inSampleRate, inputIsm->total_num_objects ) ), IVAS_ERR_OK ) )
1421 : {
1422 0 : return error;
1423 : }
1424 :
1425 1 : return IVAS_ERR_OK;
1426 : }
1427 :
1428 :
1429 426 : static ivas_error setRendInputActiveIsm(
1430 : void *input,
1431 : const AUDIO_CONFIG inConfig,
1432 : const IVAS_REND_InputId id,
1433 : RENDER_CONFIG_DATA *hRendCfg,
1434 : hrtf_handles *hrtfs )
1435 : {
1436 : ivas_error error;
1437 : rendering_context rendCtx;
1438 : AUDIO_CONFIG outConfig;
1439 : input_ism *inputIsm;
1440 : Word16 i;
1441 : Word16 SrcInd[MAX_NUM_TDREND_CHANNELS];
1442 : Word16 num_src;
1443 : Word16 ivas_format;
1444 : #ifndef FIX_CREND_SIMPLIFY_CODE
1445 : Word16 num_poses;
1446 : #endif
1447 :
1448 426 : IF( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
1449 : {
1450 0 : ivas_format = MC_FORMAT;
1451 : }
1452 : ELSE
1453 : {
1454 426 : ivas_format = ISM_FORMAT;
1455 : }
1456 426 : move16();
1457 :
1458 426 : inputIsm = (input_ism *) input;
1459 426 : rendCtx = inputIsm->base.ctx;
1460 426 : outConfig = *rendCtx.pOutConfig;
1461 :
1462 : #ifndef FIX_CREND_SIMPLIFY_CODE
1463 : num_poses = 1;
1464 : move16();
1465 : if ( rendCtx.pSplitRendWrapper != NULL )
1466 : {
1467 : num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
1468 : move16();
1469 : }
1470 : #endif
1471 426 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
1472 : {
1473 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
1474 : }
1475 :
1476 426 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputIsm->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
1477 : {
1478 0 : return error;
1479 : }
1480 426 : initRendInputBase_fx( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData_fx, MAX_BUFFER_LENGTH );
1481 :
1482 426 : inputIsm->firstFrameRendered = FALSE;
1483 426 : move16();
1484 :
1485 426 : inputIsm->currentPos = defaultObjectPosition();
1486 426 : inputIsm->previousPos = defaultObjectPosition();
1487 426 : inputIsm->crendWrapper = NULL;
1488 426 : inputIsm->hReverb = NULL;
1489 426 : inputIsm->tdRendWrapper = defaultTdRendWrapper();
1490 :
1491 426 : initRotMatrix_fx( inputIsm->rot_mat_prev );
1492 :
1493 426 : set_zero_fx( inputIsm->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
1494 :
1495 3408 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
1496 : {
1497 2982 : inputIsm->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
1498 : }
1499 :
1500 426 : inputIsm->hOMasa = NULL;
1501 :
1502 426 : error = IVAS_ERR_OK;
1503 426 : move32();
1504 :
1505 426 : inputIsm->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
1506 :
1507 426 : test();
1508 426 : test();
1509 426 : test();
1510 426 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
1511 40 : {
1512 : #ifdef NONBE_1377_REND_DIRATT_CONF
1513 40 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, inputIsm->object_id, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1514 : #else
1515 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1516 : #endif
1517 : {
1518 0 : return error;
1519 : }
1520 :
1521 40 : Word16 nchan_rend = num_src;
1522 40 : move16();
1523 :
1524 40 : test();
1525 40 : IF( EQ_16( ivas_format, MC_FORMAT ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1526 : {
1527 0 : nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
1528 : }
1529 :
1530 80 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
1531 : {
1532 40 : TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
1533 40 : IF( Src_p != NULL )
1534 : {
1535 40 : IF( Src_p->SrcSpatial_p != NULL )
1536 : {
1537 40 : Src_p->SrcSpatial_p->q_Pos_p = Q31;
1538 40 : move16();
1539 : }
1540 40 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
1541 40 : SrcSpatial_p->q_Pos_p = Q31;
1542 40 : move16();
1543 : }
1544 : }
1545 :
1546 : /* Open TD renderer wrappers */
1547 320 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
1548 : {
1549 : #ifdef NONBE_1377_REND_DIRATT_CONF
1550 280 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->splitTdRendWrappers[i], inConfig, hRendCfg, NULL, *inputIsm->base.ctx.pOutSampleRate, inputIsm->object_id, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1551 : #else
1552 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->splitTdRendWrappers[i], inConfig, hRendCfg, NULL, *inputIsm->base.ctx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1553 : #endif
1554 : {
1555 0 : return error;
1556 : }
1557 :
1558 : /* Assert same delay as main TD renderer */
1559 280 : assert( inputIsm->splitTdRendWrappers[i].binaural_latency_ns == inputIsm->tdRendWrapper.binaural_latency_ns );
1560 :
1561 560 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
1562 : {
1563 280 : TDREND_SRC_t *Src_p = inputIsm->splitTdRendWrappers[i].hBinRendererTd->Sources[SrcInd[nS]];
1564 280 : IF( Src_p != NULL )
1565 : {
1566 280 : IF( Src_p->SrcSpatial_p != NULL )
1567 : {
1568 280 : Src_p->SrcSpatial_p->q_Pos_p = Q31;
1569 280 : move16();
1570 : }
1571 280 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->splitTdRendWrappers[i].hBinRendererTd->Sources[nS]->SrcSpatial_p;
1572 280 : SrcSpatial_p->q_Pos_p = Q31;
1573 280 : move16();
1574 : }
1575 : }
1576 : }
1577 : }
1578 386 : ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
1579 : {
1580 1 : IF( NE_32( ( error = initIsmMasaRendering( inputIsm, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
1581 : {
1582 0 : return error;
1583 : }
1584 : }
1585 : ELSE
1586 : {
1587 : #ifdef NONBE_1377_REND_DIRATT_CONF
1588 385 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, inputIsm->object_id, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1589 : #else
1590 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
1591 : #endif
1592 : {
1593 0 : return error;
1594 : }
1595 :
1596 385 : Word16 nchan_rend = num_src;
1597 385 : move16();
1598 :
1599 385 : test();
1600 385 : IF( EQ_16( ivas_format, MC_FORMAT ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1601 : {
1602 0 : nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
1603 : }
1604 :
1605 770 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
1606 : {
1607 385 : TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
1608 385 : IF( Src_p != NULL )
1609 : {
1610 385 : IF( Src_p->SrcSpatial_p != NULL )
1611 : {
1612 385 : Src_p->SrcSpatial_p->q_Pos_p = Q31;
1613 385 : move16();
1614 : }
1615 385 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
1616 385 : SrcSpatial_p->q_Pos_p = Q31;
1617 385 : move16();
1618 : }
1619 : }
1620 :
1621 385 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
1622 : {
1623 40 : IF( NE_32( ( error = ivas_reverb_open_fx( &( inputIsm->hReverb ), hrtfs->hHrtfStatistics, hRendCfg, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
1624 : {
1625 0 : return error;
1626 : }
1627 : }
1628 345 : ELSE IF( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
1629 : {
1630 : #ifdef FIX_CREND_SIMPLIFY_CODE
1631 40 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputIsm->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics, *rendCtx.pOutSampleRate, 1, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ), IVAS_ERR_OK ) )
1632 : #else
1633 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputIsm->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
1634 : #endif
1635 : {
1636 0 : return error;
1637 : }
1638 : }
1639 : }
1640 :
1641 426 : return IVAS_ERR_OK;
1642 : }
1643 :
1644 2664 : static void clearInputIsm(
1645 : input_ism *inputIsm )
1646 : {
1647 : rendering_context rendCtx;
1648 : #ifdef FIX_CREND_SIMPLIFY_CODE
1649 : Word16 i;
1650 : #else
1651 : Word16 i, num_poses;
1652 :
1653 : num_poses = 1;
1654 : move16();
1655 : if ( inputIsm->base.ctx.pSplitRendWrapper != NULL )
1656 : {
1657 : num_poses = inputIsm->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
1658 : move16();
1659 : }
1660 : #endif
1661 :
1662 2664 : rendCtx = inputIsm->base.ctx;
1663 :
1664 2664 : freeInputBaseBufferData_fx( &inputIsm->base.inputBuffer.data_fx );
1665 :
1666 2664 : initRendInputBase_fx( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
1667 :
1668 : /* Free input's internal handles */
1669 : #ifdef FIX_CREND_SIMPLIFY_CODE
1670 2664 : ivas_rend_closeCrend_fx( &inputIsm->crendWrapper );
1671 : #else
1672 : ivas_rend_closeCrend_fx( &inputIsm->crendWrapper, num_poses );
1673 : #endif
1674 :
1675 2664 : ivas_reverb_close_fx( &inputIsm->hReverb );
1676 :
1677 2664 : IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1678 : {
1679 425 : ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
1680 : }
1681 :
1682 21312 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
1683 : {
1684 18648 : ivas_td_binaural_close_fx( &inputIsm->splitTdRendWrappers[i].hBinRendererTd );
1685 : }
1686 :
1687 2664 : ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
1688 :
1689 2664 : return;
1690 : }
1691 :
1692 62 : static void copyLsConversionMatrixToPanMatrix_fx(
1693 : const LS_CONVERSION_MATRIX_FX *lsConvMatrix,
1694 : pan_matrix_fx panMatrix )
1695 : {
1696 : Word16 i;
1697 : Word16 inCh, outCh;
1698 : Word16 numNonZeroGains;
1699 : Word16 numColumns;
1700 : Word16 tmp_e, tmp;
1701 : /* Index 0 is special and describes the following values */
1702 62 : numNonZeroGains = lsConvMatrix[0].index;
1703 62 : move16();
1704 62 : numColumns = (Word16) lsConvMatrix[0].value;
1705 62 : move16();
1706 :
1707 654 : FOR( i = 1; i < numNonZeroGains + 1; ++i )
1708 : {
1709 592 : tmp = BASOP_Util_Divide1616_Scale( lsConvMatrix[i].index, numColumns, &tmp_e );
1710 592 : move16();
1711 592 : tmp = shr( tmp, add( 15, negate( tmp_e ) ) );
1712 592 : move16();
1713 592 : inCh = tmp;
1714 592 : move16();
1715 : // inCh = lsConvMatrix[i].index / numColumns;
1716 592 : outCh = lsConvMatrix[i].index % numColumns;
1717 592 : move16();
1718 :
1719 592 : IF( EQ_32( lsConvMatrix[i].value, ONE_IN_Q30 ) )
1720 : {
1721 492 : panMatrix[inCh][outCh] = ONE_IN_Q31;
1722 : }
1723 : ELSE
1724 : {
1725 100 : panMatrix[inCh][outCh] = L_shl( lsConvMatrix[i].value, 1 ); /* Q30 + Q1 = Q31 */
1726 : }
1727 592 : move32();
1728 : }
1729 :
1730 62 : return;
1731 : }
1732 :
1733 1101 : static void setZeroPanMatrix_fx(
1734 : pan_matrix_fx panMatrix )
1735 : {
1736 : Word16 i;
1737 :
1738 18717 : FOR( i = 0; i < MAX_INPUT_CHANNELS; ++i )
1739 : {
1740 17616 : set32_fx( panMatrix[i], 0, MAX_OUTPUT_CHANNELS );
1741 : }
1742 :
1743 1101 : return;
1744 : }
1745 :
1746 : /* Note: this only sets non-zero elements, call setZeroPanMatrix() to init first. */
1747 91 : static void fillIdentityPanMatrix_fx(
1748 : pan_matrix_fx panMatrix )
1749 : {
1750 : Word16 i;
1751 :
1752 1547 : FOR( i = 0; i < s_min( MAX_INPUT_CHANNELS, MAX_OUTPUT_CHANNELS ); ++i )
1753 : {
1754 1456 : panMatrix[i][i] = ONE_IN_Q31;
1755 1456 : move32();
1756 : }
1757 :
1758 91 : return;
1759 : }
1760 :
1761 29 : static ivas_error initMcPanGainsWithIdentMatrix(
1762 : input_mc *inputMc )
1763 : {
1764 29 : fillIdentityPanMatrix_fx( inputMc->panGains_fx );
1765 :
1766 29 : return IVAS_ERR_OK;
1767 : }
1768 :
1769 100 : static ivas_error initMcPanGainsWithConversionMapping_fx(
1770 : input_mc *inputMc,
1771 : const AUDIO_CONFIG outConfig )
1772 : {
1773 : AUDIO_CONFIG ivasConfigIn, ivasConfigOut;
1774 : Word16 i;
1775 :
1776 100 : ivasConfigIn = inputMc->base.inConfig;
1777 100 : move32();
1778 100 : ivasConfigOut = outConfig;
1779 100 : move32();
1780 :
1781 : /* Find conversion mapping for current I/O config pair.
1782 : * Stay with default panning matrix if conversion_matrix is NULL */
1783 2580 : FOR( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; ++i )
1784 : {
1785 2580 : test();
1786 2580 : IF( EQ_32( ls_conversion_mapping_fx[i].input_config, ivasConfigIn ) && EQ_32( ls_conversion_mapping_fx[i].output_config, ivasConfigOut ) )
1787 : {
1788 : /* Mapping found with valid matrix - copy */
1789 100 : IF( ls_conversion_mapping_fx[i].conversion_matrix_fx != NULL )
1790 : {
1791 62 : copyLsConversionMatrixToPanMatrix_fx( ls_conversion_mapping_fx[i].conversion_matrix_fx, inputMc->panGains_fx );
1792 : }
1793 : /* Mapping found with NULL matrix - use identity matrix */
1794 : ELSE
1795 : {
1796 38 : fillIdentityPanMatrix_fx( inputMc->panGains_fx );
1797 : }
1798 :
1799 100 : return IVAS_ERR_OK;
1800 : }
1801 : }
1802 :
1803 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" );
1804 : }
1805 :
1806 180 : static ivas_error initMcPanGainsWithEfap_fx(
1807 : input_mc *inputMc,
1808 : const AUDIO_CONFIG outConfig )
1809 : {
1810 : Word16 i;
1811 : Word16 numNonLfeInChannels;
1812 : Word16 inLfeChIdx, outChIdx;
1813 : const Word32 *spkAzi, *spkEle; /* Q22 */
1814 : ivas_error error;
1815 :
1816 180 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1817 : {
1818 33 : IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ), IVAS_ERR_OK ) )
1819 : {
1820 0 : return error;
1821 : }
1822 :
1823 33 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi ) ), IVAS_ERR_OK ) )
1824 : {
1825 0 : return error;
1826 : }
1827 :
1828 33 : IF( NE_32( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle ) ), IVAS_ERR_OK ) )
1829 : {
1830 0 : return error;
1831 : }
1832 :
1833 33 : inLfeChIdx = LFE_CHANNEL;
1834 33 : move16();
1835 : }
1836 : ELSE
1837 : {
1838 147 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
1839 147 : move16();
1840 147 : spkAzi = inputMc->customLsInput.ls_azimuth_fx;
1841 147 : move32();
1842 147 : spkEle = inputMc->customLsInput.ls_elevation_fx;
1843 147 : move32();
1844 147 : inLfeChIdx = -1;
1845 147 : move16();
1846 147 : if ( inputMc->customLsInput.num_lfe > 0 )
1847 : {
1848 0 : inLfeChIdx = inputMc->customLsInput.lfe_idx[0];
1849 0 : move16();
1850 : }
1851 : }
1852 180 : outChIdx = 0;
1853 180 : move16();
1854 1257 : FOR( i = 0; i < numNonLfeInChannels; ++i )
1855 : {
1856 1077 : IF( EQ_16( i, inLfeChIdx ) )
1857 : {
1858 15 : outChIdx = add( outChIdx, 1 );
1859 : }
1860 :
1861 1077 : IF( NE_32( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains_fx[outChIdx] ) ), IVAS_ERR_OK ) )
1862 : {
1863 0 : return error;
1864 : }
1865 1077 : outChIdx = add( outChIdx, 1 );
1866 : }
1867 :
1868 180 : test();
1869 180 : test();
1870 180 : IF( NE_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && inLfeChIdx >= 0 )
1871 : {
1872 12 : inputMc->panGains_fx[inLfeChIdx][LFE_CHANNEL] = ONE_IN_Q31;
1873 12 : move32();
1874 : }
1875 168 : ELSE IF( inputMc->base.ctx.pCustomLsOut->num_lfe > 0 && inLfeChIdx >= 0 )
1876 : {
1877 0 : inputMc->panGains_fx[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = ONE_IN_Q31;
1878 0 : move32();
1879 : }
1880 180 : return IVAS_ERR_OK;
1881 : }
1882 :
1883 2507531 : static ivas_error getRendInputNumChannels(
1884 : const void *rendInput,
1885 : Word16 *numInChannels )
1886 : {
1887 : /* Using a void pointer for this function to be reusable for any input type (input_ism, input_mc, input_sba).
1888 : Assumptions: - input_base is always the first member in the input struct */
1889 :
1890 : ivas_error error;
1891 : const input_base *pInputBase;
1892 : const input_mc *pInputMc;
1893 :
1894 2507531 : pInputBase = (const input_base *) rendInput;
1895 :
1896 2507531 : IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1897 : {
1898 215975 : pInputMc = (const input_mc *) rendInput;
1899 215975 : *numInChannels = add( pInputMc->customLsInput.num_spk, pInputMc->customLsInput.num_lfe );
1900 215975 : move16();
1901 : }
1902 : ELSE
1903 : {
1904 2291556 : IF( NE_32( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ), IVAS_ERR_OK ) )
1905 : {
1906 0 : return error;
1907 : }
1908 : }
1909 :
1910 2507531 : return IVAS_ERR_OK;
1911 : }
1912 :
1913 16 : static ivas_error initMcPanGainsWithMonoOut_fx(
1914 : input_mc *inputMc )
1915 : {
1916 : Word16 i;
1917 : Word16 numInChannels;
1918 : Word16 readIdx;
1919 : Word16 writeIdx;
1920 : bool skipSideSpeakers;
1921 : ivas_error error;
1922 :
1923 16 : IF( NE_32( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ), IVAS_ERR_OK ) )
1924 : {
1925 0 : return error;
1926 : }
1927 :
1928 16 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
1929 : {
1930 0 : FOR( i = 0; i < numInChannels; ++i )
1931 : {
1932 : /* It's OK to also set gain 1 for LFE input channels here.
1933 : * Correct LFE handling will be applied within updateMcPanGains() */
1934 0 : inputMc->panGains_fx[i][0] = ONE_IN_Q31;
1935 0 : move32();
1936 : }
1937 : }
1938 16 : ELSE IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_STEREO ) )
1939 : {
1940 : /* Special case for STEREO to MONO: Passive downmix (L+R)/2 */
1941 4 : inputMc->panGains_fx[0][0] = ONE_IN_Q30; // Q31(of 0.5)
1942 4 : move32();
1943 4 : inputMc->panGains_fx[1][0] = ONE_IN_Q30; // Q31(of 0.5)
1944 4 : move32();
1945 : }
1946 : ELSE
1947 : {
1948 : /* ls_conversion_cicpX_stereo contains gains for side speakers.
1949 : * These should be skipped with 5.1+X inputs. */
1950 12 : skipSideSpeakers = false;
1951 12 : move16();
1952 12 : test();
1953 12 : if ( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) )
1954 : {
1955 6 : skipSideSpeakers = true;
1956 6 : move16();
1957 : }
1958 12 : readIdx = 0;
1959 12 : move16();
1960 120 : FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx )
1961 : {
1962 108 : test();
1963 108 : IF( ( skipSideSpeakers ) && EQ_16( readIdx, 4 ) )
1964 : {
1965 : /* Skip gains for side speakers in lookup table */
1966 6 : readIdx = add( readIdx, 2 );
1967 : }
1968 :
1969 108 : IF( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) )
1970 : {
1971 48 : inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
1972 : }
1973 : ELSE
1974 : {
1975 60 : inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 );
1976 : }
1977 108 : move32();
1978 :
1979 108 : IF( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) )
1980 : {
1981 48 : inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
1982 : }
1983 : ELSE
1984 : {
1985 60 : inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 ); // Q31
1986 : }
1987 108 : move32();
1988 108 : readIdx = add( readIdx, 1 );
1989 : }
1990 : }
1991 :
1992 16 : return IVAS_ERR_OK;
1993 : }
1994 :
1995 12 : static ivas_error initMcPanGainsWithStereoLookup_fx(
1996 : input_mc *inputMc )
1997 : {
1998 : Word16 readIdx;
1999 : Word16 writeIdx;
2000 : bool skipSideSpeakers;
2001 : Word16 numInChannels;
2002 : ivas_error error;
2003 :
2004 : /* Special case - MONO input.
2005 : * Use gains for center CICP speaker and return early. */
2006 12 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) )
2007 : {
2008 0 : inputMc->panGains_fx[0][0] = L_shl( ls_conversion_cicpX_stereo_fx[2][0], 1 ); /* Q30 + Q1 = Q31 */
2009 0 : move32();
2010 0 : inputMc->panGains_fx[0][1] = L_shl( ls_conversion_cicpX_stereo_fx[2][1], 1 ); /* Q30 + Q1 = Q31 */
2011 0 : move32();
2012 0 : return IVAS_ERR_OK;
2013 : }
2014 :
2015 : /* ls_conversion_cicpX_stereo contains gains for side speakers.
2016 : * These should be skipped with 5.1+X inputs. */
2017 12 : skipSideSpeakers = false;
2018 12 : move16();
2019 12 : test();
2020 12 : if ( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) )
2021 : {
2022 6 : skipSideSpeakers = true;
2023 6 : move16();
2024 : }
2025 :
2026 12 : IF( NE_32( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ), IVAS_ERR_OK ) )
2027 : {
2028 0 : return error;
2029 : }
2030 12 : readIdx = 0;
2031 12 : move16();
2032 120 : FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx )
2033 : {
2034 108 : test();
2035 108 : IF( skipSideSpeakers && EQ_16( readIdx, 4 ) )
2036 : {
2037 : /* Skip gains for side speakers in lookup table */
2038 6 : readIdx = add( readIdx, 2 );
2039 : }
2040 :
2041 108 : IF( EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][0], ONE_IN_Q30 ) )
2042 : {
2043 12 : inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
2044 : }
2045 : ELSE
2046 : {
2047 96 : inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_stereo_fx[readIdx][0], 1 ); /* Q30 + Q1 = Q31 */
2048 : }
2049 108 : move32();
2050 :
2051 108 : IF( EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][1], ONE_IN_Q30 ) )
2052 : {
2053 12 : inputMc->panGains_fx[writeIdx][1] = ONE_IN_Q31;
2054 : }
2055 : ELSE
2056 : {
2057 96 : inputMc->panGains_fx[writeIdx][1] = L_shl( ls_conversion_cicpX_stereo_fx[readIdx][1], 1 ); /* Q30 + Q1 = Q31 */
2058 : }
2059 108 : move32();
2060 108 : readIdx = add( readIdx, 1 );
2061 : }
2062 :
2063 12 : return IVAS_ERR_OK;
2064 : }
2065 :
2066 :
2067 : /* Returns 1 (true) if configs A and B are equal, otherwise returns 0 (false).
2068 : * If both configs are custom LS layouts, layout details are compared to determine equality. */
2069 342 : static bool configsAreEqual(
2070 : const AUDIO_CONFIG configA,
2071 : const LSSETUP_CUSTOM_STRUCT customLsA,
2072 : const AUDIO_CONFIG configB,
2073 : const LSSETUP_CUSTOM_STRUCT customLsB )
2074 : {
2075 : Word16 i;
2076 :
2077 : /* Both input and output are custom LS - compare structs */
2078 342 : test();
2079 342 : IF( EQ_32( configA, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && EQ_32( configB, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2080 : {
2081 18 : IF( NE_16( customLsA.num_spk, customLsB.num_spk ) )
2082 : {
2083 15 : return false;
2084 : }
2085 :
2086 3 : IF( NE_16( customLsA.num_lfe, customLsB.num_lfe ) )
2087 : {
2088 0 : return false;
2089 : }
2090 :
2091 3 : IF( NE_16( customLsA.is_planar_setup, customLsB.is_planar_setup ) )
2092 : {
2093 0 : return false;
2094 : }
2095 :
2096 39 : FOR( i = 0; i < customLsA.num_spk; ++i )
2097 : {
2098 : /* Compare to nearest degree (hence the int16_t cast) */
2099 36 : test();
2100 36 : IF( NE_32( customLsA.ls_azimuth_fx[i], customLsB.ls_azimuth_fx[i] ) ||
2101 : NE_32( customLsA.ls_elevation_fx[i], customLsB.ls_elevation_fx[i] ) )
2102 : {
2103 0 : return false;
2104 : }
2105 : }
2106 3 : FOR( i = 0; i < customLsA.num_lfe; ++i )
2107 : {
2108 0 : IF( NE_16( customLsA.lfe_idx[i], customLsB.lfe_idx[i] ) )
2109 : {
2110 0 : return false;
2111 : }
2112 : }
2113 :
2114 3 : return true;
2115 : }
2116 :
2117 : /* Otherwise it's enough to compare config enums */
2118 324 : return configA == configB;
2119 : }
2120 342 : static ivas_error updateLfePanGainsForMcOut(
2121 : input_mc *inputMc,
2122 : const AUDIO_CONFIG outConfig )
2123 : {
2124 : Word16 i, numLfeIn, numOutChannels;
2125 : ivas_error error;
2126 342 : error = IVAS_ERR_OK;
2127 342 : move32();
2128 :
2129 : /* If panning is not required, simply return */
2130 342 : IF( !inputMc->lfeRouting.pan_lfe )
2131 : {
2132 342 : return error;
2133 : }
2134 :
2135 0 : numLfeIn = getNumLfeChannels( inputMc );
2136 :
2137 0 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2138 : {
2139 0 : numOutChannels = add( inputMc->base.ctx.pCustomLsOut->num_spk, inputMc->base.ctx.pCustomLsOut->num_lfe );
2140 : }
2141 : ELSE
2142 : {
2143 0 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
2144 : {
2145 0 : return error;
2146 : }
2147 : }
2148 :
2149 0 : FOR( i = 0; i < numLfeIn; i++ )
2150 : {
2151 : /* panning gains */
2152 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 ) )
2153 : {
2154 0 : return error;
2155 : }
2156 :
2157 : /* linear input gain */
2158 0 : v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], numOutChannels ); /* Q31 */
2159 : }
2160 :
2161 0 : return error;
2162 : }
2163 90 : static ivas_error updateLfePanGainsForAmbiOut(
2164 : input_mc *inputMc,
2165 : const AUDIO_CONFIG outConfig )
2166 : {
2167 : Word16 i;
2168 : Word16 numLfeIn, outAmbiOrder;
2169 : ivas_error error;
2170 90 : error = IVAS_ERR_OK;
2171 90 : move32();
2172 :
2173 : /* If panning is not required, simply return */
2174 90 : IF( !inputMc->lfeRouting.pan_lfe )
2175 : {
2176 90 : return error;
2177 : }
2178 :
2179 0 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ), IVAS_ERR_OK ) )
2180 : {
2181 0 : return error;
2182 : }
2183 :
2184 0 : numLfeIn = getNumLfeChannels( inputMc );
2185 0 : move16();
2186 0 : FOR( i = 0; i < numLfeIn; i++ )
2187 : {
2188 : /* panning gains */
2189 0 : ivas_dirac_dec_get_response_fx( inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i], outAmbiOrder, Q29 );
2190 :
2191 : /* linear input gain */
2192 0 : v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS ); /* Q31 */
2193 : }
2194 :
2195 0 : return error;
2196 : }
2197 342 : static ivas_error updateMcPanGainsForMcOut(
2198 : input_mc *inputMc,
2199 : const AUDIO_CONFIG outConfig )
2200 : {
2201 : ivas_error error;
2202 :
2203 : /* "if" conditions below realize the following mapping:
2204 :
2205 : If in == out, use identity matrix, otherwise follow the table:
2206 : +-----------+-------------+---------------+-----------+--------------------+
2207 : | in\out | MONO | STEREO | custom LS | other |
2208 : +-----------+-------------+---------------+-----------+--------------------+
2209 : | MONO | mono out | EFAP | EFAP | EFAP |
2210 : | custom LS | mono out | EFAP | EFAP | EFAP |
2211 : | other | mono lookup | stereo lookup | EFAP | conversion mapping |
2212 : +-----------+-------------+---------------+-----------+--------------------+
2213 : */
2214 :
2215 342 : test();
2216 342 : test();
2217 342 : IF( configsAreEqual( inputMc->base.inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ) )
2218 : {
2219 29 : error = initMcPanGainsWithIdentMatrix( inputMc );
2220 : }
2221 313 : ELSE IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ||
2222 : EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) ||
2223 : EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2224 : {
2225 185 : test();
2226 185 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) && ( inputMc->nonDiegeticPan ) )
2227 : {
2228 5 : IF( EQ_32( inputMc->nonDiegeticPanGain_fx, ONE_IN_Q31 ) )
2229 : {
2230 1 : inputMc->panGains_fx[0][0] = ONE_IN_Q31;
2231 : }
2232 : ELSE
2233 : {
2234 4 : inputMc->panGains_fx[0][0] = L_add( L_shr( inputMc->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 /* 0.5f in Q31 */ ); /* Q31 */
2235 : }
2236 5 : move32();
2237 5 : inputMc->panGains_fx[0][1] = L_sub( ONE_IN_Q31, inputMc->panGains_fx[0][0] );
2238 5 : move32();
2239 5 : error = IVAS_ERR_OK;
2240 5 : move32();
2241 : }
2242 : ELSE
2243 : {
2244 180 : error = initMcPanGainsWithEfap_fx( inputMc, outConfig );
2245 : }
2246 : }
2247 128 : ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MONO ) )
2248 : {
2249 16 : error = initMcPanGainsWithMonoOut_fx( inputMc );
2250 : }
2251 112 : ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_STEREO ) )
2252 : {
2253 12 : error = initMcPanGainsWithStereoLookup_fx( inputMc );
2254 : }
2255 : ELSE /* default */
2256 : {
2257 100 : error = initMcPanGainsWithConversionMapping_fx( inputMc, outConfig );
2258 : }
2259 :
2260 : /* check for errors from above block */
2261 342 : IF( NE_32( error, IVAS_ERR_OK ) )
2262 : {
2263 0 : return error;
2264 : }
2265 :
2266 : /* update LFE panning */
2267 342 : error = updateLfePanGainsForMcOut( inputMc, outConfig );
2268 :
2269 342 : return error;
2270 : }
2271 90 : static ivas_error updateMcPanGainsForAmbiOut(
2272 : input_mc *inputMc,
2273 : const AUDIO_CONFIG outConfig )
2274 : {
2275 : Word16 ch_in, ch_out, lfeIdx, i;
2276 : Word16 numNonLfeInChannels, outAmbiOrder;
2277 : const Word32 *spkAzi_fx, *spkEle_fx; /* Q22 */
2278 : ivas_error error;
2279 :
2280 90 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ), IVAS_ERR_OK ) )
2281 : {
2282 0 : return error;
2283 : }
2284 :
2285 90 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2286 : {
2287 54 : IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ), IVAS_ERR_OK ) )
2288 : {
2289 0 : return error;
2290 : }
2291 :
2292 54 : IF( NE_32( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi_fx ) ), IVAS_ERR_OK ) )
2293 : {
2294 0 : return error;
2295 : }
2296 :
2297 54 : IF( NE_32( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle_fx ) ), IVAS_ERR_OK ) )
2298 : {
2299 0 : return error;
2300 : }
2301 54 : ch_in = 0;
2302 54 : move16();
2303 372 : FOR( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out )
2304 : {
2305 318 : IF( EQ_16( ch_in, LFE_CHANNEL ) )
2306 : {
2307 36 : ch_out = add( ch_out, 1 );
2308 : }
2309 318 : move16();
2310 318 : move16(); // move for typecasting Word32 to Word16
2311 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 );
2312 5406 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
2313 : {
2314 5088 : Word32 temp = inputMc->panGains_fx[ch_out][i];
2315 5088 : move32();
2316 :
2317 5088 : IF( GE_32( L_abs( temp ), ONE_IN_Q29 ) )
2318 : {
2319 324 : IF( temp > 0 )
2320 : {
2321 318 : inputMc->panGains_fx[ch_out][i] = ONE_IN_Q31;
2322 318 : move32();
2323 : }
2324 : ELSE
2325 : {
2326 6 : inputMc->panGains_fx[ch_out][i] = L_negate( ONE_IN_Q31 );
2327 6 : move32();
2328 : }
2329 : }
2330 : ELSE
2331 : {
2332 4764 : inputMc->panGains_fx[ch_out][i] = L_shl( temp, 2 ); /* Q29 + Q2 = Q31 */
2333 4764 : move32();
2334 : }
2335 : }
2336 318 : ch_in = add( ch_in, 1 );
2337 : }
2338 : }
2339 : ELSE
2340 : {
2341 36 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
2342 36 : move16();
2343 36 : spkAzi_fx = inputMc->customLsInput.ls_azimuth_fx;
2344 36 : move32();
2345 36 : spkEle_fx = inputMc->customLsInput.ls_elevation_fx;
2346 36 : move32();
2347 36 : ch_in = 0;
2348 36 : move16();
2349 270 : FOR( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out )
2350 : {
2351 234 : FOR( lfeIdx = 0; lfeIdx < inputMc->customLsInput.num_lfe; ++lfeIdx )
2352 : {
2353 0 : IF( EQ_16( inputMc->customLsInput.lfe_idx[lfeIdx], ch_in ) )
2354 : {
2355 0 : ch_out = add( ch_out, 1 );
2356 0 : BREAK;
2357 : }
2358 : }
2359 :
2360 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 );
2361 3978 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
2362 : {
2363 3744 : Word32 temp = inputMc->panGains_fx[ch_out][i];
2364 3744 : move32();
2365 3744 : IF( GE_32( L_abs( temp ), ONE_IN_Q29 ) )
2366 : {
2367 240 : IF( temp > 0 )
2368 : {
2369 234 : inputMc->panGains_fx[ch_out][i] = ONE_IN_Q31;
2370 234 : move32();
2371 : }
2372 : ELSE
2373 : {
2374 6 : inputMc->panGains_fx[ch_out][i] = L_negate( ONE_IN_Q31 );
2375 6 : move32();
2376 : }
2377 : }
2378 : ELSE
2379 : {
2380 3504 : inputMc->panGains_fx[ch_out][i] = L_shl( temp, 2 ); /* Q29 + Q2 = Q31 */
2381 3504 : move32();
2382 : }
2383 : }
2384 234 : ch_in = add( ch_in, 1 );
2385 : }
2386 : }
2387 :
2388 : /* update LFE panning */
2389 90 : IF( NE_32( ( error = updateLfePanGainsForAmbiOut( inputMc, outConfig ) ), IVAS_ERR_OK ) )
2390 : {
2391 0 : return error;
2392 : }
2393 :
2394 90 : return IVAS_ERR_OK;
2395 : }
2396 477 : static ivas_error updateMcPanGains(
2397 : input_mc *inputMc,
2398 : const AUDIO_CONFIG outConfig )
2399 : {
2400 : Word16 i;
2401 : ivas_error error;
2402 :
2403 : /* Reset to all zeros - some functions below only write non-zero elements. */
2404 477 : setZeroPanMatrix_fx( inputMc->panGains_fx );
2405 :
2406 477 : error = IVAS_ERR_OK;
2407 477 : move32();
2408 477 : SWITCH( getAudioConfigType( outConfig ) )
2409 : {
2410 254 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2411 254 : error = updateMcPanGainsForMcOut( inputMc, outConfig );
2412 254 : BREAK;
2413 90 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2414 90 : error = updateMcPanGainsForAmbiOut( inputMc, outConfig );
2415 90 : BREAK;
2416 132 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2417 : SWITCH( outConfig )
2418 : {
2419 44 : case IVAS_AUDIO_CONFIG_BINAURAL:
2420 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
2421 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
2422 44 : BREAK; /* Do nothing */
2423 88 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2424 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2425 : /* Prepare rendering to intermediate format */
2426 88 : error = updateMcPanGainsForMcOut( inputMc, IVAS_AUDIO_CONFIG_7_1_4 );
2427 88 : BREAK;
2428 0 : default:
2429 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2430 : }
2431 132 : BREAK;
2432 1 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2433 1 : BREAK; /* Do nothing */
2434 0 : default:
2435 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2436 : }
2437 : /* Check error here to keep switch statement more compact */
2438 477 : IF( NE_32( error, IVAS_ERR_OK ) )
2439 : {
2440 0 : return error;
2441 : }
2442 :
2443 : /* Copy LFE routing to pan gains array */
2444 477 : IF( EQ_16( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2445 : {
2446 210 : FOR( i = 0; i < inputMc->customLsInput.num_lfe; ++i )
2447 : {
2448 0 : Copy32( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->panGains_fx[inputMc->customLsInput.lfe_idx[i]], IVAS_MAX_OUTPUT_CHANNELS );
2449 : }
2450 : }
2451 : ELSE
2452 : {
2453 : /* For code simplicity, always copy LFE gains. If config has no LFE, gains will be zero anyway. */
2454 267 : Copy32( inputMc->lfeRouting.lfePanMtx_fx[0], inputMc->panGains_fx[LFE_CHANNEL], IVAS_MAX_OUTPUT_CHANNELS );
2455 : }
2456 :
2457 477 : return IVAS_ERR_OK;
2458 : }
2459 :
2460 113253 : static ivas_error initMcBinauralRendering(
2461 : input_mc *inputMc,
2462 : const AUDIO_CONFIG inConfig,
2463 : const AUDIO_CONFIG outConfig,
2464 : RENDER_CONFIG_DATA *hRendCfg,
2465 : IVAS_DEC_HRTF_CREND_HANDLE hMixconv,
2466 : HRTFS_STATISTICS_HANDLE hHrtfStatistics,
2467 : uint8_t reconfigureFlag )
2468 : {
2469 : ivas_error error;
2470 : Word32 binauralDelayNs;
2471 : Word32 outSampleRate;
2472 : Word8 useTDRend;
2473 : #ifdef FIX_CREND_SIMPLIFY_CODE
2474 : Word16 i;
2475 : #else
2476 : Word16 i, num_poses;
2477 :
2478 : num_poses = 1;
2479 : move16();
2480 : if ( inputMc->base.ctx.pSplitRendWrapper != NULL )
2481 : {
2482 : num_poses = inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
2483 : move16();
2484 : }
2485 : #endif
2486 :
2487 : /* Allocate TD binaural renderer for custom loudspeaker layouts (regardless of headrotation)
2488 : or planar MC layouts with headrotation, CREND for the rest */
2489 113253 : useTDRend = FALSE;
2490 113253 : move16();
2491 113253 : IF( NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
2492 : {
2493 75502 : test();
2494 75502 : test();
2495 75502 : test();
2496 75502 : IF( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
2497 : {
2498 16931 : useTDRend = TRUE;
2499 16931 : move16();
2500 : }
2501 58571 : ELSE IF( ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_16( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) &&
2502 : ( inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2503 : {
2504 18408 : useTDRend = TRUE;
2505 18408 : move16();
2506 : }
2507 : }
2508 :
2509 : /* if TD renderer was open and we need to use CREND, close it */
2510 113253 : test();
2511 113253 : IF( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) )
2512 : {
2513 132 : ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
2514 : }
2515 :
2516 113253 : IF( !reconfigureFlag || !useTDRend )
2517 : {
2518 623568 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2519 : {
2520 545622 : IF( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
2521 : {
2522 0 : ivas_td_binaural_close_fx( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
2523 : }
2524 : }
2525 : }
2526 :
2527 : /* if we need to use TD renderer and CREND was open, close it */
2528 113253 : IF( useTDRend )
2529 : {
2530 : #ifdef FIX_CREND_SIMPLIFY_CODE
2531 35339 : ivas_rend_closeCrend_fx( &inputMc->crendWrapper );
2532 : #else
2533 : ivas_rend_closeCrend_fx( &inputMc->crendWrapper, num_poses );
2534 : #endif
2535 : }
2536 :
2537 113253 : test();
2538 113253 : test();
2539 113253 : test();
2540 113253 : IF( !reconfigureFlag || ( !useTDRend && NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && inputMc->hReverb != NULL ) )
2541 : {
2542 132 : ivas_reverb_close_fx( &inputMc->hReverb );
2543 : }
2544 :
2545 113253 : test();
2546 113253 : test();
2547 113253 : IF( !reconfigureFlag || ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && !inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2548 : {
2549 19638 : IF( inputMc->efapInWrapper.hEfap != NULL )
2550 : {
2551 36 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2552 : }
2553 : }
2554 :
2555 113253 : outSampleRate = *inputMc->base.ctx.pOutSampleRate;
2556 113253 : move32();
2557 :
2558 113253 : test();
2559 113253 : test();
2560 113253 : IF( useTDRend && inputMc->tdRendWrapper.hBinRendererTd == NULL )
2561 32 : {
2562 : Word16 SrcInd[MAX_NUM_TDREND_CHANNELS];
2563 : Word16 num_src;
2564 : #ifdef NONBE_1377_REND_DIRATT_CONF
2565 32 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, 0, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
2566 : #else
2567 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
2568 : #endif
2569 : {
2570 0 : return error;
2571 : }
2572 32 : Word16 nchan_rend = num_src;
2573 32 : move16();
2574 :
2575 32 : test();
2576 32 : IF( ( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ) && NE_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
2577 : {
2578 8 : nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
2579 : }
2580 236 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
2581 : {
2582 204 : TDREND_SRC_t *Src_p = inputMc->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
2583 204 : IF( Src_p != NULL )
2584 : {
2585 204 : IF( Src_p->SrcSpatial_p != NULL )
2586 : {
2587 204 : Src_p->SrcSpatial_p->q_Pos_p = 31;
2588 204 : move16();
2589 : }
2590 204 : IF( inputMc->tdRendWrapper.hBinRendererTd->Sources[nS] != NULL )
2591 : {
2592 204 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputMc->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
2593 204 : SrcSpatial_p->q_Pos_p = 31;
2594 204 : move16();
2595 : }
2596 : }
2597 : }
2598 :
2599 32 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
2600 : {
2601 : /* Open TD renderer wrappers */
2602 0 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2603 : {
2604 : #ifdef NONBE_1377_REND_DIRATT_CONF
2605 0 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->splitTdRendWrappers[i], inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, 0, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
2606 : #else
2607 : IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->splitTdRendWrappers[i], inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
2608 : #endif
2609 : {
2610 0 : return error;
2611 : }
2612 :
2613 : /* Assert same delay as main TD renderer */
2614 0 : assert( inputMc->splitTdRendWrappers[i].binaural_latency_ns == inputMc->tdRendWrapper.binaural_latency_ns );
2615 :
2616 0 : FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
2617 : {
2618 0 : TDREND_SRC_t *Src_p = inputMc->splitTdRendWrappers[i].hBinRendererTd->Sources[SrcInd[nS]];
2619 0 : IF( Src_p != NULL )
2620 : {
2621 0 : IF( Src_p->SrcSpatial_p != NULL )
2622 : {
2623 0 : Src_p->SrcSpatial_p->q_Pos_p = 31;
2624 0 : move16();
2625 : }
2626 0 : IF( inputMc->splitTdRendWrappers[i].hBinRendererTd->Sources[nS] != NULL )
2627 : {
2628 0 : TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputMc->splitTdRendWrappers[i].hBinRendererTd->Sources[nS]->SrcSpatial_p;
2629 0 : SrcSpatial_p->q_Pos_p = 31;
2630 0 : move16();
2631 : }
2632 : }
2633 : }
2634 : }
2635 : }
2636 :
2637 :
2638 32 : test();
2639 32 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && inputMc->hReverb == NULL )
2640 : {
2641 4 : IF( NE_32( ( error = ivas_reverb_open_fx( &( inputMc->hReverb ), hHrtfStatistics, hRendCfg, outSampleRate ) ), IVAS_ERR_OK ) )
2642 : {
2643 0 : return error;
2644 : }
2645 : }
2646 : }
2647 113221 : ELSE IF( !useTDRend && inputMc->crendWrapper == NULL )
2648 : {
2649 : /* open CREND */
2650 : #ifdef FIX_CREND_SIMPLIFY_CODE
2651 76 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputMc->crendWrapper, ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) ? IVAS_AUDIO_CONFIG_7_1_4 : inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics,
2652 : outSampleRate, 1, ( ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) || ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ) ? inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ),
2653 : IVAS_ERR_OK ) )
2654 : #else
2655 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputMc->crendWrapper, ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) ? IVAS_AUDIO_CONFIG_7_1_4 : inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, outSampleRate, num_poses ) ), IVAS_ERR_OK ) )
2656 : #endif
2657 : {
2658 0 : return error;
2659 : }
2660 : }
2661 :
2662 : /* Initialise the EFAP handle for rotation on input layout */
2663 113253 : test();
2664 113253 : test();
2665 113253 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && inputMc->base.ctx.pHeadRotData->headRotEnabled && inputMc->efapInWrapper.hEfap == NULL )
2666 : {
2667 30 : IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inConfig, NULL ) ), IVAS_ERR_OK ) )
2668 : {
2669 0 : return error;
2670 : }
2671 : }
2672 :
2673 : /* determine binaural delay ( used for aligning LFE to output signal ) */
2674 :
2675 113253 : IF( ( inputMc->crendWrapper != NULL ) )
2676 : {
2677 77914 : binauralDelayNs = inputMc->crendWrapper->binaural_latency_ns;
2678 : }
2679 : ELSE
2680 : {
2681 35339 : binauralDelayNs = 0;
2682 : }
2683 113253 : move32();
2684 :
2685 113253 : binauralDelayNs = L_max( binauralDelayNs, inputMc->tdRendWrapper.binaural_latency_ns );
2686 113253 : Word16 exp = 0;
2687 113253 : move16();
2688 113253 : Word16 var1 = BASOP_Util_Divide3232_Scale( *inputMc->base.ctx.pOutSampleRate, 1000000000, &exp );
2689 113253 : Word32 var2 = L_shr_r( Mpy_32_32( binauralDelayNs, L_deposit_h( var1 ) ), negate( exp ) ); /* Q0 */
2690 113253 : inputMc->binauralDelaySmp = extract_l( var2 );
2691 113253 : move16();
2692 : // inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f );
2693 :
2694 113253 : IF( GT_16( inputMc->binauralDelaySmp, MAX_BIN_DELAY_SAMPLES ) )
2695 : {
2696 0 : return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid delay for LFE binaural rendering!)" );
2697 : }
2698 :
2699 113253 : return IVAS_ERR_OK;
2700 : }
2701 :
2702 1 : static ivas_error initMcMasaRendering(
2703 : input_mc *inputMc,
2704 : const AUDIO_CONFIG inConfig,
2705 : const Word32 inSampleRate )
2706 : {
2707 : ivas_error error;
2708 : #ifndef FIX_CREND_SIMPLIFY_CODE
2709 : Word16 num_poses;
2710 :
2711 : num_poses = 1;
2712 : move16();
2713 : if ( inputMc->base.ctx.pSplitRendWrapper != NULL )
2714 : {
2715 : num_poses = inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
2716 : move16();
2717 : }
2718 : #endif
2719 :
2720 1 : IF( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2721 : {
2722 0 : ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
2723 : }
2724 :
2725 : #ifdef FIX_CREND_SIMPLIFY_CODE
2726 1 : ivas_rend_closeCrend_fx( &inputMc->crendWrapper );
2727 : #else
2728 : ivas_rend_closeCrend_fx( &inputMc->crendWrapper, num_poses );
2729 : #endif
2730 :
2731 1 : ivas_reverb_close_fx( &inputMc->hReverb );
2732 :
2733 1 : IF( inputMc->efapInWrapper.hEfap != NULL )
2734 : {
2735 0 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2736 : }
2737 :
2738 1 : IF( NE_32( ( error = ivas_mcmasa_ana_open( &inputMc->hMcMasa, inConfig, inSampleRate ) ), IVAS_ERR_OK ) )
2739 : {
2740 0 : return error;
2741 : }
2742 :
2743 1 : return IVAS_ERR_OK;
2744 : }
2745 :
2746 477 : static lfe_routing defaultLfeRouting(
2747 : const AUDIO_CONFIG inConfig,
2748 : const LSSETUP_CUSTOM_STRUCT customLsIn,
2749 : const AUDIO_CONFIG outConfig,
2750 : const LSSETUP_CUSTOM_STRUCT customLsOut )
2751 : {
2752 : Word16 i;
2753 : lfe_routing routing;
2754 :
2755 : /* Set all output gains to zero, then route each input LFE consecutively to the next available output LFE. */
2756 :
2757 2385 : FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i )
2758 : {
2759 1908 : set32_fx( routing.lfePanMtx_fx[i], 0, IVAS_MAX_OUTPUT_CHANNELS );
2760 : }
2761 477 : routing.pan_lfe = false;
2762 477 : move16();
2763 477 : routing.lfeInputGain_fx = ONE_IN_Q31;
2764 477 : move32();
2765 :
2766 477 : SWITCH( inConfig )
2767 : {
2768 196 : case IVAS_AUDIO_CONFIG_5_1:
2769 : case IVAS_AUDIO_CONFIG_5_1_2:
2770 : case IVAS_AUDIO_CONFIG_5_1_4:
2771 : case IVAS_AUDIO_CONFIG_7_1:
2772 : case IVAS_AUDIO_CONFIG_7_1_4:
2773 196 : routing.numLfeChannels = 1;
2774 196 : move16();
2775 196 : BREAK;
2776 210 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2777 210 : routing.numLfeChannels = customLsIn.num_lfe;
2778 210 : move16();
2779 210 : BREAK;
2780 71 : default:
2781 71 : routing.numLfeChannels = 0;
2782 71 : move16();
2783 : }
2784 :
2785 477 : SWITCH( outConfig )
2786 : {
2787 150 : case IVAS_AUDIO_CONFIG_5_1:
2788 : case IVAS_AUDIO_CONFIG_5_1_2:
2789 : case IVAS_AUDIO_CONFIG_5_1_4:
2790 : case IVAS_AUDIO_CONFIG_7_1:
2791 : case IVAS_AUDIO_CONFIG_7_1_4:
2792 150 : routing.lfePanMtx_fx[0][LFE_CHANNEL] = ONE_IN_Q31;
2793 150 : move32();
2794 150 : BREAK;
2795 39 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2796 39 : FOR( i = 0; i < routing.numLfeChannels && i < customLsOut.num_lfe; ++i )
2797 : {
2798 0 : test();
2799 0 : routing.lfePanMtx_fx[i][customLsOut.lfe_idx[i]] = ONE_IN_Q31;
2800 0 : move32();
2801 : }
2802 39 : BREAK;
2803 288 : default:
2804 : /* Do nothing */
2805 288 : BREAK;
2806 : }
2807 :
2808 477 : return routing;
2809 : }
2810 :
2811 372 : static ivas_error setRendInputActiveMc(
2812 : void *input,
2813 : const AUDIO_CONFIG inConfig,
2814 : const IVAS_REND_InputId id,
2815 : RENDER_CONFIG_DATA *hRendCfg,
2816 : hrtf_handles *hrtfs )
2817 : {
2818 : Word16 i;
2819 : ivas_error error;
2820 : rendering_context rendCtx;
2821 : AUDIO_CONFIG outConfig;
2822 : input_mc *inputMc;
2823 : Word16 pos_idx;
2824 :
2825 372 : inputMc = (input_mc *) input;
2826 372 : rendCtx = inputMc->base.ctx;
2827 372 : outConfig = *rendCtx.pOutConfig;
2828 :
2829 372 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
2830 : {
2831 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2832 : }
2833 372 : IF( NE_32( ( error = allocateMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx, MAX_BIN_DELAY_SAMPLES ) ), IVAS_ERR_OK ) )
2834 : {
2835 0 : return error;
2836 : }
2837 :
2838 372 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMc->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
2839 : {
2840 0 : return error;
2841 : }
2842 372 : initRendInputBase_fx( &inputMc->base, inConfig, id, rendCtx, inputMc->bufferData_fx, MAX_BUFFER_LENGTH );
2843 :
2844 372 : setZeroPanMatrix_fx( inputMc->panGains_fx );
2845 :
2846 372 : inputMc->customLsInput = defaultCustomLs();
2847 372 : inputMc->tdRendWrapper = defaultTdRendWrapper();
2848 :
2849 372 : if ( hrtfs->hHrtfTD )
2850 : {
2851 : #ifdef USE_TDREND_16BIT_ROM
2852 0 : inputMc->tdRendWrapper.binaural_latency_ns = L_shr_r( Mpy_32_32_r( hrtfs->hHrtfTD->latency_s_fx, 1000000000 ), hrtfs->hHrtfTD->latency_s_Q_fx );
2853 : #else
2854 : inputMc->tdRendWrapper.binaural_latency_ns = Mult_32_32( hrtfs->hHrtfTD->latency_s_fx, 1000000000 );
2855 : #endif
2856 : }
2857 372 : inputMc->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
2858 372 : inputMc->crendWrapper = NULL;
2859 372 : inputMc->hReverb = NULL;
2860 372 : inputMc->hMcMasa = NULL;
2861 :
2862 3348 : FOR( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
2863 : {
2864 2976 : initRotGainsWord32_fx( inputMc->rot_gains_prev_fx[pos_idx] );
2865 : }
2866 372 : inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut );
2867 372 : set32_fx( inputMc->lfeDelayBuffer_fx, 0, MAX_BIN_DELAY_SAMPLES );
2868 372 : inputMc->binauralDelaySmp = 0;
2869 372 : move16();
2870 :
2871 372 : test();
2872 372 : test();
2873 2976 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2874 : {
2875 2604 : if ( hrtfs->hHrtfTD )
2876 : {
2877 : #ifdef USE_TDREND_16BIT_ROM
2878 0 : inputMc->splitTdRendWrappers[i].binaural_latency_ns = L_shr_r( Mpy_32_32_r( hrtfs->hHrtfTD->latency_s_fx, 1000000000 ), hrtfs->hHrtfTD->latency_s_Q_fx );
2879 : #else
2880 : inputMc->splitTdRendWrappers[i].binaural_latency_ns = Mult_32_32( hrtfs->hHrtfTD->latency_s_fx, 1000000000 );
2881 : #endif
2882 : }
2883 2604 : inputMc->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
2884 : }
2885 :
2886 372 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
2887 : {
2888 : #ifdef FIX_CREND_SIMPLIFY_CODE
2889 96 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
2890 : #else
2891 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
2892 : #endif
2893 : {
2894 0 : return error;
2895 : }
2896 : }
2897 :
2898 372 : test();
2899 372 : IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
2900 : {
2901 1 : IF( NE_32( ( error = initMcMasaRendering( inputMc, inConfig, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
2902 : {
2903 0 : return error;
2904 : }
2905 : }
2906 :
2907 372 : IF( NE_32( ( error = updateMcPanGains( inputMc, outConfig ) ), IVAS_ERR_OK ) )
2908 : {
2909 0 : return error;
2910 : }
2911 :
2912 372 : return IVAS_ERR_OK;
2913 : }
2914 :
2915 666 : static void clearInputMc(
2916 : input_mc *inputMc )
2917 : {
2918 : rendering_context rendCtx;
2919 : #ifdef FIX_CREND_SIMPLIFY_CODE
2920 : Word16 i;
2921 : #else
2922 : Word16 i, num_poses;
2923 :
2924 : num_poses = 1;
2925 : move16();
2926 : if ( inputMc->base.ctx.pSplitRendWrapper != NULL )
2927 : {
2928 : num_poses = inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
2929 : move16();
2930 : }
2931 : #endif
2932 666 : rendCtx = inputMc->base.ctx;
2933 666 : freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx );
2934 666 : freeInputBaseBufferData_fx( &inputMc->bufferData_fx );
2935 666 : initRendInputBase_fx( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2936 :
2937 : /* Free input's internal handles */
2938 666 : IF( inputMc->efapInWrapper.hEfap != NULL )
2939 : {
2940 99 : efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
2941 : }
2942 :
2943 : #ifdef FIX_CREND_SIMPLIFY_CODE
2944 666 : ivas_rend_closeCrend_fx( &inputMc->crendWrapper );
2945 : #else
2946 : ivas_rend_closeCrend_fx( &inputMc->crendWrapper, num_poses );
2947 : #endif
2948 :
2949 666 : ivas_reverb_close_fx( &inputMc->hReverb );
2950 :
2951 666 : IF( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2952 : {
2953 20 : ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
2954 : }
2955 :
2956 5328 : FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2957 : {
2958 4662 : IF( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
2959 : {
2960 0 : ivas_td_binaural_close_fx( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
2961 0 : inputMc->splitTdRendWrappers[i].hHrtfTD = NULL;
2962 : }
2963 : }
2964 :
2965 666 : ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
2966 :
2967 666 : return;
2968 : }
2969 :
2970 77 : static ivas_error initSbaPanGainsForMcOut(
2971 : input_sba *inputSba,
2972 : const AUDIO_CONFIG outConfig,
2973 : const LSSETUP_CUSTOM_STRUCT *outSetupCustom )
2974 : {
2975 : Word16 ambiOrderIn;
2976 : Word16 chInIdx, chOutIdx;
2977 : Word32 *tmpDecMtx, *readPtr;
2978 : IVAS_OUTPUT_SETUP hOutSetup;
2979 : ivas_error error;
2980 :
2981 77 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inputSba->base.inConfig, &ambiOrderIn ) ), IVAS_ERR_OK ) )
2982 : {
2983 0 : return error;
2984 : }
2985 :
2986 77 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
2987 : {
2988 0 : assert( !"Invalid configuration" );
2989 : return IVAS_ERR_WRONG_PARAMS;
2990 : }
2991 :
2992 77 : SWITCH( outConfig )
2993 : {
2994 8 : case IVAS_AUDIO_CONFIG_MONO:
2995 8 : hOutSetup.ls_azimuth_fx = ls_azimuth_CICP1_fx;
2996 8 : hOutSetup.ls_elevation_fx = ls_elevation_CICP1_fx;
2997 8 : ivas_output_init( &hOutSetup, outConfig );
2998 8 : BREAK;
2999 60 : case IVAS_AUDIO_CONFIG_STEREO:
3000 : case IVAS_AUDIO_CONFIG_5_1:
3001 : case IVAS_AUDIO_CONFIG_7_1:
3002 : case IVAS_AUDIO_CONFIG_5_1_2:
3003 : case IVAS_AUDIO_CONFIG_5_1_4:
3004 : case IVAS_AUDIO_CONFIG_7_1_4:
3005 60 : ivas_output_init( &hOutSetup, outConfig );
3006 60 : BREAK;
3007 9 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3008 : // ivas_ls_custom_setup( &hOutSetup, (LSSETUP_CUSTOM_STRUCT *)outSetupCustom );
3009 9 : ivas_ls_custom_setup_fx( &hOutSetup, outSetupCustom );
3010 9 : BREAK;
3011 0 : default:
3012 0 : assert( !"Invalid speaker config" );
3013 : return IVAS_ERR_WRONG_PARAMS;
3014 : }
3015 :
3016 : /* obtain and copy over HOA decoding matrix */
3017 77 : tmpDecMtx = NULL;
3018 77 : IF( NE_32( ( error = ivas_sba_get_hoa_dec_matrix_fx( hOutSetup, &tmpDecMtx, ambiOrderIn ) ), IVAS_ERR_OK ) )
3019 : {
3020 0 : return error;
3021 : }
3022 :
3023 77 : readPtr = &tmpDecMtx[0];
3024 705 : FOR( chOutIdx = 0; chOutIdx < hOutSetup.nchan_out_woLFE + hOutSetup.num_lfe; ++chOutIdx )
3025 : {
3026 10676 : FOR( chInIdx = 0; chInIdx < SBA_NHARM_HOA3; ++chInIdx )
3027 : {
3028 10048 : test();
3029 10048 : IF( hOutSetup.num_lfe > 0 && EQ_16( chOutIdx, hOutSetup.index_lfe[0] ) )
3030 : {
3031 832 : CONTINUE; /* nothing to be rendered to LFE */
3032 : }
3033 9216 : inputSba->hoaDecMtx_fx[chInIdx][chOutIdx] = L_shl_sat( *readPtr++, Q2 ); /* Q29 + Q2 = Q31 */
3034 9216 : move32();
3035 : }
3036 : }
3037 77 : free( tmpDecMtx );
3038 :
3039 77 : return IVAS_ERR_OK;
3040 : }
3041 :
3042 24 : static ivas_error initSbaPanGainsForSbaOut(
3043 : input_sba *inputSba,
3044 : const AUDIO_CONFIG outConfig )
3045 : {
3046 : ivas_error error;
3047 24 : error = IVAS_ERR_OK;
3048 24 : move32();
3049 :
3050 24 : IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
3051 : {
3052 0 : assert( !"Invalid configuration" );
3053 : return IVAS_ERR_WRONG_PARAMS;
3054 : }
3055 :
3056 24 : fillIdentityPanMatrix_fx( inputSba->hoaDecMtx_fx );
3057 :
3058 24 : return error;
3059 : }
3060 :
3061 126 : static ivas_error updateSbaPanGains(
3062 : input_sba *inputSba,
3063 : const AUDIO_CONFIG outConfig,
3064 : RENDER_CONFIG_DATA *hRendCfg,
3065 : IVAS_DEC_HRTF_CREND_HANDLE hMixconv,
3066 : IVAS_DEC_HRTF_STATISTICS_HANDLE hHrtfStatistics )
3067 : {
3068 : ivas_error error;
3069 : AUDIO_CONFIG inConfig;
3070 : rendering_context rendCtx;
3071 : #ifndef FIX_CREND_SIMPLIFY_CODE
3072 : Word16 num_poses;
3073 : #endif
3074 :
3075 : /* Reset to all zeros - some functions below only write non-zero elements. */
3076 126 : setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
3077 :
3078 126 : inConfig = inputSba->base.inConfig;
3079 126 : rendCtx = inputSba->base.ctx;
3080 :
3081 : #ifndef FIX_CREND_SIMPLIFY_CODE
3082 : num_poses = 1;
3083 : move16();
3084 : if ( rendCtx.pSplitRendWrapper != NULL )
3085 : {
3086 : num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
3087 : move16();
3088 : }
3089 : #endif
3090 126 : SWITCH( getAudioConfigType( outConfig ) )
3091 : {
3092 65 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3093 65 : error = initSbaPanGainsForMcOut( inputSba, outConfig, inputSba->base.ctx.pCustomLsOut );
3094 65 : BREAK;
3095 24 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3096 24 : error = initSbaPanGainsForSbaOut( inputSba, outConfig );
3097 24 : BREAK;
3098 36 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
3099 : SWITCH( outConfig )
3100 : {
3101 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
3102 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
3103 : {
3104 : #ifdef FIX_HRTF_LOAD
3105 0 : IF( EQ_32( hRendCfg->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
3106 : #else
3107 : IF( EQ_32( hRendCfg->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
3108 : #endif
3109 : {
3110 : #ifdef FIX_1113_EXTREND_ISAR
3111 0 : assert( *rendCtx.pOutSampleRate == 48000 && "split binaural fast conv mode is currently supported with 48k sampling rate only" );
3112 : #else
3113 : assert( inConfig == IVAS_AUDIO_CONFIG_HOA3 && ( *rendCtx.pOutSampleRate == 48000 ) && "split binaural fast conv mode is currently supported with HOA3 input and 48k sampling rate only" );
3114 : #endif
3115 0 : IF( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
3116 : {
3117 0 : return error;
3118 : }
3119 : }
3120 : else
3121 : {
3122 0 : assert( ( *rendCtx.pOutSampleRate == 48000 ) && "split binaural crend mode is currently supported with 48k sampling rate only" );
3123 0 : IF( ( error = ivas_rend_openMultiBinCrend( &inputSba->crendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
3124 : {
3125 0 : return error;
3126 : }
3127 : }
3128 0 : break;
3129 : }
3130 24 : case IVAS_AUDIO_CONFIG_BINAURAL:
3131 : #ifdef FIX_1129_EXT_REND_OUTPUT_HIGH
3132 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
3133 : #endif
3134 : {
3135 : #ifdef FIX_HRTF_LOAD
3136 24 : IF( EQ_32( hRendCfg->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
3137 : #else
3138 : if ( hRendCfg->split_rend_config.rendererSelection == ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV )
3139 : #endif
3140 : {
3141 0 : IF( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
3142 : {
3143 0 : return error;
3144 : }
3145 : }
3146 : else
3147 : {
3148 : #ifdef FIX_CREND_SIMPLIFY_CODE
3149 24 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputSba->crendWrapper, inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, 1, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ), IVAS_ERR_OK ) )
3150 : #else
3151 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputSba->crendWrapper, inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
3152 : #endif
3153 : {
3154 0 : return error;
3155 : }
3156 : }
3157 : }
3158 24 : BREAK;
3159 12 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
3160 : #ifndef FIX_1129_EXT_REND_OUTPUT_HIGH
3161 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
3162 : #endif
3163 12 : IF( NE_32( ( error = initSbaPanGainsForMcOut( inputSba, IVAS_AUDIO_CONFIG_7_1_4, NULL ) ), IVAS_ERR_OK ) )
3164 : {
3165 0 : return error;
3166 : }
3167 : #ifdef FIX_CREND_SIMPLIFY_CODE
3168 12 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputSba->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, 1, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ), IVAS_ERR_OK ) )
3169 : #else
3170 : IF( NE_32( ( error = ivas_rend_openCrend_fx( &inputSba->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
3171 : #endif
3172 : {
3173 0 : return error;
3174 : }
3175 12 : BREAK;
3176 0 : default:
3177 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3178 : }
3179 36 : BREAK;
3180 1 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3181 1 : error = IVAS_ERR_OK;
3182 1 : move32();
3183 1 : BREAK; /* Do nothing */
3184 0 : default:
3185 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3186 : }
3187 :
3188 : /* Check error here to keep switch statement more compact */
3189 126 : IF( NE_32( error, IVAS_ERR_OK ) )
3190 : {
3191 0 : return error;
3192 : }
3193 :
3194 126 : return IVAS_ERR_OK;
3195 : }
3196 :
3197 1 : static ivas_error initSbaMasaRendering(
3198 : input_sba *inputSba,
3199 : Word32 inSampleRate )
3200 : {
3201 : ivas_error error;
3202 : #ifndef FIX_CREND_SIMPLIFY_CODE
3203 : Word16 num_poses;
3204 :
3205 : num_poses = 1;
3206 : move16();
3207 : if ( inputSba->base.ctx.pSplitRendWrapper != NULL )
3208 : {
3209 : num_poses = inputSba->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
3210 : move16();
3211 : }
3212 : #endif
3213 :
3214 : #ifdef FIX_CREND_SIMPLIFY_CODE
3215 1 : ivas_rend_closeCrend_fx( &inputSba->crendWrapper );
3216 : #else
3217 : ivas_rend_closeCrend_fx( &inputSba->crendWrapper, num_poses );
3218 : #endif
3219 :
3220 1 : IF( NE_32( ( error = ivas_dirac_ana_open_fx( &inputSba->hDirAC, inSampleRate ) ), IVAS_ERR_OK ) )
3221 : {
3222 0 : return error;
3223 : }
3224 :
3225 1 : return IVAS_ERR_OK;
3226 : }
3227 :
3228 126 : static ivas_error setRendInputActiveSba(
3229 : void *input,
3230 : const AUDIO_CONFIG inConfig,
3231 : const IVAS_REND_InputId id,
3232 : RENDER_CONFIG_DATA *hRendCfg,
3233 : hrtf_handles *hrtfs )
3234 : {
3235 : ivas_error error;
3236 : rendering_context rendCtx;
3237 : AUDIO_CONFIG outConfig;
3238 : input_sba *inputSba;
3239 : Word16 pos_idx;
3240 :
3241 126 : inputSba = (input_sba *) input;
3242 126 : rendCtx = inputSba->base.ctx;
3243 126 : outConfig = *rendCtx.pOutConfig;
3244 126 : move32();
3245 :
3246 126 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
3247 : {
3248 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
3249 : }
3250 :
3251 126 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputSba->bufferData_fx, MAX_CLDFB_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
3252 : {
3253 0 : return error;
3254 : }
3255 :
3256 126 : initRendInputBase_fx( &inputSba->base, inConfig, id, rendCtx, inputSba->bufferData_fx, MAX_CLDFB_BUFFER_LENGTH );
3257 :
3258 126 : setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
3259 :
3260 126 : inputSba->crendWrapper = NULL;
3261 126 : inputSba->hDirAC = NULL;
3262 1134 : FOR( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
3263 : {
3264 1008 : initRotGains_fx( inputSba->rot_gains_prev_fx[pos_idx] );
3265 : }
3266 126 : inputSba->cldfbRendWrapper.hHrtfFastConv = hrtfs->hHrtfFastConv;
3267 :
3268 126 : test();
3269 126 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
3270 : {
3271 1 : IF( NE_32( ( error = initSbaMasaRendering( inputSba, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
3272 : {
3273 0 : return error;
3274 : }
3275 : }
3276 :
3277 : #ifdef FIX_CREND_SIMPLIFY_CODE
3278 126 : IF( NE_32( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
3279 : #else
3280 : IF( NE_32( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
3281 : #endif
3282 : {
3283 0 : return error;
3284 : }
3285 :
3286 126 : return error;
3287 : }
3288 :
3289 666 : static void clearInputSba(
3290 : input_sba *inputSba )
3291 : {
3292 : rendering_context rendCtx;
3293 : #ifndef FIX_CREND_SIMPLIFY_CODE
3294 : Word16 num_poses;
3295 : #endif
3296 :
3297 666 : rendCtx = inputSba->base.ctx;
3298 :
3299 : #ifndef FIX_CREND_SIMPLIFY_CODE
3300 : num_poses = 1;
3301 : move16();
3302 : if ( rendCtx.pSplitRendWrapper != NULL )
3303 : {
3304 : num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
3305 : move16();
3306 : }
3307 : #endif
3308 666 : freeInputBaseBufferData_fx( &inputSba->bufferData_fx );
3309 :
3310 666 : initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3311 :
3312 : #ifdef FIX_CREND_SIMPLIFY_CODE
3313 666 : ivas_rend_closeCrend_fx( &inputSba->crendWrapper );
3314 : #else
3315 : ivas_rend_closeCrend_fx( &inputSba->crendWrapper, num_poses );
3316 : #endif
3317 :
3318 666 : IF( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
3319 : {
3320 0 : ivas_rend_closeCldfbRend( &inputSba->cldfbRendWrapper );
3321 : }
3322 :
3323 666 : ivas_dirac_ana_close_fx( &( inputSba->hDirAC ) );
3324 :
3325 666 : return;
3326 : }
3327 :
3328 49 : static ivas_error setRendInputActiveMasa(
3329 : void *input,
3330 : const AUDIO_CONFIG inConfig,
3331 : const IVAS_REND_InputId id,
3332 : RENDER_CONFIG_DATA *hRendCfg,
3333 : hrtf_handles *hrtfs )
3334 : {
3335 : ivas_error error;
3336 : rendering_context rendCtx;
3337 : AUDIO_CONFIG outConfig;
3338 : input_masa *inputMasa;
3339 : Word16 numInChannels;
3340 :
3341 49 : inputMasa = (input_masa *) input;
3342 49 : rendCtx = inputMasa->base.ctx;
3343 49 : outConfig = *rendCtx.pOutConfig;
3344 49 : move32();
3345 :
3346 49 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
3347 : {
3348 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
3349 : }
3350 :
3351 49 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMasa->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
3352 : {
3353 0 : return error;
3354 : }
3355 49 : initRendInputBase_fx( &inputMasa->base, inConfig, id, rendCtx, inputMasa->bufferData_fx, MAX_BUFFER_LENGTH );
3356 :
3357 49 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &numInChannels ) ), IVAS_ERR_OK ) )
3358 : {
3359 0 : return error;
3360 : }
3361 :
3362 49 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
3363 : {
3364 1 : inputMasa->metadataHasBeenFed = false;
3365 1 : move16();
3366 : Word16 temp;
3367 1 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
3368 : {
3369 0 : temp = 1;
3370 : }
3371 : ELSE
3372 : {
3373 1 : temp = 2;
3374 : }
3375 1 : move16();
3376 1 : IF( NE_32( ( error = masaPrerendOpen_fx( &inputMasa->hMasaPrerend, temp, *( inputMasa->base.ctx.pOutSampleRate ) ) ), IVAS_ERR_OK ) )
3377 : {
3378 0 : return error;
3379 : }
3380 : }
3381 : ELSE
3382 : {
3383 48 : IF( NE_32( ( error = initMasaExtRenderer( inputMasa, outConfig, hRendCfg, hrtfs ) ), IVAS_ERR_OK ) )
3384 : {
3385 0 : return error;
3386 : }
3387 48 : inputMasa->metadataHasBeenFed = false;
3388 48 : move16();
3389 : }
3390 :
3391 49 : return IVAS_ERR_OK;
3392 : }
3393 :
3394 666 : static void clearInputMasa(
3395 : input_masa *inputMasa )
3396 : {
3397 : rendering_context rendCtx;
3398 :
3399 666 : rendCtx = inputMasa->base.ctx;
3400 :
3401 666 : freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
3402 :
3403 666 : masaPrerendClose_fx( &inputMasa->hMasaPrerend );
3404 :
3405 666 : freeMasaExtRenderer( &inputMasa->hMasaExtRend );
3406 :
3407 666 : initRendInputBase_fx( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3408 :
3409 666 : return;
3410 : }
3411 :
3412 :
3413 : /*-------------------------------------------------------------------------
3414 : * IVAS_REND_Open()
3415 : *
3416 : *
3417 : *------------------------------------------------------------------------*/
3418 :
3419 666 : ivas_error IVAS_REND_Open(
3420 : IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */
3421 : const Word32 outputSampleRate, /* i : output sampling rate */
3422 : const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */
3423 : const bool asHrtfBinary, /* i : load hrtf binary file */
3424 : const Word16 nonDiegeticPan, /* i : non-diegetic object flag */
3425 : const Word32 nonDiegeticPanGain, /* i : non-diegetic panning gain Q31*/
3426 : const Word16 Opt_Headrotation, /* i : indicates whether head-rotation is used */
3427 : const Word16 Opt_ExternalOrientation, /* i : indicates whether external orientations are used */
3428 : const Word16 num_subframes /* i : number of subframes */
3429 : )
3430 : {
3431 : Word16 i;
3432 : Word16 j;
3433 : IVAS_REND_HANDLE hIvasRend;
3434 : ivas_error error;
3435 : Word16 numOutChannels;
3436 :
3437 : /* Validate function arguments */
3438 666 : IF( phIvasRend == NULL )
3439 : {
3440 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3441 : }
3442 :
3443 666 : IF( NE_32( ( error = validateOutputAudioConfig( outConfig ) ), IVAS_ERR_OK ) )
3444 : {
3445 0 : return error;
3446 : }
3447 :
3448 666 : IF( NE_32( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ), IVAS_ERR_OK ) )
3449 : {
3450 0 : return error;
3451 : }
3452 :
3453 666 : *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
3454 666 : IF( *phIvasRend == NULL )
3455 : {
3456 0 : return IVAS_ERR_FAILED_ALLOC;
3457 : }
3458 :
3459 666 : hIvasRend = *phIvasRend;
3460 666 : hIvasRend->sampleRateOut = outputSampleRate;
3461 666 : hIvasRend->outputConfig = outConfig;
3462 666 : hIvasRend->customLsOut = defaultCustomLs();
3463 666 : hIvasRend->hLimiter = NULL;
3464 666 : hIvasRend->efapOutWrapper.hEfap = NULL;
3465 666 : hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
3466 666 : hIvasRend->num_subframes = num_subframes;
3467 :
3468 : /* Initialize limiter */
3469 666 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
3470 : {
3471 0 : return error;
3472 : }
3473 :
3474 666 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ), IVAS_ERR_OK ) )
3475 : {
3476 0 : return error;
3477 : }
3478 :
3479 : /* Initialize headrotation data */
3480 666 : hIvasRend->headRotData.headRotEnabled = 0;
3481 666 : IF( Opt_Headrotation )
3482 : {
3483 94 : IF( NE_32( ( error = initHeadRotation_fx( hIvasRend ) ), IVAS_ERR_OK ) )
3484 : {
3485 0 : return error;
3486 : }
3487 : }
3488 :
3489 : /* Initialize external orientation data */
3490 666 : hIvasRend->hExternalOrientationData = NULL;
3491 666 : IF( Opt_ExternalOrientation )
3492 : {
3493 0 : IF( NE_32( ( error = ivas_external_orientation_open( &( hIvasRend->hExternalOrientationData ), num_subframes ) ), IVAS_ERR_OK ) )
3494 : {
3495 0 : return error;
3496 : }
3497 : }
3498 :
3499 : /* Initilize combined orientation data */
3500 666 : hIvasRend->hCombinedOrientationData = NULL;
3501 666 : IF( Opt_Headrotation || Opt_ExternalOrientation )
3502 : {
3503 94 : IF( NE_32( ( error = ivas_combined_orientation_open( &( hIvasRend->hCombinedOrientationData ), outputSampleRate, num_subframes ) ), IVAS_ERR_OK ) )
3504 : {
3505 0 : return error;
3506 : }
3507 : }
3508 :
3509 : /* Initialize EFAP */
3510 666 : IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
3511 : {
3512 0 : return error;
3513 : }
3514 :
3515 : /* Initialize inputs */
3516 666 : hIvasRend->splitRendWrapper = NULL;
3517 666 : test();
3518 666 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
3519 : {
3520 0 : if ( ( hIvasRend->splitRendWrapper = (SPLIT_REND_WRAPPER *) malloc( sizeof( SPLIT_REND_WRAPPER ) ) ) == NULL )
3521 : {
3522 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS renderer handle" );
3523 : }
3524 :
3525 0 : isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
3526 : }
3527 :
3528 3330 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
3529 : {
3530 2664 : initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3531 2664 : hIvasRend->inputsIsm[i].crendWrapper = NULL;
3532 2664 : hIvasRend->inputsIsm[i].hReverb = NULL;
3533 2664 : hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
3534 21312 : FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j )
3535 : {
3536 18648 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3537 18648 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3538 : }
3539 2664 : hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
3540 2664 : move16();
3541 2664 : hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
3542 2664 : move32();
3543 2664 : hIvasRend->inputsIsm[i].hOMasa = NULL;
3544 2664 : hIvasRend->inputsIsm[i].bufferData_fx = NULL;
3545 : }
3546 :
3547 1332 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3548 : {
3549 666 : initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3550 :
3551 666 : hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
3552 666 : hIvasRend->inputsMc[i].crendWrapper = NULL;
3553 666 : hIvasRend->inputsMc[i].hReverb = NULL;
3554 666 : hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
3555 666 : hIvasRend->inputsMc[i].bufferData_fx = NULL;
3556 666 : hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL;
3557 666 : hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
3558 666 : move16();
3559 666 : hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
3560 666 : move32();
3561 666 : hIvasRend->inputsMc[i].hMcMasa = NULL;
3562 5328 : FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j )
3563 : {
3564 4662 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3565 4662 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3566 : }
3567 : }
3568 :
3569 1332 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3570 : {
3571 666 : initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3572 :
3573 666 : hIvasRend->inputsSba[i].crendWrapper = NULL;
3574 666 : hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend = NULL;
3575 666 : hIvasRend->inputsSba[i].cldfbRendWrapper.hHrtfFastConv = NULL;
3576 666 : hIvasRend->inputsSba[i].bufferData_fx = NULL;
3577 666 : hIvasRend->inputsSba[i].hDirAC = NULL;
3578 : }
3579 :
3580 1332 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3581 : {
3582 666 : initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3583 :
3584 666 : hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
3585 666 : hIvasRend->inputsMasa[i].bufferData_fx = NULL;
3586 666 : hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
3587 666 : hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
3588 666 : move16();
3589 : }
3590 :
3591 666 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
3592 666 : hIvasRend->hHrtfs.hHrtfParambin = NULL;
3593 666 : hIvasRend->hHrtfs.hHrtfTD = NULL;
3594 : #ifdef FIX_CREND_SIMPLIFY_CODE
3595 666 : hIvasRend->hHrtfs.hHrtfCrend = NULL;
3596 : #else
3597 : hIvasRend->hHrtfs.hSetOfHRTF = NULL;
3598 : #endif
3599 666 : hIvasRend->hHrtfs.hHrtfStatistics = NULL;
3600 :
3601 666 : IF( asHrtfBinary )
3602 : {
3603 0 : IF( NE_32( ( error = ivas_HRTF_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfTD ) ) ), IVAS_ERR_OK ) )
3604 : {
3605 0 : return error;
3606 : }
3607 : #ifdef FIX_CREND_SIMPLIFY_CODE
3608 0 : IF( NE_32( ( error = ivas_HRTF_CRend_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfCrend ) ) ), IVAS_ERR_OK ) )
3609 : #else
3610 : IF( NE_32( ( error = ivas_HRTF_CRend_binary_open_fx( &( hIvasRend->hHrtfs.hSetOfHRTF ) ) ), IVAS_ERR_OK ) )
3611 : #endif
3612 : {
3613 0 : return error;
3614 : }
3615 0 : IF( NE_32( ( error = ivas_HRTF_fastconv_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfFastConv ) ) ), IVAS_ERR_OK ) )
3616 : {
3617 0 : return error;
3618 : }
3619 0 : IF( NE_32( ( error = ivas_HRTF_parambin_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfParambin ) ) ), IVAS_ERR_OK ) )
3620 : {
3621 0 : return error;
3622 : }
3623 0 : IF( NE_32( ( error = ivas_HRTF_statistics_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfStatistics ) ) ), IVAS_ERR_OK ) )
3624 : {
3625 0 : return error;
3626 : }
3627 : }
3628 :
3629 666 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
3630 : {
3631 60 : IF( NE_32( ( error = ivas_HRTF_statistics_init_fx( &( hIvasRend->hHrtfs.hHrtfStatistics ), hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
3632 : {
3633 0 : return error;
3634 : }
3635 : }
3636 :
3637 666 : return IVAS_ERR_OK;
3638 : }
3639 :
3640 :
3641 152 : static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup(
3642 : const IVAS_CUSTOM_LS_DATA rendCustomLsLayout )
3643 : {
3644 : Word16 i;
3645 : LSSETUP_CUSTOM_STRUCT customLs;
3646 :
3647 : /* Copy layout description */
3648 152 : customLs.num_spk = rendCustomLsLayout.num_spk;
3649 152 : move16();
3650 152 : Copy32( rendCustomLsLayout.azimuth_fx, customLs.ls_azimuth_fx, rendCustomLsLayout.num_spk );
3651 152 : Copy32( rendCustomLsLayout.elevation_fx, customLs.ls_elevation_fx, rendCustomLsLayout.num_spk );
3652 152 : customLs.is_planar_setup = 1;
3653 152 : move16();
3654 776 : FOR( i = 0; i < rendCustomLsLayout.num_spk; ++i )
3655 : {
3656 776 : IF( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
3657 : {
3658 152 : customLs.is_planar_setup = 0;
3659 152 : move16();
3660 152 : BREAK;
3661 : }
3662 : }
3663 :
3664 152 : customLs.num_lfe = rendCustomLsLayout.num_lfe;
3665 152 : move16();
3666 152 : Copy( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
3667 :
3668 152 : return customLs;
3669 : }
3670 :
3671 :
3672 152 : static ivas_error validateCustomLsLayout_fx(
3673 : const IVAS_CUSTOM_LS_DATA layout )
3674 : {
3675 : Word16 i;
3676 :
3677 : /* Negative number of speakers or LFEs makes no sense */
3678 152 : test();
3679 152 : IF( layout.num_spk < 0 || layout.num_lfe < 0 )
3680 : {
3681 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3682 : }
3683 :
3684 : /* There must be at least one speaker or LFE in the layout */
3685 152 : IF( add( layout.num_spk, layout.num_lfe ) <= 0 )
3686 : {
3687 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3688 : }
3689 :
3690 : /* LFE indices must be positive */
3691 152 : FOR( i = 0; i < layout.num_lfe; ++i )
3692 : {
3693 0 : IF( layout.lfe_idx[i] < 0 )
3694 : {
3695 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3696 : }
3697 : }
3698 :
3699 152 : return IVAS_ERR_OK;
3700 : }
3701 :
3702 :
3703 : /*-------------------------------------------------------------------*
3704 : * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
3705 : *
3706 : *
3707 : *-------------------------------------------------------------------*/
3708 :
3709 47 : ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
3710 : IVAS_REND_HANDLE hIvasRend,
3711 : const IVAS_CUSTOM_LS_DATA layout )
3712 : {
3713 : Word16 i, numOutChannels;
3714 : ivas_error error;
3715 : input_mc *inputMc;
3716 : input_sba *inputSba;
3717 :
3718 : /* Validate function arguments */
3719 47 : IF( hIvasRend == NULL )
3720 : {
3721 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3722 : }
3723 :
3724 47 : IF( NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
3725 : {
3726 : /* Specifying details of custom speaker layout only makes sense if output config is set to custom speaker layout */
3727 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3728 : }
3729 :
3730 47 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
3731 : {
3732 0 : return error;
3733 : }
3734 :
3735 47 : hIvasRend->customLsOut = makeCustomLsSetup( layout );
3736 :
3737 : /* Re-initialize limiter - number of output channels may have changed */
3738 47 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
3739 : {
3740 0 : return error;
3741 : }
3742 :
3743 47 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
3744 : {
3745 0 : return error;
3746 : }
3747 :
3748 : /* Re-initialize EFAP - output layout has changed or has been fully defined for the first time */
3749 47 : IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, hIvasRend->outputConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
3750 : {
3751 0 : return error;
3752 : }
3753 :
3754 : /* Re-initialize panning gains for each active MC input, This includes re-initializing
3755 : * LFE handling for the new output layout, which means custom LFE handling is overwritten,
3756 : * if previously set for any MC input. */
3757 94 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3758 : {
3759 47 : inputMc = &hIvasRend->inputsMc[i];
3760 47 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3761 : {
3762 : /* Input inactive, skip. */
3763 47 : CONTINUE;
3764 : }
3765 :
3766 0 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
3767 :
3768 0 : IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
3769 : {
3770 0 : return error;
3771 : }
3772 : }
3773 :
3774 : /* Re-initialize panning gains for each active SBA input */
3775 94 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3776 : {
3777 47 : inputSba = &hIvasRend->inputsSba[i];
3778 :
3779 47 : IF( EQ_32( inputSba->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3780 : {
3781 : /* Input inactive, skip. */
3782 47 : CONTINUE;
3783 : }
3784 0 : IF( NE_32( ( error = updateSbaPanGains( inputSba, hIvasRend->outputConfig, hIvasRend->hRendererConfig, NULL, NULL ) ), IVAS_ERR_OK ) )
3785 : {
3786 0 : return error;
3787 : }
3788 : }
3789 :
3790 47 : return IVAS_ERR_OK;
3791 : }
3792 :
3793 : /*-------------------------------------------------------------------*
3794 : * IVAS_REND_NumOutChannels()
3795 : *
3796 : *
3797 : *-------------------------------------------------------------------*/
3798 :
3799 1127519 : ivas_error IVAS_REND_NumOutChannels(
3800 : IVAS_REND_CONST_HANDLE hIvasRend,
3801 : Word16 *numOutChannels )
3802 : {
3803 : ivas_error error;
3804 :
3805 : /* Validate function arguments */
3806 1127519 : test();
3807 1127519 : IF( hIvasRend == NULL || numOutChannels == NULL )
3808 : {
3809 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3810 : }
3811 :
3812 : /* Handle special cases where additional info is needed from the renderer, otherwise use getAudioConfigNumChannels() */
3813 1127519 : SWITCH( hIvasRend->outputConfig )
3814 : {
3815 36003 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3816 36003 : *numOutChannels = add( hIvasRend->customLsOut.num_spk, hIvasRend->customLsOut.num_lfe );
3817 36003 : move16();
3818 36003 : BREAK;
3819 1091516 : default:
3820 1091516 : IF( NE_32( ( error = getAudioConfigNumChannels( hIvasRend->outputConfig, numOutChannels ) ), IVAS_ERR_OK ) )
3821 : {
3822 0 : return error;
3823 : }
3824 1091516 : BREAK;
3825 : }
3826 :
3827 1127519 : return IVAS_ERR_OK;
3828 : }
3829 :
3830 :
3831 973 : static IVAS_REND_InputId makeInputId(
3832 : AUDIO_CONFIG config,
3833 : const Word32 inputIndex )
3834 : {
3835 : /* Put config type in second byte (from LSB), put index + 1 in first byte
3836 : *
3837 : * Index is incremented here so that a valid ID can never be 0. */
3838 973 : return (IVAS_REND_InputId) UL_or( UL_lshl( ( (UWord32) getAudioConfigType( config ) ), 8 ), L_add( inputIndex, 1 ) );
3839 : }
3840 :
3841 :
3842 3133018 : static ivas_error getInputById(
3843 : IVAS_REND_HANDLE hIvasRend,
3844 : IVAS_REND_InputId inputId,
3845 : void **ppInput )
3846 : {
3847 : Word32 inputIndex;
3848 : IVAS_REND_AudioConfigType configType;
3849 : input_base *pInputBase;
3850 :
3851 : /* Reverse makeInputId() */
3852 3133018 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3853 3133018 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3854 :
3855 : /* Validate values derived from input ID */
3856 3133018 : IF( inputIndex < 0 )
3857 : {
3858 0 : return IVAS_ERR_INVALID_INPUT_ID;
3859 : }
3860 3133018 : SWITCH( configType )
3861 : {
3862 2495576 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3863 2495576 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3864 : {
3865 0 : return IVAS_ERR_INVALID_INPUT_ID;
3866 : }
3867 2495576 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3868 2495576 : BREAK;
3869 360012 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3870 360012 : IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
3871 : {
3872 0 : return IVAS_ERR_INVALID_INPUT_ID;
3873 : }
3874 360012 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3875 360012 : BREAK;
3876 251881 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3877 251881 : IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
3878 : {
3879 0 : return IVAS_ERR_INVALID_INPUT_ID;
3880 : }
3881 251881 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3882 251881 : BREAK;
3883 25549 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3884 25549 : IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
3885 : {
3886 0 : return IVAS_ERR_INVALID_INPUT_ID;
3887 : }
3888 25549 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3889 25549 : BREAK;
3890 0 : default:
3891 0 : return IVAS_ERR_INVALID_INPUT_ID;
3892 : }
3893 :
3894 : /* Ensure input ID matches and that input is active */
3895 3133018 : test();
3896 3133018 : IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3897 : {
3898 0 : return IVAS_ERR_INVALID_INPUT_ID;
3899 : }
3900 :
3901 : /* Validation done, set value via output parameter */
3902 3133018 : *ppInput = pInputBase;
3903 :
3904 3133018 : return IVAS_ERR_OK;
3905 : }
3906 :
3907 :
3908 630413 : static ivas_error getConstInputById(
3909 : IVAS_REND_CONST_HANDLE hIvasRend,
3910 : const IVAS_REND_InputId inputId,
3911 : const void **ppInput )
3912 : {
3913 : Word32 inputIndex;
3914 : IVAS_REND_AudioConfigType configType;
3915 : const input_base *pInputBase;
3916 :
3917 : /* Reverse makeInputId() */
3918 630413 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3919 630413 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3920 :
3921 : /* Validate values derived from input ID */
3922 630413 : IF( inputIndex < 0 )
3923 : {
3924 0 : return IVAS_ERR_INVALID_INPUT_ID;
3925 : }
3926 630413 : SWITCH( configType )
3927 : {
3928 426 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3929 426 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3930 : {
3931 0 : return IVAS_ERR_INVALID_INPUT_ID;
3932 : }
3933 426 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3934 426 : BREAK;
3935 359907 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3936 359907 : IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
3937 : {
3938 0 : return IVAS_ERR_INVALID_INPUT_ID;
3939 : }
3940 359907 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3941 359907 : BREAK;
3942 251881 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3943 251881 : IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
3944 : {
3945 0 : return IVAS_ERR_INVALID_INPUT_ID;
3946 : }
3947 251881 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3948 251881 : BREAK;
3949 18199 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3950 18199 : IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
3951 : {
3952 0 : return IVAS_ERR_INVALID_INPUT_ID;
3953 : }
3954 18199 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3955 18199 : BREAK;
3956 0 : default:
3957 0 : return IVAS_ERR_INVALID_INPUT_ID;
3958 : }
3959 :
3960 : /* Ensure input ID matches and that input is active */
3961 630413 : test();
3962 630413 : IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3963 : {
3964 0 : return IVAS_ERR_INVALID_INPUT_ID;
3965 : }
3966 :
3967 : /* Validation done, set value via output parameter */
3968 630413 : *ppInput = pInputBase;
3969 :
3970 630413 : return IVAS_ERR_OK;
3971 : }
3972 :
3973 973 : static ivas_error findFreeInputSlot_fx(
3974 : const void *inputs,
3975 : const Word32 inputStructSize,
3976 : const Word32 maxInputs,
3977 : Word32 *inputIndex )
3978 : {
3979 : /* Using a void pointer and a separately provided size is a hack for this function
3980 : to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
3981 : Assumptions:
3982 : - input_base is always the first member in the input struct
3983 : - provided size is correct
3984 : */
3985 :
3986 : Word32 i;
3987 : bool canAddInput;
3988 : const UWord8 *pByte;
3989 : const input_base *pInputBase;
3990 :
3991 973 : canAddInput = false;
3992 973 : move16();
3993 :
3994 : /* Find first unused input in array */
3995 1353 : FOR( ( i = 0, pByte = inputs ); i < maxInputs; ( ++i, pByte += inputStructSize ) )
3996 : {
3997 1353 : pInputBase = (const input_base *) pByte;
3998 :
3999 1353 : IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4000 : {
4001 973 : *inputIndex = i;
4002 973 : move32();
4003 973 : canAddInput = true;
4004 973 : move16();
4005 973 : BREAK;
4006 : }
4007 : }
4008 :
4009 973 : IF( !canAddInput )
4010 : {
4011 0 : return IVAS_ERR_TOO_MANY_INPUTS;
4012 : }
4013 :
4014 973 : return IVAS_ERR_OK;
4015 : }
4016 :
4017 :
4018 : /*-------------------------------------------------------------------------
4019 : * Function getCldfbRendFlag()
4020 : *
4021 : *
4022 : *------------------------------------------------------------------------*/
4023 :
4024 0 : static Word16 getCldfbRendFlag(
4025 : IVAS_REND_HANDLE hIvasRend, /* i : Renderer handle */
4026 : const IVAS_REND_AudioConfigType new_configType )
4027 : {
4028 : Word16 i;
4029 0 : Word16 numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0;
4030 : Word16 isCldfbRend;
4031 :
4032 0 : move16();
4033 0 : move16();
4034 0 : move16();
4035 0 : move16();
4036 :
4037 0 : isCldfbRend = 0;
4038 0 : move16();
4039 :
4040 0 : IF( hIvasRend->hRendererConfig != NULL )
4041 : {
4042 0 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
4043 : {
4044 0 : numMasaInputs = add( numMasaInputs, ( hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ? 0 : 1 );
4045 0 : move16();
4046 : }
4047 0 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
4048 : {
4049 0 : numSbaInputs = add( numSbaInputs, ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1 );
4050 0 : move16();
4051 : }
4052 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
4053 : {
4054 0 : numIsmInputs = add( numIsmInputs, ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1 );
4055 0 : move16();
4056 : }
4057 0 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
4058 : {
4059 0 : numMcInputs = add( numMcInputs, ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1 );
4060 0 : move16();
4061 : }
4062 :
4063 0 : IF( GT_16( numIsmInputs, 0 ) || GT_16( numMcInputs, 0 ) )
4064 : {
4065 0 : isCldfbRend = 0;
4066 0 : move16();
4067 : }
4068 : #ifdef FIX_HRTF_LOAD
4069 0 : ELSE IF( GT_16( numMasaInputs, 0 ) || ( GT_16( numSbaInputs, 0 ) && EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) ) )
4070 : #else
4071 : ELSE IF( GT_16( numMasaInputs, 0 ) || ( GT_16( numSbaInputs, 0 ) && EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) ) )
4072 : #endif
4073 : {
4074 0 : isCldfbRend = 1;
4075 0 : move16();
4076 : }
4077 : }
4078 :
4079 0 : return isCldfbRend;
4080 : }
4081 :
4082 :
4083 : /*-------------------------------------------------------------------------
4084 : * Function ivas_pre_rend_init()
4085 : *
4086 : *
4087 : *------------------------------------------------------------------------*/
4088 :
4089 0 : static ivas_error ivas_pre_rend_init(
4090 : SPLIT_REND_WRAPPER *pSplitRendWrapper,
4091 : IVAS_REND_AudioBuffer *pSplitRendEncBuffer,
4092 : ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config,
4093 : IVAS_REND_HeadRotData headRotData,
4094 : const Word32 outputSampleRate,
4095 : const AUDIO_CONFIG outConfig,
4096 : const Word16 cldfb_in_flag,
4097 : const Word16 num_subframes )
4098 : {
4099 : ivas_error error;
4100 : IVAS_REND_AudioBufferConfig bufConfig;
4101 :
4102 0 : test();
4103 0 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
4104 : {
4105 0 : IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
4106 : {
4107 0 : ISAR_PRE_REND_GetMultiBinPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData, headRotData.sr_pose_pred_axis );
4108 : }
4109 0 : ELSE IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) )
4110 : {
4111 0 : isar_renderSplitUpdateNoCorrectionPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData );
4112 : }
4113 :
4114 0 : IF( ( error = ISAR_PRE_REND_open( pSplitRendWrapper, pSplit_rend_config, outputSampleRate, cldfb_in_flag, outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM, num_subframes, 0 ) ) != IVAS_ERR_OK )
4115 : {
4116 0 : return error;
4117 : }
4118 :
4119 : /*allocate for CLDFB in and change to TD during process if needed*/
4120 0 : bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL;
4121 0 : bufConfig.numChannels = i_mult( BINAURAL_CHANNELS, pSplitRendWrapper->multiBinPoseData.num_poses );
4122 0 : bufConfig.is_cldfb = 1;
4123 0 : pSplitRendEncBuffer->config = bufConfig;
4124 0 : move16();
4125 0 : move16();
4126 0 : move16();
4127 0 : move32();
4128 :
4129 0 : IF( ( pSplitRendEncBuffer->data_fx = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL )
4130 : {
4131 0 : return IVAS_ERR_FAILED_ALLOC;
4132 : }
4133 :
4134 0 : pSplitRendEncBuffer->q_factor = 0;
4135 0 : pSplitRendEncBuffer->pq_fact = &pSplitRendEncBuffer->q_factor;
4136 : }
4137 : ELSE
4138 : {
4139 : IVAS_REND_AudioBufferConfig bufConfig2;
4140 :
4141 0 : bufConfig2.numSamplesPerChannel = 0;
4142 0 : bufConfig2.numChannels = 0;
4143 0 : bufConfig2.is_cldfb = 0;
4144 0 : pSplitRendEncBuffer->config = bufConfig2;
4145 0 : pSplitRendEncBuffer->data_fx = NULL;
4146 0 : pSplitRendEncBuffer->pq_fact = NULL;
4147 0 : pSplitRendEncBuffer->q_factor = 0;
4148 0 : move16();
4149 0 : move16();
4150 0 : move16();
4151 0 : move32();
4152 0 : move32();
4153 : }
4154 :
4155 0 : return IVAS_ERR_OK;
4156 : }
4157 :
4158 :
4159 : /*-------------------------------------------------------------------*
4160 : * IVAS_REND_AddInput()
4161 : *
4162 : *
4163 : *-------------------------------------------------------------------*/
4164 :
4165 973 : ivas_error IVAS_REND_AddInput_fx(
4166 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4167 : const AUDIO_CONFIG inConfig, /* i : audio config for a new input */
4168 : IVAS_REND_InputId *inputId /* o : ID of the new input */
4169 : )
4170 : {
4171 : ivas_error error;
4172 : Word32 maxNumInputsOfType;
4173 : void *inputsArray;
4174 : Word32 inputStructSize;
4175 : ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles *hrtfs );
4176 : Word32 inputIndex;
4177 :
4178 : /* Validate function arguments */
4179 973 : test();
4180 973 : IF( hIvasRend == NULL || inputId == NULL )
4181 : {
4182 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4183 : }
4184 :
4185 973 : IF( ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) && hIvasRend->splitRendEncBuffer.data_fx == NULL && hIvasRend->hRendererConfig != NULL )
4186 : {
4187 : Word16 cldfb_in_flag;
4188 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) );
4189 :
4190 0 : IF( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
4191 : {
4192 0 : return error;
4193 : }
4194 : }
4195 :
4196 :
4197 973 : SWITCH( getAudioConfigType( inConfig ) )
4198 : {
4199 426 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
4200 426 : maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
4201 426 : inputsArray = hIvasRend->inputsIsm;
4202 426 : inputStructSize = sizeof( *hIvasRend->inputsIsm );
4203 426 : activateInput = setRendInputActiveIsm;
4204 426 : move32();
4205 426 : move32();
4206 426 : BREAK;
4207 372 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
4208 372 : maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
4209 372 : inputsArray = hIvasRend->inputsMc;
4210 372 : inputStructSize = sizeof( *hIvasRend->inputsMc );
4211 372 : activateInput = setRendInputActiveMc;
4212 372 : move32();
4213 372 : move32();
4214 372 : BREAK;
4215 126 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
4216 126 : maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
4217 126 : inputsArray = hIvasRend->inputsSba;
4218 126 : inputStructSize = sizeof( *hIvasRend->inputsSba );
4219 126 : activateInput = setRendInputActiveSba;
4220 126 : move32();
4221 126 : move32();
4222 126 : BREAK;
4223 49 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
4224 49 : maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
4225 49 : inputsArray = hIvasRend->inputsMasa;
4226 49 : inputStructSize = sizeof( *hIvasRend->inputsMasa );
4227 49 : activateInput = setRendInputActiveMasa;
4228 49 : move32();
4229 49 : move32();
4230 49 : BREAK;
4231 0 : default:
4232 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4233 : }
4234 :
4235 : /* Find first free input in array corresponding to input type */
4236 973 : IF( NE_32( ( error = findFreeInputSlot_fx( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ), IVAS_ERR_OK ) )
4237 : {
4238 0 : return error;
4239 : }
4240 :
4241 973 : *inputId = makeInputId( inConfig, inputIndex );
4242 973 : move16();
4243 973 : IF( NE_32( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ), IVAS_ERR_OK ) )
4244 : {
4245 0 : return error;
4246 : }
4247 :
4248 973 : return IVAS_ERR_OK;
4249 : }
4250 :
4251 :
4252 : /*-------------------------------------------------------------------*
4253 : * IVAS_REND_ConfigureCustomInputLoudspeakerLayout()
4254 : *
4255 : *
4256 : * Note: this will reset any custom LFE routing set for the input
4257 : *-------------------------------------------------------------------*/
4258 105 : ivas_error IVAS_REND_ConfigureCustomInputLoudspeakerLayout(
4259 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4260 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4261 : const IVAS_CUSTOM_LS_DATA layout /* i : custom loudspeaker layout for input */
4262 : )
4263 : {
4264 : input_mc *inputMc;
4265 : ivas_error error;
4266 :
4267 : /* Validate function arguments */
4268 105 : IF( hIvasRend == NULL )
4269 : {
4270 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4271 : }
4272 :
4273 105 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
4274 : {
4275 0 : return error;
4276 : }
4277 :
4278 105 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputMc ) ), IVAS_ERR_OK ) )
4279 : {
4280 0 : return error;
4281 : }
4282 :
4283 105 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
4284 : {
4285 : /* Specifying details of custom speaker layout only makes sense if input config is set to custom speaker layout */
4286 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4287 : }
4288 :
4289 : /* Re-initialize panning gains for the MC input, This includes re-initializing LFE handling
4290 : * for the new input layout, which means custom LFE handling is overwritten, if previously
4291 : * set for the MC input. */
4292 105 : inputMc->customLsInput = makeCustomLsSetup( layout );
4293 :
4294 105 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
4295 :
4296 105 : IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inputMc->base.inConfig, &inputMc->customLsInput ) ), IVAS_ERR_OK ) )
4297 : {
4298 0 : return error;
4299 : }
4300 :
4301 105 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
4302 : {
4303 : #ifdef FIX_CREND_SIMPLIFY_CODE
4304 36 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inputMc->base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hHrtfCrend, hIvasRend->hHrtfs.hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
4305 : #else
4306 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inputMc->base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
4307 : #endif
4308 : {
4309 0 : return error;
4310 : }
4311 : }
4312 :
4313 105 : IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
4314 : {
4315 0 : return error;
4316 : }
4317 :
4318 105 : return IVAS_ERR_OK;
4319 : }
4320 :
4321 : #ifdef NONBE_1377_REND_DIRATT_CONF
4322 : /*-------------------------------------------------------------------*
4323 : * IVAS_REND_SetObjectIDs()
4324 : *
4325 : *
4326 : *-------------------------------------------------------------------*/
4327 :
4328 666 : ivas_error IVAS_REND_SetObjectIDs(
4329 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
4330 : )
4331 : {
4332 : int16_t i;
4333 :
4334 : /* Validate function arguments */
4335 666 : if ( hIvasRend == NULL )
4336 : {
4337 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4338 : }
4339 :
4340 3330 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
4341 : {
4342 2664 : hIvasRend->inputsIsm[i].object_id = i;
4343 : }
4344 :
4345 666 : return IVAS_ERR_OK;
4346 : }
4347 : #endif
4348 :
4349 : /*-------------------------------------------------------------------*
4350 : * IVAS_REND_SetInputGain()
4351 : *
4352 : *
4353 : *-------------------------------------------------------------------*/
4354 973 : ivas_error IVAS_REND_SetInputGain_fx(
4355 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4356 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4357 : const Word32 gain /* i : linear gain (not in dB) Q30 */
4358 : )
4359 : {
4360 : input_base *inputBase;
4361 : ivas_error error;
4362 :
4363 : /* Validate function arguments */
4364 973 : IF( hIvasRend == NULL )
4365 : {
4366 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4367 : }
4368 :
4369 973 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4370 : {
4371 0 : return error;
4372 : }
4373 :
4374 973 : inputBase->gain_fx = gain;
4375 973 : move32();
4376 :
4377 973 : return IVAS_ERR_OK;
4378 : }
4379 :
4380 : /*-------------------------------------------------------------------*
4381 : * IVAS_REND_SetInputLfeMtx()
4382 : *
4383 : *
4384 : *-------------------------------------------------------------------*/
4385 0 : ivas_error IVAS_REND_SetInputLfeMtx_fx(
4386 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4387 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4388 : const IVAS_REND_LfePanMtx_fx *lfePanMtx /* i : LFE panning matrix */
4389 : )
4390 : {
4391 : Word16 i;
4392 : input_base *pInputBase;
4393 : input_mc *pInputMc;
4394 : ivas_error error;
4395 :
4396 : /* Validate function arguments */
4397 0 : IF( hIvasRend == NULL )
4398 : {
4399 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4400 : }
4401 :
4402 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
4403 : {
4404 0 : return error;
4405 : }
4406 :
4407 0 : IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
4408 : {
4409 : /* Custom LFE panning matrix only makes sense with channel-based input */
4410 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4411 : }
4412 0 : pInputMc = (input_mc *) pInputBase;
4413 :
4414 : /* copy LFE panning matrix */
4415 0 : FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; i++ )
4416 : {
4417 0 : Copy32( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS );
4418 : }
4419 :
4420 0 : IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
4421 : {
4422 0 : return error;
4423 : }
4424 :
4425 0 : return IVAS_ERR_OK;
4426 : }
4427 :
4428 : /*-------------------------------------------------------------------*
4429 : * IVAS_REND_SetInputLfePos()
4430 : *
4431 : *
4432 : *-------------------------------------------------------------------*/
4433 :
4434 0 : ivas_error IVAS_REND_SetInputLfePos_fx(
4435 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4436 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4437 : const Word32 inputGain, /* i : Input gain to be applied to the LFE channel(s) Q31 */
4438 : const Word16 outputAzimuth, /* i : Output azimuth position Q0 */
4439 : const Word16 outputElevation /* i : Output elevation position Q0 */
4440 : )
4441 : {
4442 : input_base *pInputBase;
4443 : input_mc *pInputMc;
4444 : ivas_error error;
4445 :
4446 : /* Validate function arguments */
4447 0 : IF( hIvasRend == NULL )
4448 : {
4449 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4450 : }
4451 :
4452 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
4453 : {
4454 0 : return error;
4455 : }
4456 :
4457 0 : IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
4458 : {
4459 : /* Custom LFE routing only makes sense with channel-based input */
4460 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4461 : }
4462 0 : pInputMc = (input_mc *) pInputBase;
4463 :
4464 0 : pInputMc->lfeRouting.pan_lfe = true;
4465 0 : move16();
4466 0 : pInputMc->lfeRouting.lfeInputGain_fx = inputGain; /* Q31 */
4467 0 : move32();
4468 0 : pInputMc->lfeRouting.lfeOutputAzimuth_fx = outputAzimuth; /* Q0 */
4469 0 : move16();
4470 0 : pInputMc->lfeRouting.lfeOutputElevation_fx = outputElevation; /* Q0 */
4471 0 : move16();
4472 :
4473 0 : IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
4474 : {
4475 0 : return error;
4476 : }
4477 :
4478 0 : return IVAS_ERR_OK;
4479 : }
4480 :
4481 : /*-------------------------------------------------------------------*
4482 : * IVAS_REND_RemoveInput()
4483 : *
4484 : *
4485 : *-------------------------------------------------------------------*/
4486 : /* ToDo; unused function */
4487 0 : ivas_error IVAS_REND_RemoveInput(
4488 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4489 : const IVAS_REND_InputId inputId /* i : ID of the input */
4490 : )
4491 : {
4492 : ivas_error error;
4493 : input_base *inputBase;
4494 :
4495 : /* Validate function arguments */
4496 0 : IF( hIvasRend == NULL )
4497 : {
4498 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4499 : }
4500 :
4501 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4502 : {
4503 0 : return error;
4504 : }
4505 :
4506 0 : SWITCH( getAudioConfigType( inputBase->inConfig ) )
4507 : {
4508 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
4509 0 : clearInputIsm( (input_ism *) inputBase );
4510 0 : BREAK;
4511 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
4512 0 : clearInputMc( (input_mc *) inputBase );
4513 0 : BREAK;
4514 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
4515 0 : clearInputSba( (input_sba *) inputBase );
4516 0 : BREAK;
4517 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
4518 0 : clearInputMasa( (input_masa *) inputBase );
4519 0 : BREAK;
4520 0 : default:
4521 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4522 : }
4523 :
4524 0 : return IVAS_ERR_OK;
4525 : }
4526 :
4527 :
4528 : /*-------------------------------------------------------------------*
4529 : * IVAS_REND_GetInputNumChannels()
4530 : *
4531 : *
4532 : *-------------------------------------------------------------------*/
4533 630413 : ivas_error IVAS_REND_GetInputNumChannels(
4534 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
4535 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4536 : Word16 *numChannels /* o : number of channels of the input */
4537 : )
4538 : {
4539 : ivas_error error;
4540 : const input_base *pInput;
4541 :
4542 : /* Validate function arguments */
4543 630413 : test();
4544 630413 : IF( hIvasRend == NULL || numChannels == NULL )
4545 : {
4546 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4547 : }
4548 :
4549 630413 : IF( NE_32( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ), IVAS_ERR_OK ) )
4550 : {
4551 0 : return error;
4552 : }
4553 :
4554 630413 : IF( NE_32( ( error = getRendInputNumChannels( pInput, numChannels ) ), IVAS_ERR_OK ) )
4555 : {
4556 0 : return error;
4557 : }
4558 :
4559 630413 : return IVAS_ERR_OK;
4560 : }
4561 :
4562 : /*-------------------------------------------------------------------*
4563 : * IVAS_REND_GetNumAllObjects()
4564 : *
4565 : *
4566 : *-------------------------------------------------------------------*/
4567 426 : ivas_error IVAS_REND_GetNumAllObjects(
4568 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
4569 : Word16 *numChannels /* o : number of all objects */
4570 : )
4571 : {
4572 426 : test();
4573 426 : IF( hIvasRend == NULL || numChannels == NULL )
4574 : {
4575 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4576 : }
4577 :
4578 426 : test();
4579 426 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
4580 : {
4581 1 : *numChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
4582 1 : move16();
4583 : }
4584 :
4585 426 : return IVAS_ERR_OK;
4586 : }
4587 :
4588 :
4589 : /*-------------------------------------------------------------------*
4590 : * IVAS_REND_GetDelay()
4591 : *
4592 : *
4593 : *-------------------------------------------------------------------*/
4594 :
4595 0 : ivas_error IVAS_REND_GetDelay_fx(
4596 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
4597 : Word16 *nSamples, /* o : Renderer delay in samples */
4598 : Word32 *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
4599 : )
4600 : {
4601 : /* TODO tmu : this function only returns the maximum delay across all inputs
4602 : * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform)
4603 : */
4604 : Word16 i;
4605 : Word32 latency_ns;
4606 : Word32 max_latency_ns;
4607 :
4608 0 : Word32 timescale_by_ns[7] = { 0, 17180, 34360, 0, 68719, 0, 103079 };
4609 0 : move32();
4610 0 : move32();
4611 0 : move32();
4612 0 : move32();
4613 0 : move32();
4614 0 : move32();
4615 0 : move32();
4616 :
4617 : /* Validate function arguments */
4618 0 : test();
4619 0 : test();
4620 0 : IF( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
4621 : {
4622 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4623 : }
4624 :
4625 0 : *timeScale = hIvasRend->sampleRateOut;
4626 0 : move32();
4627 0 : assert( *timeScale == 8000 || *timeScale == 16000 || *timeScale == 32000 || *timeScale == 48000 );
4628 0 : *nSamples = 0;
4629 0 : move16();
4630 0 : max_latency_ns = 0;
4631 0 : move32();
4632 :
4633 : /* Compute the maximum delay across all inputs */
4634 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
4635 : {
4636 0 : IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4637 : {
4638 0 : IF( hIvasRend->inputsIsm[i].crendWrapper != NULL )
4639 : {
4640 0 : latency_ns = hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns;
4641 : }
4642 : ELSE
4643 : {
4644 0 : latency_ns = 0;
4645 : }
4646 0 : move32();
4647 :
4648 0 : latency_ns = L_max( latency_ns, hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns );
4649 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4650 : }
4651 : }
4652 :
4653 0 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
4654 : {
4655 0 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4656 : {
4657 0 : IF( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) )
4658 : {
4659 0 : latency_ns = hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns;
4660 : }
4661 : ELSE
4662 : {
4663 0 : latency_ns = 0;
4664 : }
4665 0 : move32();
4666 :
4667 0 : latency_ns = L_max( latency_ns, hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns );
4668 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4669 : }
4670 : }
4671 :
4672 0 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
4673 : {
4674 0 : IF( NE_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4675 : {
4676 0 : test();
4677 0 : IF( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL )
4678 : {
4679 : #ifdef FIX_HRTF_LOAD
4680 0 : IF( EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
4681 : #else
4682 : IF( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV )
4683 : #endif
4684 : {
4685 0 : latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
4686 0 : move32();
4687 : }
4688 : ELSE
4689 : {
4690 0 : IF( ( hIvasRend->inputsSba[i].crendWrapper != NULL ) )
4691 : {
4692 0 : latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
4693 : }
4694 : ELSE
4695 : {
4696 0 : latency_ns = 0;
4697 : }
4698 0 : move32();
4699 : }
4700 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4701 : }
4702 0 : ELSE IF( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL )
4703 : {
4704 0 : latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
4705 0 : move32();
4706 0 : latency_ns = L_add( latency_ns, IVAS_FB_DEC_DELAY_NS );
4707 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4708 : }
4709 : ELSE
4710 : {
4711 0 : IF( hIvasRend->inputsSba[i].crendWrapper != NULL )
4712 : {
4713 0 : latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
4714 : }
4715 : ELSE
4716 : {
4717 0 : latency_ns = 0;
4718 : }
4719 0 : move32();
4720 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4721 : }
4722 : }
4723 : }
4724 :
4725 0 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
4726 : {
4727 0 : IF( NE_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4728 : {
4729 0 : latency_ns = (Word32) ( IVAS_FB_DEC_DELAY_NS );
4730 0 : move32();
4731 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4732 : }
4733 : }
4734 :
4735 : //*nSamples = (Word16) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
4736 0 : Word32 temp = Mpy_32_32( *timeScale, 268436 ); // Q0 + Q31 - Q31 -> Q0, ( 1 / 8000 ) * 2 ^ 31
4737 0 : *nSamples = extract_l( Mpy_32_32_r( max_latency_ns, timescale_by_ns[temp] ) );
4738 0 : move16();
4739 :
4740 0 : return IVAS_ERR_OK;
4741 : }
4742 :
4743 :
4744 : /*-------------------------------------------------------------------*
4745 : * IVAS_REND_FeedInputAudio()
4746 : *
4747 : *
4748 : *-------------------------------------------------------------------*/
4749 :
4750 1877090 : ivas_error IVAS_REND_FeedInputAudio_fx(
4751 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4752 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4753 : const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */
4754 : )
4755 : {
4756 : ivas_error error;
4757 : input_base *inputBase;
4758 : Word16 numInputChannels;
4759 : Word16 cldfb2tdShift;
4760 :
4761 : /* Validate function arguments */
4762 1877090 : test();
4763 1877090 : IF( hIvasRend == NULL || inputAudio.data_fx == NULL )
4764 : {
4765 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4766 : }
4767 :
4768 1877090 : test();
4769 1877090 : cldfb2tdShift = ( inputAudio.config.is_cldfb ) ? 1 : 0;
4770 :
4771 1877090 : IF( inputAudio.config.numSamplesPerChannel <= 0 || ( MAX_BUFFER_LENGTH_PER_CHANNEL < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
4772 : ( ( shl( MAX_BUFFER_LENGTH_PER_CHANNEL, cldfb2tdShift ) ) < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 1 ) )
4773 : {
4774 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
4775 : }
4776 :
4777 1877090 : test();
4778 1877090 : IF( inputAudio.config.numChannels <= 0 || LT_16( MAX_INPUT_CHANNELS, inputAudio.config.numChannels ) )
4779 : {
4780 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4781 : }
4782 :
4783 1877090 : test();
4784 1877090 : move32(); // move added for typecasting
4785 1877090 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
4786 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) &&
4787 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) &&
4788 : NE_32( L_shr( L_mult0( inputAudio.config.numSamplesPerChannel, 1000 ), cldfb2tdShift ), (Word32) W_mult0_32_32( L_mult0( BINAURAL_RENDERING_FRAME_SIZE_MS, hIvasRend->num_subframes ), hIvasRend->sampleRateOut ) ) )
4789 : {
4790 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
4791 : }
4792 :
4793 1877090 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4794 : {
4795 0 : return error;
4796 : }
4797 :
4798 1877090 : IF( NE_32( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ), IVAS_ERR_OK ) )
4799 : {
4800 0 : return error;
4801 : }
4802 1877090 : test();
4803 1877090 : test();
4804 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 ) )
4805 : {
4806 150 : numInputChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
4807 150 : move16();
4808 : }
4809 :
4810 1877090 : IF( NE_16( numInputChannels, inputAudio.config.numChannels ) )
4811 : {
4812 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4813 : }
4814 :
4815 1877090 : inputBase->inputBuffer.config = inputAudio.config;
4816 :
4817 1877090 : MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
4818 :
4819 1877090 : inputBase->numNewSamplesPerChannel = shr( inputAudio.config.numSamplesPerChannel, cldfb2tdShift );
4820 1877090 : move32();
4821 :
4822 1877090 : return IVAS_ERR_OK;
4823 : }
4824 :
4825 :
4826 : /*-------------------------------------------------------------------*
4827 : * IVAS_REND_FeedInputObjectMetadata()
4828 : *
4829 : *
4830 : *-------------------------------------------------------------------*/
4831 :
4832 1247500 : ivas_error IVAS_REND_FeedInputObjectMetadata(
4833 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4834 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4835 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
4836 : )
4837 : {
4838 : input_base *inputBase;
4839 : input_ism *inputIsm;
4840 : ivas_error error;
4841 :
4842 : /* Validate function arguments */
4843 1247500 : IF( hIvasRend == NULL )
4844 : {
4845 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4846 : }
4847 :
4848 1247500 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4849 : {
4850 0 : return error;
4851 : }
4852 :
4853 1247500 : IF( NE_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
4854 : {
4855 : /* Object metadata should only be fed for object inputs */
4856 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4857 : }
4858 :
4859 1247500 : inputIsm = (input_ism *) inputBase;
4860 1247500 : inputIsm->previousPos = inputIsm->currentPos;
4861 1247500 : inputIsm->currentPos = objectPosition;
4862 :
4863 1247500 : return IVAS_ERR_OK;
4864 : }
4865 :
4866 :
4867 : /*-------------------------------------------------------------------*
4868 : * IVAS_REND_FeedInputObjectMetadataToOMasa()
4869 : *
4870 : *
4871 : *-------------------------------------------------------------------*/
4872 600 : ivas_error IVAS_REND_FeedInputObjectMetadataToOMasa(
4873 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4874 : const Word16 inputIndex, /* i : Index of the input */
4875 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
4876 : )
4877 : {
4878 : /* Validate function arguments */
4879 600 : IF( hIvasRend == NULL )
4880 : {
4881 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4882 : }
4883 :
4884 : /* Set position to OMasa struct */
4885 600 : hIvasRend->inputsIsm->hOMasa->ism_azimuth_fx[inputIndex] = objectPosition.azimuth_fx;
4886 600 : move32();
4887 600 : hIvasRend->inputsIsm->hOMasa->ism_elevation_fx[inputIndex] = objectPosition.elevation_fx;
4888 600 : move32();
4889 :
4890 600 : return IVAS_ERR_OK;
4891 : }
4892 :
4893 :
4894 : /*-------------------------------------------------------------------*
4895 : * IVAS_REND_FeedInputMasaMetadata()
4896 : *
4897 : *
4898 : *-------------------------------------------------------------------*/
4899 :
4900 7350 : ivas_error IVAS_REND_FeedInputMasaMetadata(
4901 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4902 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4903 : IVAS_MASA_METADATA_HANDLE masaMetadata /* i : MASA metadata frame */
4904 : )
4905 : {
4906 : ivas_error error;
4907 : input_base *inputBase;
4908 : input_masa *inputMasa;
4909 :
4910 : /* Validate function arguments */
4911 7350 : IF( hIvasRend == NULL )
4912 : {
4913 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4914 : }
4915 :
4916 7350 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4917 : {
4918 0 : return error;
4919 : }
4920 :
4921 7350 : IF( NE_32( getAudioConfigType( inputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
4922 : {
4923 : /* MASA metadata should only be fed for MASA inputs */
4924 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4925 : }
4926 :
4927 7350 : inputMasa = (input_masa *) inputBase;
4928 7350 : inputMasa->masaMetadata = *masaMetadata;
4929 7350 : inputMasa->metadataHasBeenFed = true;
4930 7350 : move16();
4931 :
4932 7350 : return IVAS_ERR_OK;
4933 : }
4934 :
4935 :
4936 : /*-------------------------------------------------------------------*
4937 : * IVAS_REND_InitConfig()
4938 : *
4939 : *
4940 : *-------------------------------------------------------------------*/
4941 :
4942 666 : ivas_error IVAS_REND_InitConfig(
4943 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4944 : const AUDIO_CONFIG outAudioConfig /* i : output audioConfig */
4945 : )
4946 : {
4947 : ivas_error error;
4948 : bool rendererConfigEnabled;
4949 :
4950 666 : rendererConfigEnabled = EQ_32( getAudioConfigType( outAudioConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
4951 :
4952 666 : IF( rendererConfigEnabled )
4953 : {
4954 188 : hIvasRend->rendererConfigEnabled = 1;
4955 188 : move16();
4956 : }
4957 : ELSE
4958 : {
4959 478 : hIvasRend->rendererConfigEnabled = 0;
4960 478 : move16();
4961 : }
4962 :
4963 666 : IF( rendererConfigEnabled )
4964 : {
4965 188 : IF( NE_32( ( error = ivas_render_config_open_fx( &( hIvasRend->hRendererConfig ) ) ), IVAS_ERR_OK ) )
4966 : {
4967 0 : return error;
4968 : }
4969 188 : IF( NE_32( ( error = ivas_render_config_init_from_rom_fx( &hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
4970 : {
4971 0 : return error;
4972 : }
4973 : }
4974 : ELSE
4975 : {
4976 478 : hIvasRend->hRendererConfig = NULL;
4977 : }
4978 :
4979 666 : return IVAS_ERR_OK;
4980 : }
4981 :
4982 :
4983 : /*-------------------------------------------------------------------*
4984 : * IVAS_REND_GetRenderConfig()
4985 : *
4986 : *
4987 : *-------------------------------------------------------------------*/
4988 :
4989 : #ifdef FIX_1113_EXTREND_ISAR
4990 0 : ivas_error IVAS_REND_GetRenderConfig(
4991 : #else
4992 : Word16 IVAS_REND_GetRenderConfig(
4993 : #endif
4994 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
4995 : const IVAS_RENDER_CONFIG_HANDLE hRCout /* o : Render configuration handle */
4996 : )
4997 : {
4998 : RENDER_CONFIG_HANDLE hRCin;
4999 :
5000 0 : test();
5001 0 : test();
5002 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL || hRCout == NULL )
5003 : {
5004 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5005 : }
5006 :
5007 0 : hRCin = hIvasRend->hRendererConfig;
5008 0 : hRCout->roomAcoustics.nBands = hRCin->roomAcoustics.nBands;
5009 0 : hRCout->roomAcoustics.acousticPreDelay_fx = hRCin->roomAcoustics.acousticPreDelay_fx;
5010 0 : hRCout->roomAcoustics.inputPreDelay_fx = hRCin->roomAcoustics.inputPreDelay_fx;
5011 0 : Copy( hRCin->directivity_fx, hRCout->directivity_fx, 3 * MAX_NUM_OBJECTS );
5012 0 : move16();
5013 0 : move32();
5014 0 : move32();
5015 :
5016 0 : Copy32( hRCin->roomAcoustics.pFc_input_fx, hRCout->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
5017 0 : Copy32( hRCin->roomAcoustics.pAcoustic_rt60_fx, hRCout->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
5018 0 : Copy32( hRCin->roomAcoustics.pAcoustic_dsr_fx, hRCout->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
5019 :
5020 0 : hRCout->split_rend_config.splitRendBitRate = ISAR_MAX_SPLIT_REND_BITRATE;
5021 0 : hRCout->split_rend_config.dof = 3;
5022 0 : hRCout->split_rend_config.hq_mode = 0;
5023 0 : hRCout->split_rend_config.codec_delay_ms = 0;
5024 0 : hRCout->split_rend_config.isar_frame_size_ms = 20;
5025 0 : hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
5026 0 : hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
5027 0 : hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
5028 0 : hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
5029 0 : hRCout->split_rend_config.lc3plus_highres = 0;
5030 :
5031 0 : hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er;
5032 0 : hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
5033 0 : move16();
5034 0 : move32();
5035 :
5036 : #ifdef FIX_1053_REVERB_RECONFIGURATION
5037 0 : Copy32( hRCin->distAtt_fx, hRCout->distAtt_fx, 3 );
5038 : #endif
5039 :
5040 0 : return IVAS_ERR_OK;
5041 : }
5042 :
5043 :
5044 : /*-------------------------------------------------------------------*
5045 : * IVAS_REND_FeedRenderConfig()
5046 : *
5047 : *
5048 : *-------------------------------------------------------------------*/
5049 :
5050 : #ifdef FIX_1113_EXTREND_ISAR
5051 0 : ivas_error IVAS_REND_FeedRenderConfig(
5052 : #else
5053 : Word16 IVAS_REND_FeedRenderConfig(
5054 : #endif
5055 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
5056 : const IVAS_RENDER_CONFIG_DATA renderConfig /* i : Render configuration struct */
5057 : )
5058 : {
5059 : RENDER_CONFIG_HANDLE hRenderConfig;
5060 : UWord16 i;
5061 : input_ism *pIsmInput;
5062 : input_masa *pMasaInput;
5063 : input_mc *pMcInput;
5064 : input_sba *pSbaInput;
5065 : ivas_error error;
5066 :
5067 0 : test();
5068 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
5069 : {
5070 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5071 : }
5072 0 : hRenderConfig = hIvasRend->hRendererConfig;
5073 :
5074 0 : hRenderConfig->roomAcoustics.nBands = renderConfig.roomAcoustics.nBands;
5075 0 : move16();
5076 0 : hRenderConfig->roomAcoustics.acousticPreDelay_fx = renderConfig.roomAcoustics.acousticPreDelay_fx;
5077 0 : move32();
5078 0 : hRenderConfig->roomAcoustics.inputPreDelay_fx = renderConfig.roomAcoustics.inputPreDelay_fx;
5079 0 : move32();
5080 0 : Copy32( renderConfig.roomAcoustics.pFc_input_fx, hRenderConfig->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
5081 0 : Copy32( renderConfig.roomAcoustics.pAcoustic_rt60_fx, hRenderConfig->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
5082 0 : Copy32( renderConfig.roomAcoustics.pAcoustic_dsr_fx, hRenderConfig->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
5083 0 : Copy( renderConfig.directivity_fx, hRenderConfig->directivity_fx, 3 * MAX_NUM_OBJECTS );
5084 : #ifdef FIX_1053_REVERB_RECONFIGURATION
5085 0 : Copy32( renderConfig.distAtt_fx, hRenderConfig->distAtt_fx, 3 );
5086 : #endif
5087 :
5088 0 : hRenderConfig->roomAcoustics.use_er = 0;
5089 0 : move16();
5090 0 : IF( EQ_16( renderConfig.roomAcoustics.use_er, 1 ) )
5091 : {
5092 0 : hRenderConfig->roomAcoustics.use_er = renderConfig.roomAcoustics.use_er;
5093 0 : move16();
5094 0 : hRenderConfig->roomAcoustics.lowComplexity = renderConfig.roomAcoustics.lowComplexity;
5095 0 : move32();
5096 0 : hRenderConfig->roomAcoustics.dimensions = renderConfig.roomAcoustics.dimensions;
5097 0 : hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.roomAcoustics.ListenerOrigin;
5098 :
5099 0 : Copy32( renderConfig.roomAcoustics.AbsCoeff_fx, hRenderConfig->roomAcoustics.AbsCoeff_fx, IVAS_ROOM_ABS_COEFF );
5100 : }
5101 :
5102 : /* Re-initialize reverb instance if already available */
5103 : /* ISM inputs */
5104 0 : for ( i = 0, pIsmInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pIsmInput )
5105 : {
5106 0 : IF( EQ_32( pIsmInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5107 : {
5108 : /* Skip inactive inputs */
5109 0 : continue;
5110 : }
5111 0 : if ( pIsmInput->hReverb != NULL )
5112 : {
5113 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pIsmInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
5114 : {
5115 0 : return error;
5116 : }
5117 : }
5118 0 : if ( pIsmInput->crendWrapper != NULL && pIsmInput->crendWrapper->hCrend[0] != NULL )
5119 : {
5120 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pIsmInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
5121 : {
5122 0 : return error;
5123 : }
5124 : }
5125 : }
5126 :
5127 : /* MASA inputs */
5128 0 : for ( i = 0, pMasaInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pMasaInput )
5129 : {
5130 0 : IF( EQ_32( pMasaInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5131 : {
5132 : /* Skip inactive inputs */
5133 0 : continue;
5134 : }
5135 :
5136 0 : if ( pMasaInput->hMasaExtRend != NULL )
5137 : {
5138 0 : if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
5139 : {
5140 0 : ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
5141 0 : IF( NE_32( ( error = ivas_binaural_reverb_init_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) )
5142 : {
5143 0 : return error;
5144 : }
5145 : }
5146 0 : if ( pMasaInput->hMasaExtRend->hReverb != NULL )
5147 : {
5148 0 : ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hReverb );
5149 0 : IF( NE_32( ( error = ivas_binaural_reverb_init_fx( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) )
5150 : {
5151 0 : return error;
5152 : }
5153 : }
5154 : }
5155 : }
5156 :
5157 : /* Multi-channel inputs */
5158 0 : for ( i = 0, pMcInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pMcInput )
5159 : {
5160 0 : IF( EQ_32( pMcInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5161 : {
5162 : /* Skip inactive inputs */
5163 0 : continue;
5164 : }
5165 :
5166 0 : if ( pMcInput->hReverb != NULL )
5167 : {
5168 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pMcInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
5169 : {
5170 0 : return error;
5171 : }
5172 : }
5173 0 : if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
5174 : {
5175 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
5176 : {
5177 0 : return error;
5178 : }
5179 : }
5180 : }
5181 :
5182 : /* SBA inputs */
5183 0 : for ( i = 0, pSbaInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pSbaInput )
5184 : {
5185 0 : IF( EQ_32( pSbaInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5186 : {
5187 : /* Skip inactive inputs */
5188 0 : continue;
5189 : }
5190 0 : if ( pSbaInput->crendWrapper != NULL && pSbaInput->crendWrapper->hCrend[0] != NULL && pSbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
5191 : {
5192 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pSbaInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pSbaInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
5193 : {
5194 0 : return error;
5195 : }
5196 : }
5197 : }
5198 :
5199 0 : hRenderConfig->split_rend_config = renderConfig.split_rend_config;
5200 : /* Overwrite any pose correction settings if 0 DOF (no pose correction) was selected */
5201 0 : IF( EQ_16( hRenderConfig->split_rend_config.dof, 0 ) )
5202 : {
5203 0 : hRenderConfig->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
5204 : }
5205 :
5206 0 : hRenderConfig->split_rend_config.codec = renderConfig.split_rend_config.codec;
5207 :
5208 0 : IF( ( error = isar_split_rend_validate_config( &hRenderConfig->split_rend_config, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0 ) ) != IVAS_ERR_OK )
5209 : {
5210 0 : return error;
5211 : }
5212 :
5213 : /* Must re-initialize split rendering config in case renderer config is updated after adding renderer inputs */
5214 : /* if its not initialized yet then no need to re-initialize, initialization will happen while adding inputs*/
5215 0 : IF( hIvasRend->splitRendEncBuffer.data_fx != NULL && hIvasRend->hRendererConfig != NULL )
5216 : {
5217 : Word16 cldfb_in_flag;
5218 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
5219 0 : IF( hIvasRend->splitRendWrapper != NULL )
5220 : {
5221 0 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
5222 0 : free( hIvasRend->splitRendWrapper );
5223 0 : hIvasRend->splitRendWrapper = NULL;
5224 : }
5225 :
5226 0 : IF( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
5227 : {
5228 0 : return error;
5229 : }
5230 : }
5231 :
5232 0 : return IVAS_ERR_OK;
5233 : }
5234 :
5235 : /*-------------------------------------------------------------------*
5236 : * IVAS_REND_SetHeadRotation()
5237 : *
5238 : *
5239 : *-------------------------------------------------------------------*/
5240 288060 : ivas_error IVAS_REND_SetHeadRotation(
5241 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5242 : const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */
5243 : const IVAS_VECTOR3 Pos, /* i : listener positions for next rendering call */
5244 : const ISAR_SPLIT_REND_ROT_AXIS rot_axis, /* i : external control for rotation axis for split rendering */
5245 : const Word16 sf_idx /* i : subframe index */
5246 : )
5247 : {
5248 : Word16 i;
5249 : IVAS_QUATERNION rotQuat;
5250 : ivas_error error;
5251 :
5252 : /* Validate function arguments */
5253 288060 : IF( hIvasRend == NULL )
5254 : {
5255 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5256 : }
5257 :
5258 288060 : IF( NE_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
5259 : {
5260 : /* Head rotation can be set only with binaural output */
5261 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
5262 : }
5263 :
5264 288060 : hIvasRend->headRotData.headRotEnabled = 1;
5265 288060 : move16();
5266 :
5267 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
5268 576120 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
5269 : {
5270 288060 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5271 : {
5272 : #ifdef FIX_CREND_SIMPLIFY_CODE
5273 69615 : IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hHrtfCrend, hIvasRend->hHrtfs.hHrtfStatistics, TRUE ) ), IVAS_ERR_OK ) )
5274 : #else
5275 : IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, TRUE ) ), IVAS_ERR_OK ) )
5276 : #endif
5277 : {
5278 0 : return error;
5279 : }
5280 : }
5281 : }
5282 :
5283 : /* check for Euler angle signaling */
5284 288060 : IF( EQ_32( headRot.w_fx, L_negate( 12582912 ) ) && EQ_16( headRot.q_fact, Q22 ) )
5285 : {
5286 0 : Euler2Quat_fx( deg2rad_fx( headRot.x_fx ), deg2rad_fx( headRot.y_fx ), deg2rad_fx( headRot.z_fx ), &rotQuat );
5287 0 : modify_Quat_q_fx( &rotQuat, &rotQuat, Q29 );
5288 : }
5289 : ELSE
5290 : {
5291 288060 : rotQuat = headRot;
5292 : }
5293 :
5294 288060 : Word32 updateRate_fx = 1677721600; // value is 200 in Q23
5295 288060 : rotQuat.w_fx = L_shl( rotQuat.w_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5296 288060 : rotQuat.x_fx = L_shl( rotQuat.x_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5297 288060 : rotQuat.y_fx = L_shl( rotQuat.y_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5298 288060 : rotQuat.z_fx = L_shl( rotQuat.z_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5299 :
5300 288060 : move32();
5301 288060 : move32();
5302 288060 : move32();
5303 288060 : move32();
5304 :
5305 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5306 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5307 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5308 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5309 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5310 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5311 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5312 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5313 :
5314 288060 : move32();
5315 288060 : move32();
5316 288060 : move32();
5317 288060 : move32();
5318 288060 : move32();
5319 288060 : move32();
5320 288060 : move32();
5321 288060 : move32();
5322 :
5323 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.q_fact = Q29;
5324 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact = Q29;
5325 288060 : move16();
5326 288060 : move16();
5327 288060 : rotQuat.q_fact = Q29;
5328 :
5329 288060 : move16();
5330 288060 : IF( NE_32( ( error = ivas_orient_trk_Process_fx( hIvasRend->headRotData.hOrientationTracker, rotQuat, updateRate_fx, &hIvasRend->headRotData.headPositions[sf_idx] ) ), IVAS_ERR_OK ) )
5331 : {
5332 0 : return error;
5333 : }
5334 :
5335 288060 : hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
5336 :
5337 288060 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
5338 :
5339 288060 : return IVAS_ERR_OK;
5340 : }
5341 :
5342 : /*-------------------------------------------------------------------*
5343 : * IVAS_REND_DisableHeadRotation()
5344 : *
5345 : *
5346 : *-------------------------------------------------------------------*/
5347 946116 : ivas_error IVAS_REND_DisableHeadRotation(
5348 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
5349 : )
5350 : {
5351 : Word16 i;
5352 : ivas_error error;
5353 :
5354 : /* Validate function arguments */
5355 946116 : IF( hIvasRend == NULL )
5356 : {
5357 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5358 : }
5359 :
5360 946116 : hIvasRend->headRotData.headRotEnabled = 0;
5361 946116 : move32();
5362 :
5363 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
5364 946116 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
5365 : {
5366 360048 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
5367 : {
5368 180024 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5369 : {
5370 : #ifdef FIX_CREND_SIMPLIFY_CODE
5371 43506 : IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hHrtfCrend, hIvasRend->hHrtfs.hHrtfStatistics, TRUE ) ), IVAS_ERR_OK ) )
5372 : #else
5373 : IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, TRUE ) ), IVAS_ERR_OK ) )
5374 : #endif
5375 : {
5376 :
5377 0 : return error;
5378 : }
5379 : }
5380 : }
5381 : }
5382 :
5383 946116 : return IVAS_ERR_OK;
5384 : }
5385 :
5386 :
5387 : /*-------------------------------------------------------------------*
5388 : * IVAS_REND_SetSplitRendBFI()
5389 : *
5390 : *
5391 : *-------------------------------------------------------------------*/
5392 :
5393 0 : ivas_error IVAS_REND_SetSplitRendBFI(
5394 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5395 : const Word16 bfi /* i : Bad Frame Indicator */
5396 : )
5397 : {
5398 0 : hIvasRend->splitRendBFI = bfi;
5399 :
5400 0 : return IVAS_ERR_OK;
5401 : }
5402 :
5403 :
5404 : /*-------------------------------------------------------------------*
5405 : * IVAS_REND_SetOrientationTrackingMode()
5406 : *
5407 : *
5408 : *-------------------------------------------------------------------*/
5409 :
5410 666 : ivas_error IVAS_REND_SetOrientationTrackingMode(
5411 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5412 : const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i : Head orientation tracking type */
5413 : )
5414 : {
5415 666 : if ( hIvasRend->headRotData.headRotEnabled == 0 )
5416 : {
5417 572 : return IVAS_ERR_OK;
5418 : }
5419 :
5420 94 : return ivas_orient_trk_SetTrackingType_fx( hIvasRend->headRotData.hOrientationTracker, orientation_tracking );
5421 : }
5422 :
5423 :
5424 : /*-------------------------------------------------------------------*
5425 : * IVAS_REND_SetReferenceRotation()
5426 : *
5427 : *
5428 : *-------------------------------------------------------------------*/
5429 :
5430 0 : ivas_error IVAS_REND_SetReferenceRotation(
5431 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5432 : const IVAS_QUATERNION refRot /* i : Reference rotation */
5433 : )
5434 : {
5435 : ivas_error error;
5436 :
5437 : /* Validate function arguments */
5438 0 : IF( hIvasRend == NULL )
5439 : {
5440 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5441 : }
5442 :
5443 0 : error = ivas_orient_trk_SetReferenceRotation_fx( hIvasRend->headRotData.hOrientationTracker, refRot );
5444 :
5445 0 : IF( NE_32( error, IVAS_ERR_OK ) )
5446 : {
5447 :
5448 0 : return error;
5449 : }
5450 0 : return IVAS_ERR_OK;
5451 : }
5452 :
5453 :
5454 : /*-------------------------------------------------------------------*
5455 : * IVAS_REND_GetMainOrientation()
5456 : *
5457 : *
5458 : *-------------------------------------------------------------------*/
5459 :
5460 :
5461 : /*-------------------------------------------------------------------*
5462 : * IVAS_REND_GetTrackedRotation()
5463 : *
5464 : *
5465 : *-------------------------------------------------------------------*/
5466 :
5467 :
5468 : /*---------------------------------------------------------------------*
5469 : * IVAS_REND_SetReferenceVector( )
5470 : *
5471 : * Sets a reference vector spanning from listenerPos to refPos. Only
5472 : * available in OTR_TRACKING_REF_VEC and OTR_TRACKING_REF_VEC_LEV modes.
5473 : *---------------------------------------------------------------------*/
5474 :
5475 0 : ivas_error IVAS_REND_SetReferenceVector(
5476 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5477 : const IVAS_VECTOR3 listenerPos, /* i : Listener position */
5478 : const IVAS_VECTOR3 refPos /* i : Reference position */
5479 : )
5480 : {
5481 0 : test();
5482 0 : IF( hIvasRend == NULL || hIvasRend->headRotData.hOrientationTracker == NULL )
5483 : {
5484 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5485 : }
5486 :
5487 0 : return ivas_orient_trk_SetReferenceVector_fx( hIvasRend->headRotData.hOrientationTracker, listenerPos, refPos );
5488 : }
5489 :
5490 :
5491 : /*---------------------------------------------------------------------*
5492 : * IVAS_REND_SetExternalOrientation()
5493 : *
5494 : *
5495 : *---------------------------------------------------------------------*/
5496 :
5497 0 : ivas_error IVAS_REND_SetExternalOrientation(
5498 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5499 : IVAS_QUATERNION *orientation, /* i : external orientation data */
5500 : Word8 enableHeadRotation, /* i : flag to enable head rotation for this frame */
5501 : Word8 enableExternalOrientation, /* i : flag to enable external orientation for this frame */
5502 : Word8 enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */
5503 : Word16 numFramesToTargetOrientation, /* i : number of frames until target orientation is reached */
5504 : const Word16 sf_idx /* i : subframe index */
5505 : )
5506 : {
5507 : /* Validate function arguments */
5508 0 : test();
5509 0 : IF( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL )
5510 : {
5511 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5512 : }
5513 :
5514 0 : IF( orientation == NULL )
5515 : {
5516 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = 0;
5517 0 : move16();
5518 : }
5519 : ELSE
5520 : {
5521 0 : QuaternionInverse_fx( *orientation, &hIvasRend->hExternalOrientationData->Quaternions[sf_idx] );
5522 :
5523 0 : hIvasRend->hExternalOrientationData->enableHeadRotation[sf_idx] = enableHeadRotation;
5524 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = enableExternalOrientation;
5525 0 : hIvasRend->hExternalOrientationData->enableRotationInterpolation[sf_idx] = enableRotationInterpolation;
5526 0 : hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[sf_idx] = numFramesToTargetOrientation;
5527 0 : move16();
5528 0 : move16();
5529 0 : move16();
5530 0 : move16();
5531 : }
5532 :
5533 0 : return IVAS_ERR_OK;
5534 : }
5535 :
5536 :
5537 : /*---------------------------------------------------------------------*
5538 : * IVAS_REND_CombineHeadAndExternalOrientation()
5539 : *
5540 : *
5541 : *---------------------------------------------------------------------*/
5542 :
5543 1126140 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
5544 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
5545 : )
5546 : {
5547 1126140 : IF( hIvasRend == NULL )
5548 : {
5549 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5550 : }
5551 1126140 : ivas_error error = combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
5552 :
5553 1126140 : return error;
5554 : }
5555 :
5556 :
5557 : /*---------------------------------------------------------------------*
5558 : * IVAS_REND_GetCombinedOrientation()
5559 : *
5560 : *
5561 : *---------------------------------------------------------------------*/
5562 :
5563 :
5564 : /*-------------------------------------------------------------------*
5565 : * Local functions
5566 : *-------------------------------------------------------------------*/
5567 : /* Take one channel from input buffer and copy it to each channel
5568 : in output buffer, with different gain applied per output channel.
5569 : This function takes 2 gain vectors - one for the beginning and one
5570 : for the end of the buffer. Gain values are lineraly interpolated
5571 : for all samples in between. */
5572 : /* Take one channel from input buffer and copy it to each channel
5573 : in output buffer, with different gain applied per output channel.
5574 : This function takes 2 gain vectors - one for the beginning and one
5575 : for the end of the buffer. Gain values are lineraly interpolated
5576 : for all samples in between. */
5577 4992179 : static void renderBufferChannelLerp_fx(
5578 : const IVAS_REND_AudioBuffer inAudio,
5579 : const Word32 inChannelIdx,
5580 : const Word32 *const gainsCurrent, /* Q31 */
5581 : const Word32 *const gainsPrev, /* Q31 */
5582 : IVAS_REND_AudioBuffer outAudio )
5583 : {
5584 : const Word32 *inSmpl;
5585 : Word32 *outSmpl;
5586 : Word32 fadeIn;
5587 : Word32 fadeOut;
5588 : Word32 i;
5589 : const Word32 *lastInSmpl;
5590 : Word16 outChnlIdx;
5591 : Word32 currentGain; /* Q31 */
5592 : Word32 previousGain; /* Q31 */
5593 :
5594 : /* Pointer to behind last input sample */
5595 4992179 : lastInSmpl = getSmplPtr_fx( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
5596 :
5597 47433367 : FOR( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
5598 : {
5599 42441188 : currentGain = gainsCurrent[outChnlIdx];
5600 42441188 : move32();
5601 42441188 : if ( gainsPrev == NULL )
5602 : {
5603 39044000 : previousGain = 0;
5604 39044000 : move32();
5605 : }
5606 : else
5607 : {
5608 3397188 : previousGain = gainsPrev[outChnlIdx];
5609 3397188 : move32();
5610 : }
5611 :
5612 : /* Process current output channel only if applying non-zero gains */
5613 42441188 : test();
5614 42441188 : test();
5615 42441188 : IF( GT_32( L_abs( currentGain ), EPSILON_FX ) || ( gainsPrev != NULL && GT_32( L_abs( previousGain ), EPSILON_FX ) ) )
5616 : {
5617 : /* Reset input pointer to the beginning of input channel */
5618 23944469 : inSmpl = getSmplPtr_fx( inAudio, inChannelIdx, 0 );
5619 :
5620 : /* Set output pointer to first output channel sample */
5621 23944469 : outSmpl = getSmplPtr_fx( outAudio, outChnlIdx, 0 );
5622 :
5623 23944469 : test();
5624 23944469 : IF( gainsPrev == NULL || LE_32( L_abs( L_sub( L_shr( previousGain, 1 ), L_shr( currentGain, 1 ) ) ), EPSILON_FX ) )
5625 : {
5626 : /* If no interpolation from previous frame, apply current gain */
5627 : DO
5628 : {
5629 8798392080 : *outSmpl = L_add( Mpy_32_32( currentGain, ( *inSmpl ) ), *outSmpl );
5630 8798392080 : move32();
5631 8798392080 : ++outSmpl;
5632 8798392080 : ++inSmpl;
5633 : }
5634 8798392080 : WHILE( inSmpl != lastInSmpl );
5635 : }
5636 : ELSE
5637 : {
5638 1996136 : i = 0;
5639 1996136 : Word32 tmp = Q31_BY_SUB_FRAME_240;
5640 1996136 : Word32 tmp1 = 239; /* L_SUBFRAME_48k - 1 */
5641 1996136 : move32();
5642 1996136 : move32();
5643 1996136 : move32();
5644 1996136 : SWITCH( outAudio.config.numSamplesPerChannel )
5645 : {
5646 1051037 : case NUM_SAMPLES_960:
5647 1051037 : tmp = Q31_BY_NUM_SAMPLES_960;
5648 1051037 : tmp1 = 959; /* NUM_SAMPLES_960 - 1 */
5649 1051037 : move32();
5650 1051037 : move32();
5651 1051037 : BREAK;
5652 0 : case NUM_SAMPLES_720:
5653 0 : tmp = Q31_BY_NUM_SAMPLES_720;
5654 0 : tmp1 = 719; /* NUM_SAMPLES_720 - 1 */
5655 0 : move32();
5656 0 : move32();
5657 0 : BREAK;
5658 0 : case NUM_SAMPLES_640:
5659 0 : tmp = Q31_BY_NUM_SAMPLES_640;
5660 0 : tmp1 = 639; /* NUM_SAMPLES_640 - 1 */
5661 0 : move32();
5662 0 : move32();
5663 0 : BREAK;
5664 0 : case NUM_SAMPLES_320:
5665 0 : tmp = Q31_BY_NUM_SAMPLES_320;
5666 0 : tmp1 = 319; /* NUM_SAMPLES_320 - 1 */
5667 0 : move32();
5668 0 : move32();
5669 0 : BREAK;
5670 0 : case L_SUBFRAME_32k:
5671 0 : tmp = Q31_BY_NUM_SAMPLES_160;
5672 0 : tmp1 = 159; /* NUM_SAMPLES_160 - 1 */
5673 0 : move32();
5674 0 : move32();
5675 0 : BREAK;
5676 945099 : case L_SUBFRAME_48k:
5677 945099 : tmp = Q31_BY_SUB_FRAME_240;
5678 945099 : tmp1 = 239; /* L_SUBFRAME_48k - 1 */
5679 945099 : move32();
5680 945099 : move32();
5681 945099 : BREAK;
5682 0 : case L_SUBFRAME_16k:
5683 0 : tmp = Q31_BY_SUB_FRAME_80;
5684 0 : tmp1 = 79; /* L_SUBFRAME_16k - 1 */
5685 0 : move32();
5686 0 : move32();
5687 0 : BREAK;
5688 0 : case L_SUBFRAME_8k:
5689 0 : tmp = Q31_BY_SUB_FRAME_40;
5690 0 : tmp1 = 39; /* L_SUBFRAME_8k - 1 */
5691 0 : move32();
5692 0 : move32();
5693 0 : BREAK;
5694 0 : default:
5695 0 : BREAK;
5696 : }
5697 : /* Otherwise use weighted average between previous and current gain */
5698 1233823144 : DO
5699 : {
5700 1235819280 : IF( EQ_32( i, tmp1 ) )
5701 : {
5702 1996136 : fadeIn = ONE_IN_Q31;
5703 1996136 : move32();
5704 : }
5705 : ELSE
5706 : {
5707 1233823144 : fadeIn = UL_Mpy_32_32( i, tmp );
5708 : }
5709 1235819280 : fadeOut = L_sub( ONE_IN_Q31, fadeIn );
5710 :
5711 1235819280 : *outSmpl = L_add( Mpy_32_32( L_add( Mpy_32_32( fadeIn, currentGain ), Mpy_32_32( fadeOut, previousGain ) ), ( *inSmpl ) ), *outSmpl );
5712 1235819280 : move32();
5713 1235819280 : ++outSmpl;
5714 1235819280 : ++inSmpl;
5715 1235819280 : ++i;
5716 : }
5717 1235819280 : WHILE( inSmpl != lastInSmpl );
5718 : }
5719 : }
5720 : }
5721 :
5722 4992179 : return;
5723 : }
5724 :
5725 :
5726 : /* Take one channel from input buffer and copy it to each channel
5727 : in output buffer, with different gain applied per output channel */
5728 4044679 : static void renderBufferChannel_fx(
5729 : const IVAS_REND_AudioBuffer inAudio,
5730 : const Word32 inChannelIdx,
5731 : const Word32 *const outputGains, /* Q31 */
5732 : IVAS_REND_AudioBuffer outAudio )
5733 : {
5734 4044679 : renderBufferChannelLerp_fx( inAudio, inChannelIdx, outputGains, NULL, outAudio );
5735 :
5736 4044679 : return;
5737 : }
5738 :
5739 70522 : static ivas_error chooseCrossfade_fx(
5740 : const IVAS_REND_HeadRotData *headRotData,
5741 : const Word32 **pCrossfade /* Q31 */ )
5742 : {
5743 70522 : *pCrossfade = headRotData->crossfade_fx;
5744 :
5745 70522 : return IVAS_ERR_OK;
5746 : }
5747 :
5748 :
5749 25504 : static ivas_error rotateFrameMc_fx(
5750 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
5751 : AUDIO_CONFIG inConfig, /* i : Input Audio config */
5752 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs, /* i : Input Custom LS setup */
5753 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
5754 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
5755 : rotation_gains_Word32 gains_prev, /* i/o: Previous frame rotation gains */
5756 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
5757 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
5758 : )
5759 : {
5760 : Word16 i;
5761 : Word16 j;
5762 : const Word32 *crossfade; /* Q31 */
5763 : Word16 num_subframes;
5764 : Word16 subframe_idx, subframe_len;
5765 : Word32 azimuth_fx, elevation_fx; /* Q22 */
5766 : Word16 is_planar_setup, lfe_idx;
5767 : Word16 nchan;
5768 : Word16 ch_in, ch_out;
5769 : Word16 ch_in_woLFE, ch_out_woLFE;
5770 25504 : Word32 *readPtr, *writePtr = NULL;
5771 : const Word32 *ls_azimuth, *ls_elevation;
5772 : rotation_matrix_fx Rmat_fx;
5773 : rotation_gains_Word32 gains;
5774 : Word32 tmp_gains[MAX_INPUT_CHANNELS]; /* Q30 */
5775 : ivas_error error;
5776 :
5777 25504 : push_wmops( "rotateFrameMc_fx" );
5778 25504 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
5779 : {
5780 0 : return error;
5781 : }
5782 25504 : IF( ( hCombinedOrientationData != NULL ) )
5783 : {
5784 25504 : num_subframes = ( *hCombinedOrientationData )->num_subframes;
5785 : }
5786 : ELSE
5787 : {
5788 0 : num_subframes = MAX_PARAM_SPATIAL_SUBFRAMES;
5789 : }
5790 25504 : move16();
5791 :
5792 25504 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
5793 : {
5794 12500 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ), IVAS_ERR_OK ) )
5795 : {
5796 0 : return error;
5797 : }
5798 : }
5799 : ELSE
5800 : {
5801 13004 : nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe );
5802 : }
5803 :
5804 25504 : IF( NE_32( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ), IVAS_ERR_OK ) )
5805 : {
5806 0 : return error;
5807 : }
5808 :
5809 : /* initialize gains to passthrough */
5810 319068 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
5811 : {
5812 293564 : set32_fx( gains[ch_in], 0, nchan );
5813 293564 : gains[ch_in][ch_in] = ONE_IN_Q30;
5814 293564 : move32();
5815 : }
5816 :
5817 : /* subframe loop */
5818 : Word16 tmp_e;
5819 25504 : Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e );
5820 25504 : tmp = shr( tmp, negate( add( 1, tmp_e ) ) );
5821 25504 : subframe_len = tmp;
5822 25504 : move16();
5823 :
5824 66314 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5825 : {
5826 163240 : FOR( i = 0; i < 3; i++ )
5827 : {
5828 122430 : IF( hCombinedOrientationData != NULL )
5829 : {
5830 489720 : FOR( j = 0; j < 3; j++ )
5831 : {
5832 367290 : Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
5833 367290 : move32();
5834 : }
5835 : }
5836 : ELSE
5837 : {
5838 : /* Set to identity */
5839 0 : set32_fx( Rmat_fx[i], 0, 3 );
5840 0 : Rmat_fx[i][i] = ONE_IN_Q30;
5841 0 : move32();
5842 : }
5843 : }
5844 :
5845 510570 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
5846 : {
5847 : /* skip LFE */
5848 469760 : IF( EQ_16( ch_in, lfe_idx ) )
5849 : {
5850 20000 : CONTINUE;
5851 : }
5852 :
5853 : /* input channel index without LFE */
5854 449760 : test();
5855 449760 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_in, lfe_idx ) ) )
5856 : {
5857 85600 : ch_in_woLFE = sub( ch_in, 1 );
5858 : }
5859 : ELSE
5860 : {
5861 364160 : ch_in_woLFE = ch_in;
5862 364160 : move16();
5863 : }
5864 :
5865 :
5866 : /* gains for current subframe rotation */
5867 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 );
5868 :
5869 449760 : test();
5870 449760 : test();
5871 449760 : IF( hEFAPdata != NULL && ( NE_32( ls_azimuth[ch_in_woLFE], azimuth_fx ) || NE_32( ls_elevation[ch_in_woLFE], elevation_fx ) ) )
5872 : {
5873 144730 : efap_determine_gains_fx( hEFAPdata, tmp_gains, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
5874 :
5875 1444790 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
5876 : {
5877 : /* skip LFE */
5878 1300060 : IF( EQ_16( ch_out, lfe_idx ) )
5879 : {
5880 144730 : CONTINUE;
5881 : }
5882 :
5883 : /* output channel index without LFE */
5884 1155330 : test();
5885 1155330 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_out, lfe_idx ) ) )
5886 : {
5887 721140 : ch_out_woLFE = sub( ch_out, 1 );
5888 : }
5889 : ELSE
5890 : {
5891 434190 : ch_out_woLFE = ch_out;
5892 434190 : move16();
5893 : }
5894 :
5895 1155330 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
5896 1155330 : move32();
5897 : }
5898 : }
5899 : }
5900 :
5901 : /* apply panning gains by mtx multiplication */
5902 510570 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
5903 : {
5904 6541120 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
5905 : {
5906 6071360 : writePtr = getSmplPtr_fx( outAudio, ch_out, imult1616( subframe_idx, subframe_len ) ); /* Qx */
5907 6071360 : readPtr = getSmplPtr_fx( inAudio, ch_in, imult1616( subframe_idx, subframe_len ) ); /* Qx */
5908 : /* crossfade with previous rotation gains */
5909 1463197760 : FOR( i = 0; i < subframe_len; i++ )
5910 : {
5911 1457126400 : *writePtr =
5912 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] ) ),
5913 1457126400 : Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); /* Qx - 1 */
5914 1457126400 : move32();
5915 1457126400 : readPtr++;
5916 1457126400 : writePtr++;
5917 : }
5918 : }
5919 : }
5920 :
5921 : /* move gains to gains_prev */
5922 510570 : FOR( i = 0; i < nchan; i++ )
5923 : {
5924 469760 : MVR2R_WORD32( gains[i], gains_prev[i], nchan );
5925 : }
5926 : }
5927 :
5928 25504 : pop_wmops();
5929 25504 : return IVAS_ERR_OK;
5930 : }
5931 :
5932 :
5933 45018 : static ivas_error rotateFrameSba_fx(
5934 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
5935 : const AUDIO_CONFIG inConfig, /* i : Input Audio config */
5936 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
5937 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
5938 : Word16 gains_prev[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS], /* i/o: Previous frame rotation gains Q14 */
5939 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
5940 : )
5941 : {
5942 : Word16 i, l, n, m;
5943 : Word16 m1, m2;
5944 : Word16 shd_rot_max_order;
5945 : const Word32 *crossfade; /* Q31 */
5946 : Word16 num_subframes;
5947 : Word16 subframe_idx, subframe_len;
5948 : Word32 *writePtr;
5949 : Word32 tmpRot[2 * HEADROT_ORDER + 1];
5950 : Word16 gains[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; /* Q14 */
5951 : Word32 temp;
5952 : Word32 Rmat[3][3]; /* Q30 */
5953 : ivas_error error;
5954 : Word16 idx, exp;
5955 : Word32 cf, oneminuscf; /* Q31 */
5956 : Word32 val;
5957 :
5958 45018 : push_wmops( "rotateFrameSba" );
5959 :
5960 45018 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
5961 : {
5962 0 : return error;
5963 : }
5964 45018 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
5965 45018 : move16();
5966 :
5967 45018 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inConfig, &shd_rot_max_order ) ), IVAS_ERR_OK ) )
5968 : {
5969 0 : return error;
5970 : }
5971 :
5972 : // subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
5973 45018 : subframe_len = BASOP_Util_Divide1616_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &exp );
5974 45018 : subframe_len = shr( subframe_len, sub( 15, exp ) );
5975 117063 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5976 : {
5977 : /* initialize rotation matrices with zeros */
5978 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5979 : {
5980 1152720 : set16_fx( gains[i], 0, HEADROT_SHMAT_DIM );
5981 : }
5982 :
5983 288180 : FOR( i = 0; i < 3; i++ )
5984 : {
5985 216135 : IF( hCombinedOrientationData != NULL )
5986 : {
5987 864540 : FOR( l = 0; l < 3; l++ )
5988 : {
5989 648405 : Rmat[i][l] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][l]; /* Q30 */
5990 648405 : move32();
5991 : }
5992 : }
5993 : ELSE
5994 : {
5995 : /* Set to identity */
5996 0 : set32_fx( Rmat[i], 0, 3 );
5997 0 : Rmat[i][i] = ONE_IN_Q30;
5998 0 : move32();
5999 : }
6000 : }
6001 : /* calculate ambisonics rotation matrices for the previous and current frames */
6002 72045 : SHrotmatgen_fx( gains, Rmat, shd_rot_max_order );
6003 :
6004 : #ifdef DEBUGGING
6005 : dbgwrite_txt( (const float *) ( gains[0] ), HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_code_gains.txt", NULL );
6006 : dbgwrite_txt( (const float *) ( Rmat[0] ), 3 * 3, "Fixed_code_Rmat.txt", NULL );
6007 : #endif
6008 17362845 : FOR( i = 0; i < subframe_len; i++ )
6009 : {
6010 17290800 : idx = add( imult1616( subframe_idx, subframe_len ), i );
6011 : // cf = crossfade[i];
6012 17290800 : cf = crossfade[i];
6013 17290800 : move32();
6014 17290800 : oneminuscf = L_sub( ONE_IN_Q31, cf );
6015 : /* As the rotation matrix becomes block diagonal in a SH basis, we can*/
6016 : /* apply each angular-momentum block individually to save complexity. */
6017 :
6018 : /* loop over l blocks */
6019 17290800 : m1 = 1;
6020 17290800 : m2 = 4;
6021 17290800 : move16();
6022 17290800 : move16();
6023 51872400 : FOR( l = 1; l <= shd_rot_max_order; l++ )
6024 : {
6025 : /* compute mtx-vector product for this l */
6026 184435200 : FOR( n = m1; n < m2; n++ )
6027 : {
6028 149853600 : tmpRot[n - m1] = 0;
6029 149853600 : move32();
6030 876067200 : FOR( m = m1; m < m2; m++ )
6031 : {
6032 726213600 : val = inAudio.data_fx[m * inAudio.config.numSamplesPerChannel + idx];
6033 : /* crossfade with previous rotation gains */
6034 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 );
6035 726213600 : tmpRot[n - m1] = L_add( L_shl( temp, 1 ), tmpRot[n - m1] );
6036 726213600 : move32();
6037 726213600 : move32();
6038 : }
6039 : }
6040 : /* write back the result */
6041 184435200 : FOR( n = m1; n < m2; n++ )
6042 : {
6043 149853600 : writePtr = getSmplPtr_fx( outAudio, n, idx );
6044 149853600 : ( *writePtr ) = tmpRot[n - m1];
6045 149853600 : move32();
6046 : }
6047 34581600 : m1 = m2;
6048 34581600 : move16();
6049 34581600 : m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
6050 : }
6051 : }
6052 :
6053 : /* move SHrotmat to SHrotmat_prev */
6054 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
6055 : {
6056 1152720 : Copy( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
6057 : }
6058 : }
6059 45018 : pop_wmops();
6060 :
6061 45018 : return IVAS_ERR_OK;
6062 : }
6063 :
6064 :
6065 150000 : static ivas_error renderIsmToBinaural(
6066 : input_ism *ismInput,
6067 : IVAS_REND_AudioBuffer outAudio )
6068 : {
6069 : Word32 tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6070 : ivas_error error;
6071 : Word16 ism_md_subframe_update_ext;
6072 : Word16 i;
6073 150000 : Word16 exp = *outAudio.pq_fact;
6074 150000 : move16();
6075 :
6076 150000 : push_wmops( "renderIsmToBinaural" );
6077 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6078 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 */ ) );
6079 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer );
6080 :
6081 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6082 : {
6083 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
6084 : }
6085 :
6086 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,
6087 : *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer, &exp ) ),
6088 : IVAS_ERR_OK ) )
6089 : {
6090 0 : return error;
6091 : }
6092 :
6093 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6094 : {
6095 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
6096 : }
6097 :
6098 150000 : IF( ismInput->hReverb != NULL )
6099 : {
6100 0 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
6101 : {
6102 0 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
6103 : {
6104 0 : tmpTDRendBuffer[i][j] = L_shl( tmpTDRendBuffer[i][j], Q2 ); /* Q(exp + 2) */
6105 0 : move32();
6106 : }
6107 : }
6108 : }
6109 150000 : accumulate2dArrayToBuffer_fx( tmpTDRendBuffer, &outAudio );
6110 :
6111 150000 : pop_wmops();
6112 :
6113 150000 : return IVAS_ERR_OK;
6114 : }
6115 :
6116 :
6117 0 : static Word16 getNumSubframesInBuffer(
6118 : const IVAS_REND_AudioBuffer *buffer,
6119 : const Word32 sampleRate )
6120 : {
6121 : Word16 cldfb2tdShift;
6122 :
6123 0 : cldfb2tdShift = buffer->config.is_cldfb ? 1 : 0;
6124 :
6125 0 : Word16 scale, temp = extract_l( Mpy_32_32( sampleRate, 10737418 /* 1 / FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
6126 0 : temp = BASOP_Util_Divide1616_Scale( buffer->config.numSamplesPerChannel, temp, &scale );
6127 0 : temp = shr( temp, sub( 15, scale ) ); /* Q0 */
6128 0 : temp = shr( temp, cldfb2tdShift );
6129 :
6130 0 : return temp;
6131 : }
6132 :
6133 :
6134 150000 : static ivas_error renderIsmToBinauralRoom(
6135 : input_ism *ismInput,
6136 : IVAS_REND_AudioBuffer outAudio,
6137 : Word16 *exp )
6138 : {
6139 : Word16 position_changed;
6140 : Word16 i, j;
6141 : Word32 azi_rot, ele_rot; /* Q22 */
6142 : Word16 subframe_idx;
6143 : Word16 tmp;
6144 : rotation_matrix_fx Rmat;
6145 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6146 : ivas_error error;
6147 : pan_vector_fx currentPanGains;
6148 : IVAS_REND_AudioBuffer tmpMcBuffer;
6149 : IVAS_ISM_METADATA rotatedPosPrev;
6150 : IVAS_ISM_METADATA rotatedPos;
6151 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6152 : Word8 combinedOrientationEnabled;
6153 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6154 :
6155 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6156 : {
6157 2400000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6158 : }
6159 :
6160 150000 : push_wmops( "renderIsmToBinauralRoom" );
6161 :
6162 150000 : rotatedPosPrev = defaultObjectPosition();
6163 150000 : rotatedPos = defaultObjectPosition();
6164 :
6165 150000 : hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
6166 150000 : combinedOrientationEnabled = 0;
6167 150000 : move16();
6168 150000 : IF( *hCombinedOrientationData != NULL )
6169 : {
6170 75000 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6171 : {
6172 75000 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6173 : {
6174 75000 : combinedOrientationEnabled = 1;
6175 75000 : move16();
6176 75000 : BREAK;
6177 : }
6178 : }
6179 : }
6180 :
6181 150000 : IF( combinedOrientationEnabled )
6182 : {
6183 150000 : FOR( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
6184 : {
6185 300000 : FOR( i = 0; i < 3; i++ )
6186 : {
6187 225000 : test();
6188 225000 : IF( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
6189 : {
6190 900000 : FOR( j = 0; j < 3; j++ )
6191 : {
6192 675000 : Rmat[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
6193 675000 : move32();
6194 : }
6195 : }
6196 : ELSE
6197 : {
6198 : /* Set to identity */
6199 0 : set_zero_fx( Rmat[i], 3 );
6200 0 : Rmat[i][i] = ONE_IN_Q30;
6201 0 : move32();
6202 : }
6203 : }
6204 : }
6205 : }
6206 :
6207 : /* get previous position */
6208 150000 : IF( combinedOrientationEnabled )
6209 : {
6210 75000 : rotateAziEle_fx_frac_az_el( ismInput->previousPos.azimuth_fx, ismInput->previousPos.elevation_fx, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
6211 75000 : rotatedPosPrev.azimuth_fx = azi_rot;
6212 75000 : move32();
6213 75000 : rotatedPosPrev.elevation_fx = ele_rot;
6214 75000 : move32();
6215 : }
6216 : ELSE
6217 : {
6218 75000 : rotatedPosPrev.azimuth_fx = ismInput->previousPos.azimuth_fx;
6219 75000 : move32();
6220 75000 : rotatedPosPrev.elevation_fx = ismInput->previousPos.elevation_fx;
6221 75000 : move32();
6222 : }
6223 :
6224 : /* get current position */
6225 150000 : IF( combinedOrientationEnabled )
6226 : {
6227 75000 : rotateAziEle_fx_frac_az_el( ismInput->currentPos.azimuth_fx, ismInput->currentPos.elevation_fx, &azi_rot, &ele_rot, Rmat, 0 );
6228 75000 : rotatedPos.azimuth_fx = azi_rot;
6229 75000 : move32();
6230 75000 : rotatedPos.elevation_fx = ele_rot;
6231 75000 : move32();
6232 : }
6233 : ELSE
6234 : {
6235 75000 : rotatedPos.azimuth_fx = ismInput->currentPos.azimuth_fx;
6236 75000 : move32();
6237 75000 : rotatedPos.elevation_fx = ismInput->currentPos.elevation_fx;
6238 75000 : move32();
6239 : }
6240 :
6241 150000 : test();
6242 150000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &rotatedPos, &rotatedPosPrev );
6243 150000 : move16();
6244 :
6245 : /* set previous gains if this is the first frame */
6246 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 ) )
6247 : {
6248 0 : return error;
6249 : }
6250 :
6251 : /* compute gains only if position changed */
6252 150000 : IF( position_changed )
6253 : {
6254 64693 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper, rotatedPos.azimuth_fx, rotatedPos.elevation_fx, currentPanGains ) ),
6255 : IVAS_ERR_OK ) )
6256 : {
6257 0 : return error;
6258 : }
6259 : }
6260 :
6261 : /* intermediate rendering to 7_1_4 */
6262 150000 : tmpMcBuffer = ismInput->base.inputBuffer;
6263 :
6264 150000 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
6265 : {
6266 0 : return error;
6267 : }
6268 :
6269 150000 : tmpMcBuffer.config.numChannels = tmp;
6270 150000 : move16();
6271 150000 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
6272 150000 : set_zero_fx( tmpMcBuffer.data_fx, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
6273 :
6274 150000 : IF( position_changed )
6275 : {
6276 64693 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains, ismInput->prev_pan_gains_fx, tmpMcBuffer );
6277 : }
6278 : ELSE
6279 : {
6280 85307 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, tmpMcBuffer );
6281 : }
6282 :
6283 150000 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpRendBuffer );
6284 :
6285 : /* save gains for next frame */
6286 600000 : FOR( i = 0; i < 3; i++ )
6287 : {
6288 450000 : Copy32( Rmat[i], ismInput->rot_mat_prev[i], 3 );
6289 : }
6290 :
6291 150000 : IF( position_changed )
6292 : {
6293 64693 : Copy32( currentPanGains, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
6294 : }
6295 :
6296 : CREND_HANDLE hCrend;
6297 150000 : hCrend = ismInput->crendWrapper->hCrend[0];
6298 150000 : IF( hCrend->reflections != NULL )
6299 : {
6300 0 : test();
6301 0 : IF( EQ_32( hCrend->reflections->use_er, 1 ) && EQ_32( hCrend->reflections->is_ready, 1 ) )
6302 : {
6303 0 : FOR( i = 0; i < 150; i++ )
6304 : {
6305 0 : hCrend->reflections->shoebox_data.gains.data_fx[i] = L_shl( hCrend->reflections->shoebox_data.gains.data_fx[i], Q9 );
6306 0 : move32();
6307 : }
6308 : }
6309 : }
6310 :
6311 150000 : *ismInput->crendWrapper->p_io_qfactor = *exp;
6312 150000 : move16();
6313 :
6314 : /* render 7_1_4 with BRIRs */
6315 150000 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, ismInput->base.inputBuffer.config.numSamplesPerChannel, *ismInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
6316 : {
6317 0 : return error;
6318 : }
6319 :
6320 150000 : IF( hCrend->hReverb != NULL )
6321 : {
6322 0 : *exp = sub( *exp, 2 );
6323 0 : move16();
6324 : }
6325 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
6326 :
6327 150000 : free( tmpMcBuffer.data_fx );
6328 :
6329 150000 : pop_wmops();
6330 :
6331 150000 : return IVAS_ERR_OK;
6332 : }
6333 :
6334 :
6335 150000 : static ivas_error renderIsmToBinauralReverb(
6336 : input_ism *ismInput,
6337 : IVAS_REND_AudioBuffer outAudio )
6338 : {
6339 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6340 : ivas_error error;
6341 : Word16 ism_md_subframe_update_ext, i;
6342 150000 : Word16 exp = *outAudio.pq_fact;
6343 150000 : move16();
6344 :
6345 150000 : push_wmops( "renderIsmToBinauralRoom" );
6346 :
6347 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6348 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 */ ) );
6349 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
6350 :
6351 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6352 : {
6353 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
6354 : }
6355 :
6356 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 ) )
6357 : {
6358 0 : return error;
6359 : }
6360 :
6361 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6362 : {
6363 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( 11, exp ) ) ); /* Q(exp) */
6364 : }
6365 :
6366 150000 : IF( ismInput->hReverb != NULL )
6367 : {
6368 450000 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
6369 : {
6370 115500000 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
6371 : {
6372 115200000 : tmpRendBuffer_fx[i][j] = L_shl( tmpRendBuffer_fx[i][j], 2 ); /* Q(exp + 2) */
6373 115200000 : move16();
6374 : }
6375 : }
6376 : }
6377 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6378 150000 : pop_wmops();
6379 :
6380 150000 : return IVAS_ERR_OK;
6381 : }
6382 :
6383 :
6384 569500 : static ivas_error renderIsmToMc(
6385 : input_ism *ismInput,
6386 : const IVAS_REND_AudioBuffer outAudio )
6387 : {
6388 : Word8 position_changed;
6389 : pan_vector_fx currentPanGains_fx; /* Q31 */
6390 : ivas_error error;
6391 :
6392 569500 : push_wmops( "renderIsmToMc" );
6393 :
6394 569500 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6395 569500 : move32();
6396 569500 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6397 569500 : move32();
6398 569500 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6399 569500 : move32();
6400 569500 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6401 569500 : move32();
6402 :
6403 569500 : test();
6404 569500 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
6405 569500 : move16();
6406 569500 : IF( EQ_32( *ismInput->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_STEREO ) )
6407 : {
6408 83500 : IF( ismInput->nonDiegeticPan )
6409 : {
6410 7500 : currentPanGains_fx[0] = L_add( L_shr( ismInput->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); /* Q31 */
6411 7500 : currentPanGains_fx[1] = L_sub( ONE_IN_Q31, currentPanGains_fx[0] ); /* Q31 */
6412 7500 : ismInput->prev_pan_gains_fx[0] = currentPanGains_fx[0]; /* Q31 */
6413 7500 : ismInput->prev_pan_gains_fx[1] = currentPanGains_fx[1]; /* Q31 */
6414 7500 : move32();
6415 7500 : move32();
6416 7500 : move32();
6417 7500 : move32();
6418 : }
6419 : ELSE
6420 : {
6421 76000 : set32_fx( currentPanGains_fx, 0, MAX_OUTPUT_CHANNELS );
6422 :
6423 : Word16 gains_fx[2];
6424 : Word16 azimuth_tmp, elevation_tmp;
6425 :
6426 76000 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
6427 76000 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
6428 :
6429 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
6430 76000 : currentPanGains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
6431 76000 : currentPanGains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
6432 76000 : move32();
6433 76000 : move32();
6434 :
6435 76000 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
6436 76000 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
6437 :
6438 76000 : set32_fx( ismInput->prev_pan_gains_fx, 0, MAX_OUTPUT_CHANNELS );
6439 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
6440 76000 : ismInput->prev_pan_gains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
6441 76000 : ismInput->prev_pan_gains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
6442 76000 : move32();
6443 76000 : move32();
6444 : }
6445 : }
6446 : ELSE
6447 : {
6448 : /* compute gains only if position changed */
6449 486000 : IF( position_changed )
6450 : {
6451 : // TODO tmu review when #215 is resolved
6452 207304 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
6453 : ismInput->currentPos.azimuth_fx,
6454 : ismInput->currentPos.elevation_fx,
6455 : currentPanGains_fx ) ),
6456 : IVAS_ERR_OK ) )
6457 : {
6458 0 : return error;
6459 : }
6460 : }
6461 :
6462 : /* set previous gains if this is the first frame */
6463 486000 : IF( !ismInput->firstFrameRendered )
6464 : {
6465 : // TODO tmu review when #215 is resolved
6466 188 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
6467 : ismInput->previousPos.azimuth_fx,
6468 : ismInput->previousPos.elevation_fx,
6469 : ismInput->prev_pan_gains_fx ) ),
6470 : IVAS_ERR_OK ) )
6471 : {
6472 0 : return error;
6473 : }
6474 : /* fix2float to be removed */
6475 : }
6476 : }
6477 :
6478 : /* Assume num channels in audio buffer to be 1.
6479 : * This should have been validated in IVAS_REND_FeedInputAudio() */
6480 569500 : IF( position_changed )
6481 : {
6482 244300 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains_fx, ismInput->prev_pan_gains_fx, outAudio );
6483 : }
6484 : ELSE
6485 : {
6486 325200 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, outAudio );
6487 : }
6488 :
6489 569500 : IF( position_changed )
6490 : {
6491 244300 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
6492 : }
6493 :
6494 569500 : pop_wmops();
6495 :
6496 :
6497 569500 : return IVAS_ERR_OK;
6498 : }
6499 :
6500 :
6501 228000 : static ivas_error renderIsmToSba(
6502 : input_ism *ismInput,
6503 : const AUDIO_CONFIG outConfig,
6504 : const IVAS_REND_AudioBuffer outAudio )
6505 : {
6506 : Word16 i;
6507 : Word8 position_changed;
6508 : Word16 ambiOrderOut;
6509 : Word16 numOutChannels;
6510 : pan_vector_fx currentPanGains_fx;
6511 : ivas_error error;
6512 228000 : error = IVAS_ERR_OK;
6513 228000 : move32();
6514 :
6515 228000 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6516 228000 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6517 228000 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6518 228000 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6519 228000 : move32();
6520 228000 : move32();
6521 228000 : move32();
6522 228000 : move32();
6523 :
6524 228000 : push_wmops( "renderIsmToSba" );
6525 :
6526 228000 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
6527 : {
6528 0 : return error;
6529 : }
6530 :
6531 228000 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &ambiOrderOut ) ), IVAS_ERR_OK ) )
6532 : {
6533 0 : return error;
6534 : }
6535 :
6536 228000 : test();
6537 228000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
6538 228000 : move16();
6539 :
6540 : /* set previous gains if this is the first frame */
6541 : Word16 azimuth_tmp, elevation_tmp;
6542 228000 : IF( !ismInput->firstFrameRendered )
6543 : {
6544 : // TODO tmu review when #215 is resolved
6545 84 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
6546 84 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
6547 84 : ivas_dirac_dec_get_response_fx( azimuth_tmp, elevation_tmp, ismInput->prev_pan_gains_fx, ambiOrderOut, Q29 );
6548 1428 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6549 : {
6550 1344 : ismInput->prev_pan_gains_fx[i] = L_shl_sat( ismInput->prev_pan_gains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
6551 1344 : move32();
6552 : }
6553 : }
6554 :
6555 : /* compute gains only if position changed */
6556 228000 : IF( position_changed )
6557 : {
6558 : // TODO tmu review when #215 is resolved
6559 88848 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
6560 88848 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
6561 88848 : ivas_dirac_dec_get_response_fx( azimuth_tmp, elevation_tmp, currentPanGains_fx, ambiOrderOut, Q29 );
6562 1510416 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6563 : {
6564 1421568 : currentPanGains_fx[i] = L_shl_sat( currentPanGains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
6565 1421568 : move32();
6566 : }
6567 : }
6568 :
6569 : /* Assume num channels in audio buffer to be 1.
6570 : * This should have been validated in IVAS_REND_FeedInputAudio() */
6571 228000 : IF( position_changed )
6572 : {
6573 88848 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains_fx, ismInput->prev_pan_gains_fx, outAudio );
6574 : }
6575 : ELSE
6576 : {
6577 139152 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, outAudio );
6578 : }
6579 :
6580 228000 : IF( position_changed )
6581 : {
6582 88848 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
6583 : }
6584 228000 : pop_wmops();
6585 :
6586 228000 : return error;
6587 : }
6588 :
6589 :
6590 0 : static ivas_error renderIsmToSplitBinaural(
6591 : input_ism *ismInput,
6592 : const IVAS_REND_AudioBuffer outAudio )
6593 : {
6594 : ivas_error error;
6595 : Word32 tmpProcessing[MAX_NUM_OBJECTS][L_FRAME48k];
6596 : Word16 pos_idx;
6597 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
6598 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
6599 : IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
6600 : IVAS_QUATERNION localHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
6601 : Word16 i;
6602 : Word32 tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
6603 0 : Word16 output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
6604 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
6605 : Word16 ism_md_subframe_update_ext, exp;
6606 :
6607 0 : push_wmops( "renderIsmToSplitBinaural" );
6608 :
6609 0 : pSplitRendWrapper = ismInput->base.ctx.pSplitRendWrapper;
6610 0 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
6611 :
6612 0 : exp = *outAudio.pq_fact;
6613 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6614 0 : ism_md_subframe_update_ext = (Word16) Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, ONE_BY_SUBFRAME_LEN_MS_Q31 );
6615 :
6616 0 : pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData;
6617 :
6618 0 : IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
6619 : {
6620 0 : FOR( i = 1; i < pCombinedOrientationData->num_subframes; ++i )
6621 : {
6622 0 : Copy_Quat_fx( &pCombinedOrientationData->Quaternions[0], &pCombinedOrientationData->Quaternions[i] );
6623 : }
6624 : }
6625 :
6626 : /* Save current head positions */
6627 0 : FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6628 : {
6629 0 : Copy_Quat_fx( &pCombinedOrientationData->Quaternions[i], &originalHeadRot[i] );
6630 : }
6631 :
6632 : /* Copy input audio to a processing buffer. */
6633 0 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
6634 :
6635 :
6636 0 : FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6637 : {
6638 : /* Update head positions */
6639 0 : IF( NE_16( pos_idx, 0 ) )
6640 : {
6641 : Word16 q_fact_orig;
6642 0 : FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6643 : {
6644 0 : pCombinedOrientationData->Quaternions[i].w_fx = L_negate( 12582912 ); // Q22
6645 0 : q_fact_orig = originalHeadRot[i].q_fact;
6646 0 : modify_Quat_q_fx( &originalHeadRot[i], &localHeadRot[i], Q22 );
6647 : /*euler*/
6648 0 : Quat2EulerDegree_fx( localHeadRot[i], &pCombinedOrientationData->Quaternions[i].z_fx, &pCombinedOrientationData->Quaternions[i].y_fx, &pCombinedOrientationData->Quaternions[i].x_fx );
6649 0 : pCombinedOrientationData->Quaternions[i].x_fx = L_add( pCombinedOrientationData->Quaternions[i].x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
6650 0 : pCombinedOrientationData->Quaternions[i].y_fx = L_add( pCombinedOrientationData->Quaternions[i].y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
6651 0 : pCombinedOrientationData->Quaternions[i].z_fx = L_add( pCombinedOrientationData->Quaternions[i].z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
6652 :
6653 0 : Euler2Quat_fx( deg2rad_fx( pCombinedOrientationData->Quaternions[i].x_fx ), deg2rad_fx( pCombinedOrientationData->Quaternions[i].y_fx ), deg2rad_fx( pCombinedOrientationData->Quaternions[i].z_fx ), &pCombinedOrientationData->Quaternions[i] );
6654 :
6655 0 : modify_Quat_q_fx( &pCombinedOrientationData->Quaternions[i], &pCombinedOrientationData->Quaternions[i], q_fact_orig );
6656 : }
6657 : }
6658 :
6659 :
6660 0 : FOR( i = 0; i < MAX_NUM_OBJECTS; ++i )
6661 : {
6662 0 : Scale_sig32( tmpProcessing[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
6663 : }
6664 :
6665 : /* Render */
6666 0 : IF( ( error = ivas_td_binaural_renderer_ext_fx( ( pos_idx == 0 ) ? &ismInput->tdRendWrapper : &ismInput->splitTdRendWrappers[sub( pos_idx, 1 )], ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos,
6667 : NULL, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, output_frame, tmpProcessing, &exp ) ) != IVAS_ERR_OK )
6668 : {
6669 0 : return error;
6670 : }
6671 :
6672 0 : FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
6673 : {
6674 0 : Scale_sig32( tmpProcessing[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
6675 : }
6676 :
6677 0 : IF( ismInput->hReverb != NULL )
6678 : {
6679 0 : FOR( i = 0; i < BINAURAL_CHANNELS; i++ )
6680 : {
6681 0 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
6682 : {
6683 0 : tmpProcessing[i][j] = L_shl( tmpProcessing[i][j], Q2 ); /* Q(exp + 2) */
6684 0 : move32();
6685 : }
6686 : }
6687 : }
6688 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
6689 : * overwrite original audio, which is still needed for rendering next head pose. */
6690 0 : Copy32( tmpProcessing[0], tmpBinaural[i_mult( 2, pos_idx )], output_frame );
6691 0 : Copy32( tmpProcessing[1], tmpBinaural[add( i_mult( 2, pos_idx ), 1 )], output_frame );
6692 :
6693 : /* Overwrite processing buffer with original input audio again */
6694 0 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
6695 : }
6696 :
6697 : /* Restore original head rotation */
6698 0 : FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6699 : {
6700 0 : Copy_Quat_fx( &originalHeadRot[i], &pCombinedOrientationData->Quaternions[i] );
6701 : }
6702 :
6703 0 : accumulate2dArrayToBuffer_fx( tmpBinaural, &outAudio );
6704 0 : pop_wmops();
6705 :
6706 : /* Encoding to split rendering bitstream done at a higher level */
6707 0 : return IVAS_ERR_OK;
6708 : }
6709 :
6710 :
6711 150 : static void renderIsmToMasa(
6712 : input_ism *ismInput,
6713 : IVAS_REND_AudioBuffer outAudio,
6714 : Word16 *exp )
6715 : {
6716 : Word32 tmpRendBuffer_fx[MAX_NUM_OBJECTS][L_FRAME48k];
6717 : Word16 i, guard_bits, q_min, q_diff;
6718 :
6719 150 : push_wmops( "renderIsmToMasa" );
6720 :
6721 150 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
6722 :
6723 150 : q_min = MAX_16;
6724 150 : move16();
6725 :
6726 750 : FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
6727 : {
6728 600 : q_min = s_min( q_min, L_norm_arr( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel ) );
6729 : }
6730 :
6731 150 : guard_bits = find_guarded_bits_fx( ismInput->base.inputBuffer.config.numSamplesPerChannel );
6732 150 : q_min = sub( add( q_min, *outAudio.pq_fact ), guard_bits );
6733 150 : q_diff = sub( q_min, *outAudio.pq_fact );
6734 :
6735 750 : FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
6736 : {
6737 600 : scale_sig32( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel, q_diff ); // *outAudio.pq_fact -> q_min
6738 : }
6739 :
6740 150 : ivas_omasa_ana_fx( ismInput->hOMasa, tmpRendBuffer_fx, &q_min, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
6741 :
6742 150 : *exp = q_min;
6743 150 : move16();
6744 :
6745 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6746 :
6747 150 : pop_wmops();
6748 :
6749 150 : return;
6750 : }
6751 :
6752 1247650 : static ivas_error renderInputIsm(
6753 : input_ism *ismInput,
6754 : const AUDIO_CONFIG outConfig,
6755 : const IVAS_REND_AudioBuffer outAudio )
6756 : {
6757 : ivas_error error;
6758 : IVAS_REND_AudioBuffer inAudio;
6759 1247650 : Word16 exp = *outAudio.pq_fact;
6760 1247650 : move16();
6761 :
6762 1247650 : error = IVAS_ERR_OK;
6763 1247650 : move32();
6764 1247650 : inAudio = ismInput->base.inputBuffer;
6765 :
6766 1247650 : IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6767 : {
6768 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" );
6769 : }
6770 1247650 : ismInput->base.numNewSamplesPerChannel = 0;
6771 1247650 : move32();
6772 :
6773 : /* Apply input gain to new audio */
6774 1247650 : v_multc_fixed( inAudio.data_fx, ismInput->base.gain_fx, inAudio.data_fx, imult1616( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
6775 1247650 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 );
6776 1247650 : move16();
6777 1247650 : exp = *outAudio.pq_fact;
6778 1247650 : move16();
6779 :
6780 : /* set combined orientation subframe info to start info */
6781 1247650 : ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
6782 :
6783 :
6784 1247650 : SWITCH( getAudioConfigType( outConfig ) )
6785 : {
6786 569500 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6787 569500 : error = renderIsmToMc( ismInput, outAudio );
6788 569500 : BREAK;
6789 228000 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6790 228000 : error = renderIsmToSba( ismInput, outConfig, outAudio );
6791 228000 : BREAK;
6792 450000 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6793 : SWITCH( outConfig )
6794 : {
6795 150000 : case IVAS_AUDIO_CONFIG_BINAURAL:
6796 150000 : error = renderIsmToBinaural( ismInput, outAudio );
6797 150000 : BREAK;
6798 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6799 150000 : error = renderIsmToBinauralRoom( ismInput, outAudio, &exp );
6800 150000 : BREAK;
6801 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
6802 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
6803 0 : error = renderIsmToSplitBinaural( ismInput, outAudio );
6804 0 : break;
6805 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6806 150000 : error = renderIsmToBinauralReverb( ismInput, outAudio );
6807 150000 : BREAK;
6808 0 : default:
6809 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6810 : }
6811 450000 : BREAK;
6812 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6813 150 : renderIsmToMasa( ismInput, outAudio, &exp );
6814 150 : BREAK;
6815 0 : default:
6816 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6817 : }
6818 :
6819 : /* Check error here to keep switch statement more compact */
6820 1247650 : IF( NE_32( error, IVAS_ERR_OK ) )
6821 : {
6822 0 : return error;
6823 : }
6824 :
6825 1247650 : ismInput->firstFrameRendered = TRUE;
6826 1247650 : move16();
6827 :
6828 1247650 : *outAudio.pq_fact = exp;
6829 1247650 : move16();
6830 :
6831 1247650 : return error;
6832 : }
6833 :
6834 1126140 : static ivas_error renderActiveInputsIsm(
6835 : IVAS_REND_HANDLE hIvasRend,
6836 : IVAS_REND_AudioBuffer outAudio )
6837 : {
6838 : Word16 i;
6839 : input_ism *pCurrentInput;
6840 : ivas_error error;
6841 1126140 : Word16 input_q = outAudio.q_factor;
6842 1126140 : move16();
6843 5630700 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
6844 : {
6845 4504560 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6846 : {
6847 : /* Skip inactive inputs */
6848 3256910 : CONTINUE;
6849 : }
6850 :
6851 1247650 : *outAudio.pq_fact = input_q;
6852 1247650 : move16();
6853 1247650 : IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6854 : {
6855 0 : return error;
6856 : }
6857 2925119650 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
6858 : {
6859 2923872000 : outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
6860 2923872000 : move32();
6861 : }
6862 1247650 : *outAudio.pq_fact = sub( input_q, 1 );
6863 1247650 : move16();
6864 : }
6865 1126140 : return IVAS_ERR_OK;
6866 : }
6867 :
6868 87012 : static ivas_error renderLfeToBinaural_fx(
6869 : const input_mc *mcInput,
6870 : const AUDIO_CONFIG outConfig,
6871 : IVAS_REND_AudioBuffer outAudio,
6872 : Word16 in_q,
6873 : Word16 out_q )
6874 : {
6875 : Word16 lfe_idx;
6876 : Word16 pose_idx, num_poses;
6877 : Word32 gain_fx;
6878 : Word16 ear_idx, i, r_shift;
6879 : Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL];
6880 : Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
6881 : const Word32 *lfeInput;
6882 : Word32 *writePtr;
6883 :
6884 87012 : assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" );
6885 :
6886 87012 : push_wmops( "renderLfeToBinaural" );
6887 87012 : gain_fx = GAIN_LFE_WORD32; /* 1.88364911f in Q30 */
6888 87012 : move32();
6889 :
6890 87012 : IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
6891 : {
6892 48000 : lfe_idx = LFE_CHANNEL;
6893 48000 : move16();
6894 : }
6895 39012 : ELSE IF( mcInput->customLsInput.num_lfe > 0 )
6896 : {
6897 0 : lfe_idx = mcInput->customLsInput.lfe_idx[0];
6898 0 : move16();
6899 : }
6900 : ELSE
6901 : {
6902 : /* no LFE to render */
6903 39012 : pop_wmops();
6904 39012 : return IVAS_ERR_OK;
6905 : }
6906 :
6907 : /* --- Prepare LFE signal to be added to binaural output --- */
6908 48000 : lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 );
6909 48000 : frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
6910 48000 : move16();
6911 48000 : num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
6912 48000 : move16();
6913 48000 : num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame );
6914 :
6915 : /* Assuming LFE should be delayed by less that the duration of one frame */
6916 48000 : assert( mcInput->binauralDelaySmp < frame_size );
6917 :
6918 : /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
6919 48000 : v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
6920 :
6921 : /* Continue filling tmp buffer, now with LFE signal from current frame */
6922 48000 : v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); /* Qx - 1 */
6923 :
6924 : /* Save remaining LFE samples of current frame for next frame */
6925 48000 : MVR2R_WORD32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame );
6926 48000 : r_shift = sub( sub( in_q, 1 ), out_q );
6927 :
6928 48000 : IF( r_shift != 0 )
6929 : {
6930 14533750 : FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ )
6931 : {
6932 14496000 : tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); /* Q(out_q) */
6933 14496000 : move32();
6934 : }
6935 : }
6936 :
6937 : /* Copy LFE to left and right binaural channels for all poses */
6938 48000 : IF( mcInput->base.ctx.pSplitRendWrapper != NULL )
6939 : {
6940 0 : num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
6941 0 : move16();
6942 : }
6943 : ELSE
6944 : {
6945 48000 : num_poses = 1;
6946 48000 : move16();
6947 : }
6948 :
6949 96000 : FOR( pose_idx = 0; pose_idx < num_poses; ++pose_idx )
6950 : {
6951 144000 : FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
6952 : {
6953 96000 : writePtr = getSmplPtr_fx( outAudio, add( i_mult( pose_idx, BINAURAL_CHANNELS ), ear_idx ), 0 );
6954 96000 : move32();
6955 96000 : v_add_fixed_no_hdrm( writePtr, tmpLfeBuffer, writePtr, frame_size ); /* Q(out_q) */
6956 : }
6957 : }
6958 :
6959 48000 : pop_wmops();
6960 :
6961 48000 : return IVAS_ERR_OK;
6962 : }
6963 :
6964 29004 : static ivas_error renderMcToBinaural(
6965 : input_mc *mcInput,
6966 : const AUDIO_CONFIG outConfig,
6967 : IVAS_REND_AudioBuffer outAudio )
6968 : {
6969 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6970 : AUDIO_CONFIG inConfig;
6971 : ivas_error error;
6972 : IVAS_REND_AudioBuffer tmpRotBuffer;
6973 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6974 : Word8 combinedOrientationEnabled;
6975 : Word16 subframe_idx;
6976 : Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS];
6977 : Word16 i;
6978 29004 : Word16 exp = *outAudio.pq_fact;
6979 29004 : move16();
6980 :
6981 493068 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6982 : {
6983 464064 : p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i];
6984 : }
6985 29004 : push_wmops( "renderMcToBinaural" );
6986 :
6987 29004 : inConfig = mcInput->base.inConfig;
6988 29004 : move32();
6989 29004 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6990 29004 : combinedOrientationEnabled = 0;
6991 29004 : move16();
6992 29004 : IF( *hCombinedOrientationData != NULL )
6993 : {
6994 14502 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6995 : {
6996 14502 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6997 : {
6998 14502 : combinedOrientationEnabled = 1;
6999 14502 : move16();
7000 14502 : BREAK;
7001 : }
7002 : }
7003 : }
7004 :
7005 29004 : test();
7006 29004 : test();
7007 29004 : test();
7008 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 ) ) ) )
7009 : {
7010 18754 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
7011 :
7012 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7013 : {
7014 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
7015 : }
7016 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,
7017 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ),
7018 : IVAS_ERR_OK ) )
7019 : {
7020 0 : return error;
7021 : }
7022 :
7023 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7024 : {
7025 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
7026 : }
7027 : }
7028 : ELSE
7029 : {
7030 : /* apply rotation */
7031 10250 : IF( combinedOrientationEnabled )
7032 : {
7033 2250 : tmpRotBuffer = mcInput->base.inputBuffer;
7034 2250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7035 2250 : set32_fx( tmpRotBuffer.data_fx, 0, imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
7036 :
7037 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[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ), IVAS_ERR_OK ) )
7038 : {
7039 0 : return error;
7040 : }
7041 :
7042 2250 : exp = sub( *outAudio.pq_fact, 1 );
7043 :
7044 2250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx );
7045 :
7046 2250 : free( tmpRotBuffer.data_fx );
7047 : }
7048 : ELSE
7049 : {
7050 8000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
7051 : }
7052 :
7053 : CREND_HANDLE hCrend;
7054 10250 : hCrend = mcInput->crendWrapper->hCrend[0];
7055 :
7056 10250 : *mcInput->crendWrapper->p_io_qfactor = exp;
7057 10250 : move16();
7058 :
7059 : /* call CREND */
7060 10250 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer_fx, p_tmpRendBuffer_fx, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
7061 : {
7062 0 : return error;
7063 : }
7064 :
7065 10250 : IF( hCrend->hReverb != NULL )
7066 : {
7067 0 : exp = sub( exp, 2 );
7068 : }
7069 : }
7070 :
7071 29004 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
7072 :
7073 29004 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
7074 :
7075 : {
7076 0 : return error;
7077 : }
7078 29004 : *outAudio.pq_fact = exp;
7079 29004 : move16();
7080 :
7081 29004 : pop_wmops();
7082 29004 : return IVAS_ERR_OK;
7083 : }
7084 :
7085 32000 : static ivas_error renderMcToBinauralRoom(
7086 : input_mc *mcInput,
7087 : const AUDIO_CONFIG outConfig,
7088 : IVAS_REND_AudioBuffer outAudio )
7089 : {
7090 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7091 : AUDIO_CONFIG inConfig;
7092 : ivas_error error;
7093 : IVAS_REND_AudioBuffer tmpRotBuffer;
7094 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
7095 : Word16 i;
7096 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7097 : Word8 combinedOrientationEnabled;
7098 : Word16 subframe_idx;
7099 32000 : Word16 exp = *outAudio.pq_fact;
7100 32000 : move16();
7101 :
7102 544000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7103 : {
7104 512000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
7105 : }
7106 :
7107 32000 : push_wmops( "renderMcToBinauralRoom" );
7108 32000 : inConfig = mcInput->base.inConfig;
7109 32000 : move32();
7110 32000 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
7111 32000 : combinedOrientationEnabled = 0;
7112 32000 : move16();
7113 32000 : IF( *hCombinedOrientationData != NULL )
7114 : {
7115 16000 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7116 : {
7117 16000 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7118 : {
7119 16000 : combinedOrientationEnabled = 1;
7120 16000 : move16();
7121 16000 : BREAK;
7122 : }
7123 : }
7124 : }
7125 :
7126 32000 : test();
7127 32000 : test();
7128 32000 : test();
7129 32000 : test();
7130 32000 : test();
7131 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 ) ) ) ) )
7132 : {
7133 5750 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
7134 :
7135 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7136 : {
7137 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
7138 : }
7139 :
7140 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,
7141 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ),
7142 : IVAS_ERR_OK ) )
7143 : {
7144 0 : return error;
7145 : }
7146 :
7147 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7148 : {
7149 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
7150 : }
7151 : }
7152 : ELSE
7153 : {
7154 : /* apply rotation */
7155 26250 : IF( combinedOrientationEnabled )
7156 : {
7157 10250 : tmpRotBuffer = mcInput->base.inputBuffer;
7158 10250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7159 10250 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
7160 :
7161 10250 : 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[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
7162 : IVAS_ERR_OK ) )
7163 : {
7164 0 : return error;
7165 : }
7166 :
7167 10250 : exp = sub( *outAudio.pq_fact, 1 );
7168 :
7169 10250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
7170 10250 : free( tmpRotBuffer.data_fx );
7171 : }
7172 : ELSE
7173 : {
7174 16000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
7175 : }
7176 :
7177 : CREND_HANDLE hCrend;
7178 26250 : hCrend = mcInput->crendWrapper->hCrend[0];
7179 :
7180 26250 : *mcInput->crendWrapper->p_io_qfactor = exp;
7181 26250 : move16();
7182 :
7183 : /* call CREND */
7184 26250 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
7185 : {
7186 0 : return error;
7187 : }
7188 :
7189 26250 : IF( hCrend->hReverb != NULL )
7190 : {
7191 10250 : exp = sub( exp, Q2 );
7192 : }
7193 : }
7194 :
7195 32000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
7196 :
7197 32000 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
7198 : {
7199 0 : return error;
7200 : }
7201 32000 : *outAudio.pq_fact = exp;
7202 32000 : move16();
7203 :
7204 32000 : pop_wmops();
7205 32000 : return IVAS_ERR_OK;
7206 : }
7207 :
7208 26008 : static ivas_error renderMcCustomLsToBinauralRoom(
7209 : input_mc *mcInput,
7210 : const AUDIO_CONFIG outConfig,
7211 : IVAS_REND_AudioBuffer outAudio )
7212 : {
7213 : Word16 i;
7214 : Word16 tmp;
7215 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7216 : ivas_error error;
7217 : IVAS_REND_AudioBuffer tmpRotBuffer;
7218 : IVAS_REND_AudioBuffer tmpMcBuffer;
7219 : IVAS_REND_AudioBuffer *tmpBufPtr;
7220 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7221 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7222 : Word8 combinedOrientationEnabled;
7223 : Word16 subframe_idx;
7224 26008 : Word16 exp = *outAudio.pq_fact;
7225 26008 : move16();
7226 26008 : push_wmops( "renderMcCustomLsToBinauralRoom" );
7227 26008 : tmpRotBuffer = outAudio; /* avoid compilation warning */
7228 :
7229 442136 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7230 : {
7231 416128 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7232 : }
7233 :
7234 26008 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
7235 26008 : combinedOrientationEnabled = 0;
7236 26008 : move16();
7237 26008 : IF( *hCombinedOrientationData != NULL )
7238 : {
7239 13004 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7240 : {
7241 13004 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7242 : {
7243 13004 : combinedOrientationEnabled = 1;
7244 13004 : move16();
7245 13004 : BREAK;
7246 : }
7247 : }
7248 : }
7249 :
7250 : /* apply rotation */
7251 26008 : IF( combinedOrientationEnabled )
7252 : {
7253 13004 : tmpRotBuffer = mcInput->base.inputBuffer;
7254 13004 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7255 13004 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
7256 :
7257 13004 : 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[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
7258 : IVAS_ERR_OK ) )
7259 : {
7260 0 : return error;
7261 : }
7262 13004 : exp = sub( *outAudio.pq_fact, Q1 );
7263 : }
7264 :
7265 : /* intermediate conversion to 7_1_4 */
7266 26008 : tmpMcBuffer = mcInput->base.inputBuffer;
7267 :
7268 26008 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
7269 : {
7270 0 : return error;
7271 : }
7272 :
7273 26008 : tmpMcBuffer.config.numChannels = tmp;
7274 26008 : move16();
7275 26008 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
7276 26008 : set32_fx( tmpMcBuffer.data_fx, 0, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
7277 :
7278 26008 : IF( combinedOrientationEnabled )
7279 : {
7280 13004 : tmpBufPtr = &tmpRotBuffer;
7281 : }
7282 : ELSE
7283 : {
7284 13004 : tmpBufPtr = &mcInput->base.inputBuffer;
7285 : }
7286 406136 : FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
7287 : {
7288 380128 : renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer );
7289 : }
7290 :
7291 26008 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
7292 :
7293 : CREND_HANDLE hCrend;
7294 26008 : hCrend = mcInput->crendWrapper->hCrend[0];
7295 :
7296 26008 : *mcInput->crendWrapper->p_io_qfactor = exp;
7297 26008 : move16();
7298 :
7299 : /* call CREND */
7300 26008 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
7301 : {
7302 0 : return error;
7303 : }
7304 :
7305 26008 : IF( hCrend->hReverb != NULL )
7306 : {
7307 13004 : exp = sub( exp, 2 );
7308 : }
7309 :
7310 26008 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
7311 :
7312 26008 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
7313 : {
7314 0 : return error;
7315 : }
7316 26008 : *outAudio.pq_fact = exp;
7317 26008 : move16();
7318 26008 : IF( combinedOrientationEnabled )
7319 : {
7320 13004 : free( tmpRotBuffer.data_fx );
7321 : }
7322 26008 : free( tmpMcBuffer.data_fx );
7323 :
7324 26008 : pop_wmops();
7325 26008 : return IVAS_ERR_OK;
7326 : }
7327 :
7328 196617 : static void renderMcToMc(
7329 : const input_mc *mcInput,
7330 : IVAS_REND_AudioBuffer outAudio )
7331 : {
7332 : Word16 i;
7333 : IVAS_REND_AudioBuffer inAudio;
7334 :
7335 196617 : push_wmops( "renderMcToMc" );
7336 196617 : inAudio = mcInput->base.inputBuffer;
7337 :
7338 1507289 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7339 : {
7340 1310672 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
7341 : }
7342 :
7343 196617 : pop_wmops();
7344 196617 : return;
7345 : }
7346 :
7347 75756 : static void renderMcToSba(
7348 : const input_mc *mcInput,
7349 : IVAS_REND_AudioBuffer outAudio )
7350 : {
7351 : Word16 i;
7352 : IVAS_REND_AudioBuffer inAudio;
7353 :
7354 75756 : push_wmops( "renderMcToSba" );
7355 75756 : inAudio = mcInput->base.inputBuffer;
7356 :
7357 591852 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7358 : {
7359 516096 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
7360 : }
7361 75756 : pop_wmops();
7362 75756 : return;
7363 : }
7364 :
7365 150 : static void renderMcToMasa(
7366 : input_mc *mcInput,
7367 : IVAS_REND_AudioBuffer outAudio )
7368 : {
7369 150 : push_wmops( "renderMcToMasa" );
7370 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7371 150 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
7372 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 );
7373 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
7374 :
7375 150 : pop_wmops();
7376 150 : return;
7377 : }
7378 :
7379 0 : static ivas_error renderMcToSplitBinaural(
7380 : input_mc *mcInput,
7381 : const AUDIO_CONFIG outConfig,
7382 : IVAS_REND_AudioBuffer outAudio )
7383 : {
7384 : Word16 i, j, pos_idx;
7385 : Word16 sf;
7386 : Word16 output_frame;
7387 : ivas_error error;
7388 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
7389 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
7390 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7391 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
7392 : Word32 tmpSplitBinauralBuffer[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
7393 : AUDIO_CONFIG inConfig;
7394 : IVAS_REND_AudioBuffer tmpRotBuffer;
7395 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
7396 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
7397 0 : Word16 exp = *outAudio.pq_fact;
7398 0 : move16();
7399 : CREND_HANDLE hCrend;
7400 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
7401 : Word16 q_fact_orig;
7402 :
7403 0 : push_wmops( "renderMcToSplitBinaural" );
7404 0 : inConfig = mcInput->base.inConfig;
7405 0 : move32();
7406 0 : output_frame = mcInput->base.inputBuffer.config.numSamplesPerChannel;
7407 0 : move16();
7408 :
7409 0 : pSplitRendWrapper = mcInput->base.ctx.pSplitRendWrapper;
7410 0 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
7411 0 : move32();
7412 0 : move32();
7413 :
7414 0 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7415 : {
7416 0 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
7417 0 : move32();
7418 : }
7419 :
7420 : /* save current head positions */
7421 0 : pCombinedOrientationDataLocal = *mcInput->base.ctx.pCombinedOrientationData;
7422 0 : move32();
7423 0 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
7424 0 : move32();
7425 0 : IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
7426 : {
7427 0 : FOR( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
7428 : {
7429 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[0], &combinedOrientationDataLocal.Quaternions[sf] );
7430 0 : FOR( i = 0; i < 3; i++ )
7431 : {
7432 0 : FOR( j = 0; j < 3; j++ )
7433 : {
7434 0 : combinedOrientationDataLocal.Rmat_fx[sf][i][j] = combinedOrientationDataLocal.Rmat_fx[0][i][j];
7435 0 : move32();
7436 : }
7437 : }
7438 : }
7439 : }
7440 :
7441 : /* temporary buffer for rotation in source format for CREND */
7442 0 : tmpRotBuffer = mcInput->base.inputBuffer;
7443 0 : move32();
7444 0 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
7445 : {
7446 0 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7447 : }
7448 :
7449 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7450 : {
7451 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[i], &Quaternions_orig[i] );
7452 : }
7453 :
7454 0 : FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
7455 : {
7456 : /* Update head positions */
7457 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7458 : {
7459 0 : Quaternions_abs.w_fx = L_negate( 12582912 ); // Q22
7460 0 : q_fact_orig = Quaternions_orig[i].q_fact;
7461 0 : modify_Quat_q_fx( &combinedOrientationDataLocal.Quaternions[i], &combinedOrientationDataLocal.Quaternions[i], Q22 );
7462 : /*euler*/
7463 0 : Quat2EulerDegree_fx( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z_fx, &Quaternions_abs.y_fx, &Quaternions_abs.x_fx );
7464 0 : Quaternions_abs.x_fx = L_add( Quaternions_abs.x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
7465 0 : Quaternions_abs.y_fx = L_add( Quaternions_abs.y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
7466 0 : Quaternions_abs.z_fx = L_add( Quaternions_abs.z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
7467 :
7468 0 : Euler2Quat_fx( deg2rad_fx( Quaternions_abs.x_fx ), deg2rad_fx( Quaternions_abs.y_fx ), deg2rad_fx( Quaternions_abs.z_fx ), &Quaternions_abs );
7469 :
7470 0 : modify_Quat_q_fx( &Quaternions_abs, &Quaternions_abs, q_fact_orig );
7471 :
7472 0 : Copy_Quat_fx( &Quaternions_abs, &combinedOrientationDataLocal.Quaternions[i] );
7473 0 : QuatToRotMat_fx( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat_fx[i] );
7474 0 : modify_Rmat_q_fx( combinedOrientationDataLocal.Rmat_fx[i], combinedOrientationDataLocal.Rmat_fx[i], sub( shl( q_fact_orig, 1 ), 32 ), Q30 );
7475 : }
7476 :
7477 0 : IF( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
7478 : {
7479 : /* tdrend processing overview:
7480 : * 1. copy from inputBuffer to tmpRendBuffer
7481 : * 2. td_binaural_renderer_ext: inplace processing in tmpRendBuffer
7482 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
7483 : * 4. LFE mixing
7484 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
7485 :
7486 : /* copy input to tdrend input/output buffer */
7487 0 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
7488 :
7489 : /* perform rotation in source format to tmpRotBuffer */
7490 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7491 :
7492 0 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7493 : {
7494 0 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
7495 : }
7496 : /* Render */
7497 0 : IF( ( error = ivas_td_binaural_renderer_ext_fx( ( pos_idx == 0 ) ? &mcInput->tdRendWrapper : &mcInput->splitTdRendWrappers[pos_idx - 1], mcInput->base.inConfig, &mcInput->customLsInput, &pCombinedOrientationDataLocal, NULL, mcInput->hReverb, 0, /* Ism Audio Metadata Delay Sync in ms for External Renderer */ *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ) != IVAS_ERR_OK )
7498 : {
7499 0 : return error;
7500 : }
7501 0 : FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
7502 : {
7503 0 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
7504 : }
7505 :
7506 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
7507 : * overwrite original audio, which is still needed for rendering next head pose. */
7508 0 : Copy32( tmpRendBuffer[0], tmpSplitBinauralBuffer[i_mult( 2, pos_idx )], output_frame );
7509 0 : Copy32( tmpRendBuffer[1], tmpSplitBinauralBuffer[add( i_mult( 2, pos_idx ), 1 )], output_frame );
7510 : }
7511 : ELSE
7512 : {
7513 0 : hCrend = mcInput->crendWrapper->hCrend[0];
7514 : /* crend processing overview:
7515 : * 1. rotateFrameMc: inputBuffer to tmpRotBuffer
7516 : * 2. crend_process: tmpRotBuffer to tmpRendBuffer
7517 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
7518 : * 4. LFE mixing
7519 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
7520 :
7521 :
7522 : /* copy input for in-place rotation */
7523 0 : set32_fx( tmpRotBuffer.data_fx, 0, i_mult( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
7524 :
7525 : /* perform rotation in source format to tmpRotBuffer */
7526 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7527 0 : IF( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, mcInput->rot_gains_prev_fx[pos_idx], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
7528 : {
7529 0 : return error;
7530 : }
7531 0 : IF( EQ_16( pos_idx, 0 ) )
7532 : {
7533 0 : exp = sub( *outAudio.pq_fact, 1 );
7534 : }
7535 :
7536 0 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
7537 :
7538 0 : *mcInput->crendWrapper->p_io_qfactor = exp;
7539 0 : move16();
7540 :
7541 : /* call CREND (rotation already performed) */
7542 0 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, pos_idx ) ), IVAS_ERR_OK ) )
7543 : {
7544 0 : return error;
7545 : }
7546 :
7547 0 : IF( EQ_16( pos_idx, 0 ) )
7548 : {
7549 0 : IF( hCrend->hReverb != NULL )
7550 : {
7551 0 : exp = sub( exp, 2 );
7552 : }
7553 : }
7554 :
7555 : /* Copy rendererd audio to tmp storage buffer, Copying directly to output would
7556 : * overwrite original audio, which is still needed for rendering next head pose. */
7557 0 : Copy32( tmpRendBuffer[0], tmpSplitBinauralBuffer[i_mult( 2, pos_idx )], output_frame );
7558 0 : Copy32( tmpRendBuffer[1], tmpSplitBinauralBuffer[add( i_mult( 2, pos_idx ), 1 )], output_frame );
7559 : }
7560 :
7561 : /* restore original headrotation data */
7562 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7563 : {
7564 0 : Copy_Quat_fx( &Quaternions_orig[i], &combinedOrientationDataLocal.Quaternions[i] );
7565 : }
7566 : }
7567 :
7568 0 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
7569 : {
7570 : /* free temporary buffer for rotation in source format for CREND */
7571 0 : free( tmpRotBuffer.data_fx );
7572 : }
7573 :
7574 0 : accumulate2dArrayToBuffer_fx( tmpSplitBinauralBuffer, &outAudio );
7575 :
7576 0 : IF( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ) != IVAS_ERR_OK )
7577 : {
7578 0 : return error;
7579 : }
7580 0 : *outAudio.pq_fact = exp;
7581 :
7582 0 : pop_wmops();
7583 0 : return IVAS_ERR_OK;
7584 : }
7585 :
7586 :
7587 359535 : static ivas_error renderInputMc(
7588 : input_mc *mcInput,
7589 : const AUDIO_CONFIG outConfig,
7590 : IVAS_REND_AudioBuffer outAudio )
7591 : {
7592 : ivas_error error;
7593 : IVAS_REND_AudioBuffer inAudio;
7594 359535 : error = IVAS_ERR_OK;
7595 359535 : move32();
7596 :
7597 359535 : inAudio = mcInput->base.inputBuffer;
7598 :
7599 359535 : IF( NE_32( mcInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
7600 : {
7601 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" );
7602 : }
7603 359535 : mcInput->base.numNewSamplesPerChannel = 0;
7604 359535 : move32();
7605 359535 : v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
7606 359535 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 ); // reducing the Q by 1 compensating for the v_mult_fixed done
7607 359535 : move16();
7608 : /* set combined orientation subframe info to start info */
7609 359535 : ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
7610 :
7611 359535 : SWITCH( getAudioConfigType( outConfig ) )
7612 : {
7613 196617 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
7614 196617 : renderMcToMc( mcInput, outAudio );
7615 196617 : BREAK;
7616 75756 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
7617 75756 : renderMcToSba( mcInput, outAudio );
7618 75756 : BREAK;
7619 87012 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
7620 : SWITCH( outConfig )
7621 : {
7622 29004 : case IVAS_AUDIO_CONFIG_BINAURAL:
7623 29004 : error = renderMcToBinaural( mcInput, outConfig, outAudio );
7624 29004 : BREAK;
7625 58008 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
7626 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
7627 58008 : IF( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
7628 : {
7629 26008 : error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
7630 : }
7631 : ELSE
7632 : {
7633 32000 : error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
7634 : }
7635 58008 : BREAK;
7636 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
7637 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
7638 0 : error = renderMcToSplitBinaural( mcInput, outConfig, outAudio );
7639 0 : break;
7640 0 : default:
7641 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7642 : }
7643 87012 : BREAK;
7644 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
7645 150 : renderMcToMasa( mcInput, outAudio );
7646 150 : BREAK;
7647 0 : default:
7648 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7649 : }
7650 359535 : return error;
7651 : }
7652 :
7653 :
7654 1126140 : static ivas_error renderActiveInputsMc(
7655 : IVAS_REND_HANDLE hIvasRend,
7656 : IVAS_REND_AudioBuffer outAudio )
7657 : {
7658 : Word16 i;
7659 : input_mc *pCurrentInput;
7660 : ivas_error error;
7661 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMc ); i < RENDERER_MAX_MC_INPUTS; ( ++i, ++pCurrentInput ) )
7662 : {
7663 1126140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7664 : {
7665 : /* Skip inactive inputs */
7666 766605 : CONTINUE;
7667 : }
7668 :
7669 359535 : *outAudio.pq_fact = outAudio.q_factor;
7670 359535 : move16();
7671 359535 : IF( NE_32( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
7672 : {
7673 0 : return error;
7674 : }
7675 : }
7676 :
7677 1126140 : return IVAS_ERR_OK;
7678 : }
7679 :
7680 :
7681 115801 : static void renderSbaToMc(
7682 : const input_sba *sbaInput,
7683 : IVAS_REND_AudioBuffer outAudio )
7684 : {
7685 : Word16 i;
7686 : IVAS_REND_AudioBuffer inAudio;
7687 :
7688 115801 : push_wmops( "renderSbaToMc" );
7689 115801 : inAudio = sbaInput->base.inputBuffer;
7690 :
7691 1225294 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7692 : {
7693 1109493 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
7694 : }
7695 :
7696 115801 : pop_wmops();
7697 115801 : return;
7698 : }
7699 :
7700 :
7701 45768 : static void renderSbaToSba(
7702 : const input_sba *sbaInput,
7703 : IVAS_REND_AudioBuffer outAudio )
7704 : {
7705 : Word16 i;
7706 : IVAS_REND_AudioBuffer inAudio;
7707 :
7708 45768 : push_wmops( "renderSbaToSba" );
7709 45768 : inAudio = sbaInput->base.inputBuffer;
7710 :
7711 483942 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7712 : {
7713 438174 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
7714 : }
7715 :
7716 45768 : pop_wmops();
7717 45768 : return;
7718 : }
7719 :
7720 :
7721 0 : static ivas_error renderSbaToMultiBinaural(
7722 : input_sba *sbaInput,
7723 : const AUDIO_CONFIG outConfig,
7724 : Word32 out[][L_FRAME48k],
7725 : const Word16 *pq_fact )
7726 : {
7727 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7728 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7729 : Word16 sf;
7730 : Word16 i, j, pos_idx;
7731 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
7732 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
7733 : ivas_error error;
7734 : IVAS_REND_AudioBuffer tmpRotBuffer;
7735 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
7736 :
7737 0 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7738 : {
7739 0 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7740 0 : move32();
7741 : }
7742 0 : push_wmops( "renderSbaToMultiBinaural" );
7743 0 : pMultiBinPoseData = &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData;
7744 0 : move32();
7745 :
7746 0 : pCombinedOrientationDataLocal = *sbaInput->base.ctx.pCombinedOrientationData;
7747 0 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
7748 0 : move32();
7749 0 : move32();
7750 :
7751 0 : IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
7752 : {
7753 0 : FOR( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
7754 : {
7755 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[0], &combinedOrientationDataLocal.Quaternions[sf] );
7756 0 : FOR( i = 0; i < 3; i++ )
7757 : {
7758 0 : FOR( j = 0; j < 3; j++ )
7759 : {
7760 0 : combinedOrientationDataLocal.Rmat_fx[sf][i][j] = combinedOrientationDataLocal.Rmat_fx[0][i][j];
7761 0 : move32();
7762 : }
7763 : }
7764 : }
7765 : }
7766 :
7767 0 : tmpRotBuffer = sbaInput->base.inputBuffer;
7768 0 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7769 :
7770 0 : FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
7771 : {
7772 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
7773 : Word16 q_fact_orig;
7774 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7775 : {
7776 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[i], &Quaternions_orig[i] );
7777 :
7778 0 : Quaternions_abs.w_fx = L_negate( 12582912 ); // Q22
7779 0 : q_fact_orig = combinedOrientationDataLocal.Quaternions[i].q_fact;
7780 0 : modify_Quat_q_fx( &combinedOrientationDataLocal.Quaternions[i], &combinedOrientationDataLocal.Quaternions[i], Q22 );
7781 : /*euler*/
7782 0 : Quat2EulerDegree_fx( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z_fx, &Quaternions_abs.y_fx, &Quaternions_abs.x_fx );
7783 0 : Quaternions_abs.x_fx = L_add( Quaternions_abs.x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
7784 0 : Quaternions_abs.y_fx = L_add( Quaternions_abs.y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
7785 0 : Quaternions_abs.z_fx = L_add( Quaternions_abs.z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
7786 :
7787 0 : Euler2Quat_fx( deg2rad_fx( Quaternions_abs.x_fx ), deg2rad_fx( Quaternions_abs.y_fx ), deg2rad_fx( Quaternions_abs.z_fx ), &Quaternions_abs );
7788 :
7789 0 : modify_Quat_q_fx( &Quaternions_abs, &Quaternions_abs, q_fact_orig );
7790 :
7791 0 : Copy_Quat_fx( &Quaternions_abs, &combinedOrientationDataLocal.Quaternions[i] );
7792 0 : QuatToRotMat_fx( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat_fx[i] );
7793 0 : modify_Rmat_q_fx( combinedOrientationDataLocal.Rmat_fx[i], combinedOrientationDataLocal.Rmat_fx[i], sub( shl( q_fact_orig, 1 ), 32 ), Q30 );
7794 : }
7795 :
7796 : /* copy input for in-place rotation */
7797 0 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7798 :
7799 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7800 :
7801 0 : IF( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, sbaInput->rot_gains_prev_fx[pos_idx], tmpRotBuffer ) ) != IVAS_ERR_OK )
7802 : {
7803 0 : return error;
7804 : }
7805 :
7806 0 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpCrendBuffer );
7807 :
7808 0 : assert( sbaInput->crendWrapper->hCrend[0]->hReverb == NULL );
7809 :
7810 0 : *sbaInput->crendWrapper->p_io_qfactor = *pq_fact;
7811 0 : move16();
7812 :
7813 : /* call CREND */
7814 0 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, pos_idx ) ), IVAS_ERR_OK ) )
7815 : {
7816 0 : return error;
7817 : }
7818 :
7819 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7820 : {
7821 0 : Copy_Quat_fx( &Quaternions_orig[i], &combinedOrientationDataLocal.Quaternions[i] );
7822 : }
7823 :
7824 : /* move to output */
7825 0 : FOR( i = 0; i < BINAURAL_CHANNELS; i++ )
7826 : {
7827 0 : Copy32( tmpCrendBuffer[i], out[pos_idx * BINAURAL_CHANNELS + i], tmpRotBuffer.config.numSamplesPerChannel );
7828 : }
7829 : }
7830 :
7831 0 : free( tmpRotBuffer.data_fx );
7832 :
7833 0 : pop_wmops();
7834 0 : return IVAS_ERR_OK;
7835 : }
7836 :
7837 :
7838 0 : static ivas_error renderSbaToMultiBinauralCldfb(
7839 : input_sba *sbaInput,
7840 : Word32 Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7841 : Word32 Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7842 : const Word16 low_res_pre_rend_rot,
7843 : const Word16 num_subframes,
7844 : const Word16 Q_in )
7845 : {
7846 : Word32 Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7847 : Word32 Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7848 :
7849 0 : copyBufferToCLDFBarray_fx( sbaInput->base.inputBuffer, Cldfb_RealBuffer, Cldfb_ImagBuffer );
7850 :
7851 0 : ivas_rend_CldfbMultiBinRendProcess( sbaInput->cldfbRendWrapper.hCldfbRend, sbaInput->base.ctx.pCombinedOrientationData, &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData,
7852 : Cldfb_RealBuffer, Cldfb_ImagBuffer, Cldfb_Out_Real, Cldfb_Out_Imag, low_res_pre_rend_rot, num_subframes, Q_in );
7853 :
7854 0 : return IVAS_ERR_OK;
7855 : }
7856 :
7857 :
7858 0 : static ivas_error renderSbaToSplitBinaural(
7859 : input_sba *sbaInput,
7860 : const AUDIO_CONFIG outConfig,
7861 : IVAS_REND_AudioBuffer outAudio )
7862 : {
7863 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7864 : ivas_error error;
7865 : Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7866 : Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7867 : Word16 low_res_pre_rend_rot;
7868 :
7869 0 : low_res_pre_rend_rot = 1;
7870 :
7871 0 : push_wmops( "renderSbaToSplitBinaural" );
7872 :
7873 : #ifdef FIX_HRTF_LOAD
7874 0 : IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
7875 : #else
7876 : IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
7877 : #endif
7878 : {
7879 0 : IF( ( error = renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, low_res_pre_rend_rot,
7880 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ), *outAudio.pq_fact ) ) != IVAS_ERR_OK )
7881 : {
7882 0 : return error;
7883 : }
7884 :
7885 0 : accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7886 : }
7887 : ELSE
7888 : {
7889 0 : IF( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer, outAudio.pq_fact ) ) != IVAS_ERR_OK )
7890 : {
7891 0 : return error;
7892 : }
7893 :
7894 0 : IF( sbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
7895 : {
7896 0 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
7897 0 : move16();
7898 : }
7899 :
7900 0 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
7901 : }
7902 :
7903 0 : pop_wmops();
7904 0 : return IVAS_ERR_OK;
7905 : }
7906 :
7907 :
7908 60024 : static ivas_error renderSbaToBinaural(
7909 : input_sba *sbaInput,
7910 : const AUDIO_CONFIG outConfig,
7911 : IVAS_REND_AudioBuffer outAudio )
7912 : {
7913 : ivas_error error;
7914 : IVAS_REND_AudioBuffer tmpRotBuffer;
7915 : Word16 i;
7916 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7917 : Word8 combinedOrientationEnabled;
7918 : Word16 subframe_idx;
7919 : Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7920 : Word32 *output_fx[MAX_OUTPUT_CHANNELS];
7921 :
7922 60024 : push_wmops( "renderSbaToBinaural" );
7923 :
7924 : #ifdef FIX_HRTF_LOAD
7925 60024 : IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
7926 : #else
7927 : IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
7928 : #endif
7929 : {
7930 : Word32 Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7931 : Word32 Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7932 :
7933 0 : IF( ( error = renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 0,
7934 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ), *outAudio.pq_fact ) ) != IVAS_ERR_OK )
7935 : {
7936 0 : return error;
7937 : }
7938 :
7939 0 : accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7940 : }
7941 : ELSE
7942 : {
7943 1020408 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7944 : {
7945 960384 : output_fx[i] = output_buffer_fx[i];
7946 960384 : move32();
7947 : }
7948 :
7949 60024 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7950 60024 : combinedOrientationEnabled = 0;
7951 60024 : move16();
7952 60024 : IF( *hCombinedOrientationData != NULL )
7953 : {
7954 30012 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7955 : {
7956 30012 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7957 : {
7958 30012 : combinedOrientationEnabled = 1;
7959 30012 : move16();
7960 30012 : BREAK;
7961 : }
7962 : }
7963 : }
7964 :
7965 : /* apply rotation */
7966 60024 : IF( combinedOrientationEnabled )
7967 : {
7968 30012 : tmpRotBuffer = sbaInput->base.inputBuffer;
7969 :
7970 30012 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7971 :
7972 : /* copy input for in-place rotation */
7973 30012 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
7974 :
7975 30012 : IF( NE_16( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx[0], tmpRotBuffer ) ),
7976 : IVAS_ERR_OK ) )
7977 : {
7978 0 : return error;
7979 : }
7980 :
7981 30012 : copyBufferTo2dArray_fx( tmpRotBuffer, output_buffer_fx );
7982 30012 : free( tmpRotBuffer.data_fx );
7983 : }
7984 : ELSE
7985 : {
7986 30012 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, output_buffer_fx );
7987 : }
7988 :
7989 : CREND_HANDLE hCrend;
7990 60024 : hCrend = sbaInput->crendWrapper->hCrend[0];
7991 :
7992 60024 : *sbaInput->crendWrapper->p_io_qfactor = *outAudio.pq_fact;
7993 60024 : move16();
7994 :
7995 : /* call CREND */
7996 60024 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, output_fx, output_fx, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
7997 : {
7998 0 : return error;
7999 : }
8000 :
8001 60024 : IF( hCrend->hReverb != NULL )
8002 : {
8003 30012 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
8004 30012 : move16();
8005 : }
8006 :
8007 60024 : accumulate2dArrayToBuffer_fx( output_buffer_fx, &outAudio );
8008 : }
8009 :
8010 60024 : pop_wmops();
8011 60024 : return IVAS_ERR_OK;
8012 : }
8013 :
8014 :
8015 30012 : static ivas_error renderSbaToBinauralRoom(
8016 : input_sba *sbaInput,
8017 : const AUDIO_CONFIG outConfig,
8018 : IVAS_REND_AudioBuffer outAudio )
8019 : {
8020 : Word16 i;
8021 : Word16 tmp;
8022 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8023 : ivas_error error;
8024 : IVAS_REND_AudioBuffer tmpRotBuffer;
8025 : IVAS_REND_AudioBuffer tmpMcBuffer;
8026 : IVAS_REND_AudioBuffer *tmpBufPtr;
8027 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
8028 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
8029 : Word8 combinedOrientationEnabled;
8030 : Word16 subframe_idx;
8031 :
8032 30012 : tmpRotBuffer = outAudio; /* avoid compilation warning */
8033 30012 : push_wmops( "renderSbaToBinauralRoom" );
8034 : Word16 nchan_out;
8035 : CREND_HANDLE hCrend;
8036 30012 : hCrend = sbaInput->crendWrapper->hCrend[0];
8037 :
8038 30012 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ), IVAS_ERR_OK ) )
8039 : {
8040 0 : return error;
8041 : }
8042 :
8043 510204 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
8044 : {
8045 480192 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
8046 : }
8047 :
8048 30012 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
8049 30012 : combinedOrientationEnabled = 0;
8050 30012 : move16();
8051 30012 : IF( *hCombinedOrientationData != NULL )
8052 : {
8053 15006 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
8054 : {
8055 15006 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
8056 : {
8057 15006 : combinedOrientationEnabled = 1;
8058 15006 : move16();
8059 15006 : BREAK;
8060 : }
8061 : }
8062 : }
8063 :
8064 : /* apply rotation */
8065 30012 : IF( combinedOrientationEnabled )
8066 : {
8067 15006 : tmpRotBuffer = sbaInput->base.inputBuffer;
8068 15006 : tmpRotBuffer.data_fx = malloc( imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) * sizeof( Word32 ) );
8069 :
8070 : /* copy input for in-place rotation */
8071 15006 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
8072 :
8073 15006 : IF( NE_32( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx[0], tmpRotBuffer ) ),
8074 : IVAS_ERR_OK ) )
8075 : {
8076 0 : return error;
8077 : }
8078 : }
8079 :
8080 : /* intermediate rendering to 7_1_4 */
8081 30012 : tmpMcBuffer = sbaInput->base.inputBuffer;
8082 :
8083 30012 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
8084 : {
8085 0 : return error;
8086 : }
8087 :
8088 30012 : tmpMcBuffer.config.numChannels = tmp;
8089 30012 : move16();
8090 30012 : tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) );
8091 30012 : set32_fx( tmpMcBuffer.data_fx, 0, i_mult( tmpMcBuffer.config.numChannels, tmpMcBuffer.config.numSamplesPerChannel ) );
8092 :
8093 30012 : IF( combinedOrientationEnabled )
8094 : {
8095 15006 : tmpBufPtr = &tmpRotBuffer;
8096 : }
8097 : ELSE
8098 : {
8099 15006 : tmpBufPtr = &sbaInput->base.inputBuffer;
8100 : }
8101 320128 : FOR( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
8102 : {
8103 290116 : renderBufferChannel_fx( *tmpBufPtr, i, sbaInput->hoaDecMtx_fx[i], tmpMcBuffer );
8104 : }
8105 :
8106 30012 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
8107 :
8108 30012 : *sbaInput->crendWrapper->p_io_qfactor = *outAudio.pq_fact;
8109 30012 : move16();
8110 :
8111 : /* call CREND */
8112 30012 : IF( NE_32( ( error = ivas_rend_crendProcessSubframe_fx( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
8113 : {
8114 0 : return error;
8115 : }
8116 :
8117 30012 : IF( hCrend->hReverb != NULL )
8118 : {
8119 0 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 2 );
8120 0 : move16();
8121 : }
8122 :
8123 30012 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
8124 :
8125 30012 : IF( combinedOrientationEnabled )
8126 : {
8127 15006 : free( tmpRotBuffer.data_fx );
8128 : }
8129 30012 : free( tmpMcBuffer.data_fx );
8130 :
8131 30012 : pop_wmops();
8132 30012 : return IVAS_ERR_OK;
8133 : }
8134 :
8135 :
8136 150 : static void renderSbaToMasa(
8137 : input_sba *sbaInput,
8138 : IVAS_REND_AudioBuffer outAudio )
8139 : {
8140 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8141 :
8142 150 : push_wmops( "renderMcToMasa" );
8143 150 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, tmpRendBuffer );
8144 150 : ivas_dirac_ana_fx( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, *outAudio.pq_fact );
8145 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
8146 :
8147 150 : pop_wmops();
8148 150 : return;
8149 : }
8150 :
8151 :
8152 251755 : static ivas_error renderInputSba(
8153 : input_sba *sbaInput,
8154 : const AUDIO_CONFIG outConfig,
8155 : IVAS_REND_AudioBuffer outAudio )
8156 : {
8157 : ivas_error error;
8158 : IVAS_REND_AudioBuffer inAudio;
8159 : Word16 cldfb2tdShift;
8160 251755 : error = IVAS_ERR_OK;
8161 251755 : move32();
8162 251755 : inAudio = sbaInput->base.inputBuffer;
8163 :
8164 251755 : cldfb2tdShift = outAudio.config.is_cldfb ? 1 : 0;
8165 251755 : IF( NE_32( L_shl( sbaInput->base.numNewSamplesPerChannel, cldfb2tdShift ), outAudio.config.numSamplesPerChannel ) &&
8166 : NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8167 : {
8168 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" );
8169 : }
8170 251755 : sbaInput->base.numNewSamplesPerChannel = 0;
8171 251755 : move32();
8172 251755 : *outAudio.pq_fact = outAudio.q_factor;
8173 251755 : move16();
8174 : /* Apply input gain to new audio */
8175 251755 : v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
8176 251755 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
8177 251755 : move16();
8178 :
8179 : /* set combined orientation subframe info to start info */
8180 251755 : ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
8181 :
8182 251755 : SWITCH( getAudioConfigType( outConfig ) )
8183 : {
8184 115801 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
8185 115801 : renderSbaToMc( sbaInput, outAudio );
8186 115801 : BREAK;
8187 45768 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
8188 45768 : renderSbaToSba( sbaInput, outAudio );
8189 45768 : BREAK;
8190 90036 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
8191 : SWITCH( outConfig )
8192 : {
8193 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
8194 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
8195 0 : error = renderSbaToSplitBinaural( sbaInput, outConfig, outAudio );
8196 0 : break;
8197 : #ifdef FIX_1129_EXT_REND_OUTPUT_HIGH
8198 60024 : case IVAS_AUDIO_CONFIG_BINAURAL:
8199 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
8200 60024 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
8201 60024 : break;
8202 30012 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
8203 : #else
8204 : case IVAS_AUDIO_CONFIG_BINAURAL:
8205 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
8206 : BREAK;
8207 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
8208 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
8209 : #endif
8210 30012 : error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
8211 30012 : BREAK;
8212 0 : default:
8213 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
8214 : }
8215 90036 : BREAK;
8216 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
8217 150 : renderSbaToMasa( sbaInput, outAudio );
8218 150 : BREAK;
8219 0 : default:
8220 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
8221 : }
8222 :
8223 251755 : return error;
8224 : }
8225 :
8226 :
8227 1126140 : static ivas_error renderActiveInputsSba(
8228 : IVAS_REND_HANDLE hIvasRend,
8229 : IVAS_REND_AudioBuffer outAudio )
8230 : {
8231 : Word16 i;
8232 : input_sba *pCurrentInput;
8233 : ivas_error error;
8234 :
8235 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsSba ); i < RENDERER_MAX_SBA_INPUTS; ( ++i, ++pCurrentInput ) )
8236 : {
8237 1126140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8238 : {
8239 : /* Skip inactive inputs */
8240 874385 : CONTINUE;
8241 : }
8242 251755 : *outAudio.pq_fact = outAudio.q_factor;
8243 251755 : move16();
8244 251755 : IF( NE_32( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
8245 : {
8246 0 : return error;
8247 : }
8248 : }
8249 :
8250 1126140 : return IVAS_ERR_OK;
8251 : }
8252 :
8253 :
8254 17250 : static void copyMasaMetadataToDiracRenderer_fx(
8255 : MASA_METADATA_FRAME *meta,
8256 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
8257 : const Word16 maxBin )
8258 : {
8259 : Word16 band, sf, bin;
8260 : Word16 meta_write_index;
8261 :
8262 17250 : hSpatParamRendCom->numParametricDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
8263 17250 : hSpatParamRendCom->numSimultaneousDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
8264 17250 : move16();
8265 17250 : move16();
8266 :
8267 86250 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
8268 : {
8269 69000 : meta_write_index = add( hSpatParamRendCom->dirac_bs_md_write_idx, sf ) % hSpatParamRendCom->dirac_md_buffer_length;
8270 :
8271 1725000 : FOR( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
8272 : {
8273 5796000 : FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
8274 : {
8275 4140000 : hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8276 4140000 : move16();
8277 4140000 : hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8278 4140000 : move16();
8279 4140000 : hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band];
8280 4140000 : move32();
8281 4140000 : hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( ONE_IN_Q30, meta->directional_meta[0].energy_ratio_fx[sf][band] );
8282 4140000 : move32();
8283 4140000 : hSpatParamRendCom->spreadCoherence_fx[meta_write_index][bin] = meta->directional_meta[0].spread_coherence_fx[sf][band];
8284 4140000 : move16();
8285 4140000 : hSpatParamRendCom->surroundingCoherence_fx[meta_write_index][bin] = meta->common_meta.surround_coherence_fx[sf][band];
8286 4140000 : move16();
8287 :
8288 4140000 : IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) )
8289 : {
8290 2160000 : hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8291 2160000 : move16();
8292 2160000 : hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8293 2160000 : move16();
8294 2160000 : hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band];
8295 2160000 : move32();
8296 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] );
8297 2160000 : move32();
8298 2160000 : hSpatParamRendCom->spreadCoherence2_fx[meta_write_index][bin] = meta->directional_meta[1].spread_coherence_fx[sf][band];
8299 2160000 : move16();
8300 : }
8301 : }
8302 : }
8303 : }
8304 :
8305 17250 : hSpatParamRendCom->dirac_bs_md_write_idx = add( hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
8306 17250 : move16();
8307 :
8308 17250 : return;
8309 : }
8310 :
8311 :
8312 150 : static void renderMasaToMasa(
8313 : input_masa *masaInput,
8314 : IVAS_REND_AudioBuffer outAudio )
8315 : {
8316 : Word16 sf, band, dir, numDirs;
8317 : Word32 ratioSum_fx; /* Q30 */
8318 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
8319 : MASA_METADATA_FRAME *inMeta;
8320 : Word32 tmpBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8321 : Word16 ts, i, j, l_ts;
8322 : Word32 Chan_RealBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
8323 : Word32 Chan_ImagBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
8324 : Word16 band_m_idx, block_m_idx;
8325 : Word16 mrange[2];
8326 : Word16 brange[2];
8327 : Word16 numAnalysisChannels;
8328 150 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_fx );
8329 150 : Word16 q_cldfb = *outAudio.pq_fact;
8330 150 : Word16 q_cldfb_out = *outAudio.pq_fact;
8331 150 : Word16 scale_factor = 31;
8332 : Word16 scale_fac_arr[MASA_MAX_TRANSPORT_CHANNELS];
8333 150 : move16();
8334 150 : move16();
8335 150 : move16();
8336 : /* Calculate energy */
8337 : // l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
8338 150 : l_ts = shr( masaInput->base.inputBuffer.config.numSamplesPerChannel, 4 );
8339 150 : numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
8340 150 : move16();
8341 : /* do processing over all CLDFB time slots */
8342 750 : FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
8343 : {
8344 600 : mrange[0] = DirAC_block_grouping[block_m_idx];
8345 600 : mrange[1] = DirAC_block_grouping[block_m_idx + 1];
8346 600 : move16();
8347 600 : move16();
8348 :
8349 600 : set_zero_fx( masaInput->hMasaPrerend->energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
8350 600 : set16_fx( masaInput->hMasaPrerend->energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
8351 :
8352 3000 : FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
8353 : {
8354 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
8355 : {
8356 4800 : scale_factor = 31;
8357 4800 : move16();
8358 4800 : masaInput->hMasaPrerend->cldfbAnaEnc[i]->Q_cldfb_state = q_cldfb;
8359 4800 : q_cldfb_out = q_cldfb;
8360 4800 : move16();
8361 4800 : move16();
8362 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 );
8363 4800 : scale_factor = s_min( scale_factor, s_min( getScaleFactor32( Chan_RealBuffer_fx[i], l_ts ), getScaleFactor32( Chan_ImagBuffer_fx[i], l_ts ) ) );
8364 4800 : scale_factor = sub( scale_factor, 1 );
8365 4800 : scale_sig32( Chan_RealBuffer_fx[i], l_ts, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
8366 4800 : scale_sig32( Chan_ImagBuffer_fx[i], l_ts, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
8367 4800 : scale_fac_arr[i] = scale_factor;
8368 4800 : move16();
8369 : }
8370 :
8371 2400 : scale_factor = MAX_16;
8372 2400 : move16();
8373 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
8374 : {
8375 4800 : scale_factor = s_min( scale_factor, scale_fac_arr[i] );
8376 : }
8377 :
8378 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
8379 : {
8380 4800 : IF( NE_16( scale_factor, scale_fac_arr[i] ) )
8381 : {
8382 48861 : FOR( j = 0; j < l_ts; j++ )
8383 : {
8384 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) */
8385 48060 : move32();
8386 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) */
8387 48060 : move32();
8388 : }
8389 : }
8390 : }
8391 :
8392 2400 : Word16 q_add = sub( 31, add( scale_factor, q_cldfb_out ) );
8393 : /* Compute channel energy for metadata processing */
8394 60000 : FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
8395 : {
8396 57600 : brange[0] = MASA_band_grouping_24[band_m_idx];
8397 57600 : move16();
8398 57600 : brange[1] = MASA_band_grouping_24[band_m_idx + 1];
8399 57600 : move16();
8400 201600 : FOR( j = brange[0]; j < brange[1]; j++ )
8401 : {
8402 432000 : FOR( i = 0; i < numAnalysisChannels; i++ )
8403 : {
8404 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 */
8405 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] );
8406 288000 : move32();
8407 : }
8408 : }
8409 : }
8410 : }
8411 : }
8412 :
8413 : /* Copy audio channels if mismatch in number of transports */
8414 150 : test();
8415 150 : test();
8416 150 : IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 1 ) && EQ_16( outAudio.config.numChannels, 2 ) )
8417 : {
8418 0 : Copy32( tmpBuffer_fx[0], tmpBuffer_fx[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
8419 : }
8420 150 : ELSE IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 2 ) && EQ_16( outAudio.config.numChannels, 1 ) )
8421 : {
8422 : // v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
8423 0 : v_add_fixed_no_hdrm( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
8424 : }
8425 :
8426 : /* Copy metadata */
8427 150 : outMeta = masaInput->hMasaPrerend->hMasaOut;
8428 150 : inMeta = &masaInput->masaMetadata;
8429 150 : numDirs = add( inMeta->descriptive_meta.numberOfDirections, 1 );
8430 :
8431 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
8432 : {
8433 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
8434 : {
8435 : /* Remainder is always set to zero and energy removal is compensated in following steps
8436 : * to other ratios. */
8437 : // inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
8438 14400 : inMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0;
8439 14400 : move32();
8440 14400 : ratioSum_fx = 0;
8441 14400 : move32();
8442 43200 : FOR( dir = 0; dir < numDirs; dir++ )
8443 : {
8444 28800 : ratioSum_fx = L_add( ratioSum_fx, inMeta->directional_meta[dir].energy_ratio_fx[sf][band] );
8445 : }
8446 14400 : ratioSum_fx = L_add( ratioSum_fx, inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
8447 :
8448 14400 : IF( ratioSum_fx == 0 )
8449 : {
8450 0 : FOR( dir = 0; dir < numDirs; dir++ )
8451 : {
8452 0 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0;
8453 0 : move32();
8454 : }
8455 0 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30;
8456 0 : move32();
8457 : }
8458 14400 : ELSE IF( NE_32( ratioSum_fx, ONE_IN_Q30 ) )
8459 : {
8460 14400 : Word16 tmp_e = 0;
8461 14400 : move16();
8462 14400 : Word32 tmp = 0;
8463 14400 : move32();
8464 43200 : FOR( dir = 0; dir < numDirs; dir++ )
8465 : {
8466 28800 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
8467 28800 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
8468 28800 : move32();
8469 : }
8470 14400 : tmp_e = 0;
8471 14400 : move16();
8472 14400 : tmp = 0;
8473 14400 : move32();
8474 14400 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
8475 14400 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
8476 14400 : move32();
8477 : }
8478 : }
8479 : }
8480 :
8481 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
8482 : {
8483 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
8484 : {
8485 14400 : outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
8486 14400 : move16();
8487 43200 : FOR( dir = 0; dir < numDirs; dir++ )
8488 : {
8489 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 );
8490 28800 : outMeta->directToTotalRatio[dir][sf][band] = (UWord8) L_shr( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], Q22 );
8491 28800 : outMeta->diffuseToTotalRatio[sf][band] = (UWord8) sub( outMeta->diffuseToTotalRatio[sf][band], outMeta->directToTotalRatio[dir][sf][band] );
8492 28800 : outMeta->spreadCoherence[dir][sf][band] = (UWord8) shr( inMeta->directional_meta[dir].spread_coherence_fx[sf][band], Q7 );
8493 :
8494 28800 : move16();
8495 28800 : move16();
8496 28800 : move16();
8497 28800 : move16();
8498 : }
8499 14400 : outMeta->surroundCoherence[sf][band] = (UWord8) shr( inMeta->common_meta.surround_coherence_fx[sf][band], Q7 );
8500 14400 : move16();
8501 : }
8502 : }
8503 :
8504 150 : copy_masa_descriptive_meta_fx( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
8505 :
8506 150 : accumulate2dArrayToBuffer_fx( tmpBuffer_fx, &outAudio );
8507 :
8508 150 : return;
8509 : }
8510 :
8511 18150 : static ivas_error renderInputMasa(
8512 : input_masa *masaInput,
8513 : const AUDIO_CONFIG outConfig,
8514 : IVAS_REND_AudioBuffer outAudio )
8515 : {
8516 : IVAS_REND_AudioBuffer inAudio;
8517 : Word16 ch;
8518 : Word16 maxBin;
8519 : Word32 *tmpBuffer_fx[MAX_OUTPUT_CHANNELS];
8520 : Word32 tmpBuffer_buff_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8521 : Word16 cldfb2tdShift;
8522 : Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8523 : Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8524 :
8525 18150 : IF( !masaInput->metadataHasBeenFed )
8526 : {
8527 0 : return IVAS_ERR_MISSING_METADATA;
8528 : }
8529 :
8530 18150 : inAudio = masaInput->base.inputBuffer;
8531 :
8532 18150 : cldfb2tdShift = outAudio.config.is_cldfb ? 1 : 0;
8533 18150 : IF( ( NE_32( L_shl( masaInput->base.numNewSamplesPerChannel, cldfb2tdShift ), outAudio.config.numSamplesPerChannel ) ) &&
8534 : NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8535 : {
8536 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" );
8537 : }
8538 18150 : masaInput->base.numNewSamplesPerChannel = 0;
8539 18150 : move32();
8540 :
8541 18150 : *outAudio.pq_fact = outAudio.q_factor;
8542 18150 : move16();
8543 : /* Apply input gain to new audio */
8544 18150 : v_multc_fixed( inAudio.data_fx, masaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
8545 18150 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
8546 18150 : move16();
8547 :
8548 18150 : maxBin = extract_l( Mpy_32_32( *masaInput->base.ctx.pOutSampleRate, INV_CLDFB_BANDWIDTH_Q31 ) ); /* Q0 */
8549 :
8550 : /* set combined orientation subframe info to start info */
8551 18150 : ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
8552 :
8553 18150 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8554 : {
8555 : /* MASA prerendering path for MASA -> MASA */
8556 150 : renderMasaToMasa( masaInput, outAudio );
8557 : }
8558 : ELSE
8559 : {
8560 : /* MASA external renderer -> other formats */
8561 : Word16 num_subframes, exp;
8562 306000 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
8563 : {
8564 288000 : tmpBuffer_fx[ch] = tmpBuffer_buff_fx[ch];
8565 : }
8566 18000 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_buff_fx );
8567 :
8568 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 );
8569 18000 : num_subframes = shr( num_subframes, sub( 15, exp ) ); /* Q0 */
8570 :
8571 18000 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) )
8572 0 : {
8573 : /* split rendering. use the combined of the first subframe in all subframes */
8574 : Word16 sf, i, j;
8575 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
8576 0 : pCombinedOrientationData = *masaInput->base.ctx.pCombinedOrientationData;
8577 0 : FOR( sf = 1; sf < pCombinedOrientationData->num_subframes; sf++ )
8578 : {
8579 0 : Copy_Quat_fx( &pCombinedOrientationData->Quaternions[0], &pCombinedOrientationData->Quaternions[sf] );
8580 0 : FOR( i = 0; i < 3; i++ )
8581 : {
8582 0 : FOR( j = 0; j < 3; j++ )
8583 : {
8584 0 : pCombinedOrientationData->Rmat_fx[sf][i][j] = pCombinedOrientationData->Rmat_fx[0][i][j];
8585 0 : move32();
8586 : }
8587 : }
8588 : }
8589 :
8590 0 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
8591 0 : Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8592 0 : Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8593 : // scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
8594 :
8595 0 : ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes, masaInput->base.ctx.pSplitRendWrapper, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
8596 :
8597 0 : accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
8598 :
8599 0 : *outAudio.pq_fact = Q6;
8600 0 : move16();
8601 : }
8602 : ELSE
8603 : {
8604 : /* non-split path */
8605 18000 : SWITCH( masaInput->hMasaExtRend->renderer_type )
8606 : {
8607 12750 : case RENDERER_DIRAC:
8608 :
8609 12750 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
8610 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 1 );
8611 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
8612 : {
8613 110250 : masaInput->hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state = Q11;
8614 110250 : move16();
8615 : }
8616 216750 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
8617 : {
8618 204000 : Scale_sig32( tmpBuffer_buff_fx[ch], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8619 : }
8620 :
8621 12750 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8622 :
8623 12750 : ivas_masa_ext_dirac_render_fx( masaInput->hMasaExtRend, tmpBuffer_fx, num_subframes );
8624 :
8625 12750 : *outAudio.pq_fact = Q11;
8626 12750 : move16();
8627 :
8628 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
8629 : {
8630 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 */
8631 110250 : masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
8632 110250 : move16();
8633 : }
8634 :
8635 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 0 );
8636 12750 : BREAK;
8637 4500 : case RENDERER_STEREO_PARAMETRIC:
8638 : case RENDERER_BINAURAL_PARAMETRIC:
8639 : case RENDERER_BINAURAL_PARAMETRIC_ROOM:
8640 :
8641 4500 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
8642 :
8643 4500 : Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8644 4500 : Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8645 :
8646 4500 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
8647 :
8648 4500 : ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes, NULL, NULL, NULL );
8649 4500 : *outAudio.pq_fact = Q11;
8650 4500 : move16();
8651 4500 : BREAK;
8652 750 : case RENDERER_DISABLE:
8653 750 : BREAK; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
8654 0 : default:
8655 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
8656 : }
8657 18000 : accumulate2dArrayToBuffer_fx( tmpBuffer_buff_fx, &outAudio );
8658 : }
8659 : }
8660 :
8661 18150 : return IVAS_ERR_OK;
8662 : }
8663 :
8664 :
8665 1126140 : static ivas_error renderActiveInputsMasa(
8666 : IVAS_REND_HANDLE hIvasRend,
8667 : IVAS_REND_AudioBuffer outAudio )
8668 : {
8669 : Word16 i;
8670 : input_masa *pCurrentInput;
8671 : ivas_error error;
8672 :
8673 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMasa ); i < RENDERER_MAX_MASA_INPUTS; ( ++i, ++pCurrentInput ) )
8674 : {
8675 1126140 : IF( EQ_16( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8676 : {
8677 : /* Skip inactive inputs */
8678 1107990 : CONTINUE;
8679 : }
8680 :
8681 18150 : *outAudio.pq_fact = outAudio.q_factor;
8682 18150 : move16();
8683 :
8684 18150 : IF( NE_32( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
8685 : {
8686 0 : return error;
8687 : }
8688 : }
8689 :
8690 1126140 : return IVAS_ERR_OK;
8691 : }
8692 :
8693 :
8694 : /*---------------------------------------------------------------------*
8695 : * IVAS_REND_GetMasaMetadata( )
8696 : *
8697 : * Get metadata of the estimated MASA frame
8698 : *---------------------------------------------------------------------*/
8699 :
8700 0 : ivas_error IVAS_REND_GetMasaMetadata(
8701 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8702 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to analyzed MASA metadata */
8703 : const IVAS_REND_AudioConfigType inputType /* i : Input type */
8704 : )
8705 : {
8706 0 : IF( hIvasRend == NULL )
8707 : {
8708 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8709 : }
8710 :
8711 : /* Get the metadata handle */
8712 0 : IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
8713 : {
8714 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
8715 : }
8716 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
8717 : {
8718 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
8719 : }
8720 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
8721 : {
8722 0 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
8723 : }
8724 : ELSE
8725 : {
8726 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
8727 : }
8728 :
8729 0 : return IVAS_ERR_OK;
8730 : }
8731 :
8732 :
8733 : /*---------------------------------------------------------------------*
8734 : * IVAS_REND_MergeMasaMetadata( )
8735 : *
8736 : * Merge MASA metadata from two formats
8737 : *---------------------------------------------------------------------*/
8738 :
8739 450 : ivas_error IVAS_REND_MergeMasaMetadata(
8740 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8741 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to merged metadata */
8742 : const IVAS_REND_AudioConfigType inputType1, /* i : Input type 1 */
8743 : const IVAS_REND_AudioConfigType inputType2 /* i : Input type 2 */
8744 : )
8745 : {
8746 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
8747 : Word32( *inEne1_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8748 : Word32( *inEne2_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8749 : Word16( *inEne1_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8750 : Word16( *inEne2_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8751 :
8752 450 : IF( hIvasRend == NULL )
8753 : {
8754 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8755 : }
8756 :
8757 : /* Input1 metadata and energy */
8758 450 : IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
8759 : {
8760 :
8761 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
8762 0 : inEne1_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
8763 0 : inEne1_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
8764 : }
8765 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
8766 : {
8767 :
8768 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
8769 0 : inEne1_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
8770 0 : inEne1_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
8771 : }
8772 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
8773 : {
8774 :
8775 450 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
8776 450 : inEne1_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
8777 450 : inEne1_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
8778 : }
8779 0 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8780 : {
8781 :
8782 0 : *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
8783 0 : inEne1_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
8784 0 : inEne1_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
8785 : }
8786 : ELSE
8787 : {
8788 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
8789 : }
8790 :
8791 : /* Input2 metadata and energy */
8792 450 : IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
8793 : {
8794 150 : inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
8795 150 : inEne2_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
8796 150 : inEne2_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
8797 : }
8798 300 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
8799 : {
8800 150 : inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
8801 150 : inEne2_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
8802 150 : inEne2_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
8803 : }
8804 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
8805 : {
8806 0 : inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
8807 0 : inEne2_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
8808 0 : inEne2_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
8809 : }
8810 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8811 : {
8812 :
8813 150 : inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
8814 150 : inEne2_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
8815 150 : inEne2_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
8816 : }
8817 : ELSE
8818 : {
8819 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
8820 : }
8821 :
8822 : /* Merge metadata */
8823 450 : ivas_prerend_merge_masa_metadata_fx( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1_fx, *inEne1_e, inMeta2, inputType2, *inEne2_fx, *inEne2_e );
8824 :
8825 :
8826 450 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
8827 : {
8828 0 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 0u;
8829 0 : move16();
8830 : }
8831 : ELSE
8832 : {
8833 450 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 1u;
8834 450 : move16();
8835 : }
8836 :
8837 450 : return IVAS_ERR_OK;
8838 : }
8839 :
8840 :
8841 : /*---------------------------------------------------------------------*
8842 : * IVAS_REND_SetTotalNumberOfObjects( )
8843 : *
8844 : * Set the total number of objects to the first object data
8845 : *---------------------------------------------------------------------*/
8846 :
8847 182 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
8848 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8849 : const UWord16 total_num_objects /* i : total number of objects */
8850 : )
8851 : {
8852 182 : IF( hIvasRend == NULL )
8853 : {
8854 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8855 : }
8856 :
8857 182 : hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
8858 182 : move16();
8859 :
8860 182 : return IVAS_ERR_OK;
8861 : }
8862 :
8863 :
8864 : /*---------------------------------------------------------------------*
8865 : * IVAS_REND_SetIsmMetadataDelay( )
8866 : *
8867 : * Set the Metadata Delay in ms in order to sync with audio delay
8868 : *---------------------------------------------------------------------*/
8869 :
8870 182 : ivas_error IVAS_REND_SetIsmMetadataDelay(
8871 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8872 : const Word32 sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */
8873 : )
8874 : {
8875 : Word16 i;
8876 :
8877 182 : IF( hIvasRend == NULL )
8878 : {
8879 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8880 : }
8881 910 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8882 : {
8883 728 : hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay;
8884 728 : move32();
8885 : }
8886 :
8887 182 : return IVAS_ERR_OK;
8888 : }
8889 :
8890 :
8891 : /*-------------------------------------------------------------------*
8892 : * getSamplesInternal()
8893 : *
8894 : *
8895 : *-------------------------------------------------------------------*/
8896 :
8897 1126140 : static ivas_error getSamplesInternal(
8898 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
8899 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
8900 : IVAS_REND_BitstreamBuffer *hBits /* i/o: buffer for input/output bitstream. Needed in split rendering */
8901 : )
8902 : {
8903 : ivas_error error;
8904 : Word16 numOutChannels;
8905 : Word16 cldfb2tdSampleShift;
8906 : IVAS_REND_AudioBuffer outAudioOrig;
8907 :
8908 : /* Validate function arguments */
8909 1126140 : test();
8910 1126140 : IF( hIvasRend == NULL || outAudio.data_fx == NULL )
8911 : {
8912 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8913 : }
8914 :
8915 1126140 : test();
8916 1126140 : cldfb2tdSampleShift = ( outAudio.config.is_cldfb ) ? 1 : 0;
8917 :
8918 1126140 : IF( outAudio.config.numSamplesPerChannel <= 0 || ( MAX_BUFFER_LENGTH_PER_CHANNEL < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
8919 : ( ( shl( MAX_BUFFER_LENGTH_PER_CHANNEL, cldfb2tdSampleShift ) ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
8920 : {
8921 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
8922 : }
8923 :
8924 1126140 : test();
8925 1126140 : IF( LE_16( outAudio.config.numChannels, 0 ) || LT_16( MAX_OUTPUT_CHANNELS, outAudio.config.numChannels ) )
8926 : {
8927 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
8928 : }
8929 :
8930 1126140 : test();
8931 1126140 : test();
8932 1126140 : test();
8933 1126140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
8934 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) &&
8935 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) &&
8936 : NE_32( L_shr( L_mult0( outAudio.config.numSamplesPerChannel, 1000 ), cldfb2tdSampleShift ),
8937 : imult3216( hIvasRend->sampleRateOut, i_mult( hIvasRend->num_subframes, BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ) )
8938 : {
8939 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
8940 : }
8941 :
8942 : /* Check that there is allowed configuration for MASA format output */
8943 1126140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8944 : {
8945 : Word16 i;
8946 150 : Word16 numMasaInputs = 0;
8947 150 : move16();
8948 150 : Word16 numOtherInputs = 0;
8949 150 : move16();
8950 :
8951 300 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
8952 : {
8953 : // numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8954 :
8955 150 : IF( EQ_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8956 : {
8957 0 : numMasaInputs = add( numMasaInputs, 0 );
8958 : }
8959 : ELSE
8960 : {
8961 150 : numMasaInputs = add( numMasaInputs, 1 );
8962 : }
8963 : }
8964 :
8965 300 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
8966 : {
8967 : // numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8968 :
8969 150 : IF( EQ_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8970 : {
8971 0 : numOtherInputs = add( numOtherInputs, 0 );
8972 : }
8973 : ELSE
8974 : {
8975 150 : numOtherInputs = add( numOtherInputs, 1 );
8976 : }
8977 : }
8978 :
8979 300 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
8980 : {
8981 : // numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8982 :
8983 150 : IF( EQ_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8984 : {
8985 0 : numOtherInputs = add( numOtherInputs, 0 );
8986 : }
8987 : ELSE
8988 : {
8989 150 : numOtherInputs = add( numOtherInputs, 1 );
8990 : }
8991 : }
8992 :
8993 : /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
8994 : // numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8995 150 : IF( EQ_32( hIvasRend->inputsIsm[0].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8996 : {
8997 0 : numOtherInputs = add( numOtherInputs, 0 );
8998 : }
8999 : ELSE
9000 : {
9001 150 : numOtherInputs = add( numOtherInputs, 1 );
9002 : }
9003 :
9004 150 : test();
9005 150 : IF( numMasaInputs == 0 || numOtherInputs == 0 )
9006 : {
9007 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
9008 : }
9009 : }
9010 :
9011 1126140 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
9012 : {
9013 0 : return error;
9014 : }
9015 :
9016 1126140 : IF( NE_16( numOutChannels, outAudio.config.numChannels ) && NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
9017 : {
9018 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
9019 : }
9020 :
9021 : /* Clear original output buffer */
9022 1126140 : set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) );
9023 :
9024 1126140 : outAudioOrig = outAudio;
9025 :
9026 : /* Use internal buffer if outputting split rendering bitstream */
9027 1126140 : test();
9028 1126140 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
9029 : EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
9030 : {
9031 : Word16 num_poses_orig;
9032 0 : num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
9033 0 : move16();
9034 0 : outAudio.config = hIvasRend->splitRendEncBuffer.config;
9035 0 : outAudio.data_fx = hIvasRend->splitRendEncBuffer.data_fx;
9036 :
9037 0 : ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis );
9038 :
9039 0 : assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" );
9040 :
9041 : /* Clear output buffer for split rendering bitstream */
9042 0 : set32_fx( outAudio.data_fx, 0, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
9043 : }
9044 :
9045 1126140 : IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
9046 : {
9047 0 : return error;
9048 : }
9049 1126140 : IF( NE_32( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
9050 : {
9051 0 : return error;
9052 : }
9053 1126140 : IF( NE_32( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
9054 : {
9055 0 : return error;
9056 : }
9057 1126140 : IF( NE_32( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
9058 : {
9059 0 : return error;
9060 : }
9061 :
9062 1126140 : test();
9063 1126140 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
9064 : {
9065 : ISAR_SPLIT_REND_BITS_DATA bits;
9066 : Word16 cldfb_in_flag, i, j, k, ch, ro_md_flag;
9067 : Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
9068 : Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
9069 :
9070 0 : FOR( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; i++ )
9071 : {
9072 0 : FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ )
9073 : {
9074 0 : FOR( k = 0; k < CLDFB_NO_CHANNELS_MAX; k++ )
9075 : {
9076 0 : Cldfb_RealBuffer_Binaural[i][j][k] = 0;
9077 0 : Cldfb_ImagBuffer_Binaural[i][j][k] = 0;
9078 0 : move32();
9079 0 : move32();
9080 : }
9081 : }
9082 : }
9083 :
9084 : Word32 *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
9085 :
9086 0 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
9087 : {
9088 0 : tmpBinaural[ch] = tmpBinaural_buff[ch];
9089 0 : move32();
9090 : }
9091 :
9092 0 : IF( EQ_16( outAudio.config.is_cldfb, 1 ) )
9093 : {
9094 0 : cldfb_in_flag = 1;
9095 0 : move16();
9096 0 : copyBufferToCLDFBarray_fx( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
9097 : }
9098 : ELSE
9099 : {
9100 0 : cldfb_in_flag = 0;
9101 0 : move16();
9102 0 : copyBufferTo2dArray_fx( outAudio, tmpBinaural_buff );
9103 : }
9104 :
9105 : /* Encode split rendering bitstream */
9106 0 : convertBitsBufferToInternalBitsBuff( *hBits, &bits );
9107 :
9108 0 : ro_md_flag = 0;
9109 0 : move16();
9110 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
9111 : {
9112 0 : IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
9113 : {
9114 0 : ro_md_flag = 1;
9115 0 : move16();
9116 0 : break;
9117 : }
9118 : }
9119 :
9120 0 : Word16 q1 = 31, q2 = 31, Q_buff;
9121 : Word16 Q_out[CLDFB_NO_COL_MAX];
9122 0 : Q_out[0] = 31;
9123 0 : Word16 num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
9124 :
9125 0 : for ( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ )
9126 : {
9127 0 : for ( j = 0; j < CLDFB_NO_COL_MAX; j++ )
9128 : {
9129 0 : q1 = s_min( q1, L_norm_arr( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) );
9130 0 : q2 = s_min( q2, L_norm_arr( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) );
9131 : }
9132 : }
9133 0 : Q_buff = s_min( q1, q2 );
9134 0 : for ( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ )
9135 : {
9136 0 : for ( j = 0; j < CLDFB_NO_COL_MAX; j++ )
9137 : {
9138 0 : scale_sig32( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff );
9139 0 : scale_sig32( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff );
9140 : }
9141 : }
9142 0 : Q_buff = Q_buff + *outAudio.pq_fact;
9143 :
9144 0 : IF( EQ_16( cldfb_in_flag, 0 ) )
9145 : {
9146 : /*TD input*/
9147 0 : num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
9148 :
9149 0 : FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
9150 : {
9151 0 : Q_out[0] = s_min( Q_out[0], L_norm_arr( tmpBinaural_buff[i], L_FRAME48k ) );
9152 : }
9153 :
9154 0 : FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
9155 : {
9156 0 : scale_sig32( tmpBinaural_buff[i], L_FRAME48k, Q_out[0] );
9157 : }
9158 :
9159 0 : Q_out[0] = Q_out[0] + *outAudio.pq_fact;
9160 : }
9161 :
9162 0 : if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, hIvasRend->headRotData.headPositions[0], hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, hIvasRend->hRendererConfig->split_rend_config.codec,
9163 0 : hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms,
9164 0 : hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms,
9165 0 : &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, ( const Word16 )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), tmpBinaural, 1, cldfb_in_flag, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, ro_md_flag, Q_buff, &Q_out[0] ) ) != IVAS_ERR_OK )
9166 : {
9167 0 : return error;
9168 : }
9169 :
9170 0 : Word16 pcm_out_flag = ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0;
9171 0 : IF( NE_16( pcm_out_flag, 0 ) )
9172 : {
9173 0 : FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
9174 : {
9175 0 : scale_sig32( tmpBinaural_buff[j], L_FRAME48k, sub( *outAudio.pq_fact, Q_out[j] ) ); // *outAudio.pq_fact
9176 : }
9177 : }
9178 :
9179 0 : convertInternalBitsBuffToBitsBuffer( hBits, bits );
9180 :
9181 : /* reset to outAudioOrig in case of PCM output */
9182 0 : outAudio.config = outAudioOrig.config;
9183 0 : outAudio.data_fx = outAudioOrig.data_fx;
9184 :
9185 0 : IF( NE_16( pcm_out_flag, 0 ) )
9186 : {
9187 0 : accumulate2dArrayToBuffer_fx( tmpBinaural_buff, &outAudio );
9188 : }
9189 : }
9190 :
9191 1126140 : if ( outAudio.config.is_cldfb == 0 )
9192 : {
9193 1126140 : Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact );
9194 : #ifndef DISABLE_LIMITER
9195 1126140 : limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact );
9196 : #endif
9197 : }
9198 :
9199 : /* update global cominbed orientation start index */
9200 1126140 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
9201 :
9202 1126140 : return IVAS_ERR_OK;
9203 : }
9204 :
9205 :
9206 : /*-------------------------------------------------------------------*
9207 : * IVAS_REND_GetSamples()
9208 : *
9209 : *
9210 : *-------------------------------------------------------------------*/
9211 :
9212 1126140 : ivas_error IVAS_REND_GetSamples(
9213 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
9214 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
9215 : )
9216 : {
9217 1126140 : return getSamplesInternal( hIvasRend, outAudio, NULL );
9218 : }
9219 :
9220 :
9221 : /*-------------------------------------------------------------------*
9222 : * IVAS_REND_GetSplitBinauralBitstream()
9223 : *
9224 : *
9225 : *-------------------------------------------------------------------*/
9226 :
9227 0 : ivas_error IVAS_REND_GetSplitBinauralBitstream(
9228 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
9229 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
9230 : IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */
9231 : )
9232 : {
9233 : Word16 cldfb_in_flag;
9234 :
9235 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
9236 0 : hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag;
9237 :
9238 0 : if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
9239 : {
9240 0 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
9241 : }
9242 : else
9243 : {
9244 0 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (Word16) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
9245 : }
9246 :
9247 0 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
9248 :
9249 : /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output
9250 : outAudio used for BINAURAL_SPLIT_PCM output */
9251 0 : return getSamplesInternal( hIvasRend, outAudio, hBits );
9252 : }
9253 :
9254 :
9255 : /*-------------------------------------------------------------------*
9256 : * IVAS_REND_GetSplitRendBitstreamHeader()
9257 : *
9258 : *
9259 : *-------------------------------------------------------------------*/
9260 :
9261 0 : ivas_error IVAS_REND_GetSplitRendBitstreamHeader(
9262 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9263 : ISAR_SPLIT_REND_CODEC *pCodec, /* o : pointer to codec setting */
9264 : ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o : pointer to pose correction mode */
9265 : Word16 *pCodec_frame_size_ms, /* o : pointer to codec frame size setting */
9266 : Word16 *pIsar_frame_size_ms /* o : pointer to ISAR frame size setting */
9267 : )
9268 : {
9269 0 : test();
9270 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
9271 : {
9272 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
9273 : }
9274 :
9275 0 : *pCodec = hIvasRend->hRendererConfig->split_rend_config.codec;
9276 0 : *pCodec_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms;
9277 0 : *pIsar_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms;
9278 0 : *poseCorrection = hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode;
9279 :
9280 0 : return IVAS_ERR_OK;
9281 : }
9282 :
9283 :
9284 : /*-------------------------------------------------------------------*
9285 : * IVAS_REND_Close()
9286 : *
9287 : *
9288 : *-------------------------------------------------------------------*/
9289 :
9290 666 : void IVAS_REND_Close(
9291 : IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
9292 : )
9293 : {
9294 : UWord16 i;
9295 : IVAS_REND_HANDLE hIvasRend;
9296 :
9297 : /* Validate function arguments */
9298 666 : test();
9299 666 : IF( phIvasRend == NULL || *phIvasRend == NULL )
9300 : {
9301 0 : return;
9302 : }
9303 666 : hIvasRend = *phIvasRend;
9304 :
9305 666 : IF( hIvasRend->efapOutWrapper.hEfap != NULL )
9306 : {
9307 471 : efap_free_data_fx( &hIvasRend->efapOutWrapper.hEfap );
9308 : }
9309 :
9310 : /* clear inputs */
9311 3330 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
9312 : {
9313 2664 : clearInputIsm( &hIvasRend->inputsIsm[i] );
9314 : }
9315 1332 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
9316 : {
9317 666 : clearInputMc( &hIvasRend->inputsMc[i] );
9318 : }
9319 1332 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
9320 : {
9321 666 : clearInputSba( &hIvasRend->inputsSba[i] );
9322 : #ifdef FIX_CREND_SIMPLIFY_CODE
9323 666 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
9324 : #endif
9325 : }
9326 1332 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
9327 : {
9328 666 : clearInputMasa( &hIvasRend->inputsMasa[i] );
9329 : }
9330 :
9331 : /* clear Config. Renderer */
9332 666 : ivas_render_config_close_fx( &( hIvasRend->hRendererConfig ) );
9333 :
9334 666 : ivas_limiter_close_fx( &hIvasRend->hLimiter );
9335 :
9336 : /* Split binaural rendering */
9337 666 : IF( hIvasRend->splitRendWrapper != NULL )
9338 : {
9339 0 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
9340 0 : free( hIvasRend->splitRendWrapper );
9341 0 : hIvasRend->splitRendWrapper = NULL;
9342 : }
9343 :
9344 666 : closeHeadRotation( hIvasRend );
9345 :
9346 666 : ivas_external_orientation_close_fx( &hIvasRend->hExternalOrientationData );
9347 666 : ivas_combined_orientation_close_fx( &hIvasRend->hCombinedOrientationData );
9348 :
9349 : /* Fastconv HRTF memories */
9350 666 : ivas_binaural_hrtf_close_fx( &hIvasRend->hHrtfs.hHrtfFastConv );
9351 :
9352 : /* Parametric binauralizer HRTF filters */
9353 666 : ivas_HRTF_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfTD ) );
9354 : #ifdef FIX_CREND_SIMPLIFY_CODE
9355 666 : ivas_HRTF_CRend_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfCrend ) );
9356 : #else
9357 : ivas_HRTF_CRend_binary_close_fx( &( hIvasRend->hHrtfs.hSetOfHRTF ) );
9358 : #endif
9359 666 : ivas_HRTF_fastconv_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfFastConv ) );
9360 666 : ivas_HRTF_parambin_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfParambin ) );
9361 666 : ivas_HRTF_statistics_close_fx( &( hIvasRend->hHrtfs.hHrtfStatistics ) );
9362 :
9363 666 : free( hIvasRend );
9364 666 : *phIvasRend = NULL;
9365 :
9366 666 : return;
9367 : }
9368 :
9369 : /*-------------------------------------------------------------------*
9370 : * IVAS_REND_openCldfb()
9371 : *
9372 : *
9373 : *-------------------------------------------------------------------*/
9374 :
9375 0 : ivas_error IVAS_REND_openCldfb(
9376 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
9377 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS],
9378 : const Word16 num_in_chs,
9379 : const Word16 num_out_chs,
9380 : const Word32 output_Fs )
9381 : {
9382 : Word16 n;
9383 : ivas_error error;
9384 :
9385 0 : FOR( n = 0; n < num_in_chs; n++ )
9386 : {
9387 0 : IF( ( error = openCldfb_ivas_fx( &( cldfbAna[n] ), CLDFB_ANALYSIS, output_Fs, CLDFB_PROTOTYPE_5_00MS, DEC ) ) != IVAS_ERR_OK )
9388 : {
9389 0 : return error;
9390 : }
9391 : }
9392 0 : FOR( ; n < IVAS_MAX_INPUT_CHANNELS; n++ )
9393 : {
9394 0 : cldfbAna[n] = NULL;
9395 : }
9396 :
9397 0 : FOR( n = 0; n < num_out_chs; n++ )
9398 : {
9399 0 : IF( ( error = openCldfb_ivas_fx( &( cldfbSyn[n] ), CLDFB_SYNTHESIS, output_Fs, CLDFB_PROTOTYPE_5_00MS, DEC ) ) != IVAS_ERR_OK )
9400 : {
9401 0 : return error;
9402 : }
9403 : }
9404 0 : FOR( ; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
9405 : {
9406 0 : cldfbSyn[n] = NULL;
9407 : }
9408 :
9409 0 : return IVAS_ERR_OK;
9410 : }
9411 :
9412 :
9413 : /*-------------------------------------------------------------------*
9414 : * IVAS_REND_closeCldfb()
9415 : *
9416 : *
9417 : *-------------------------------------------------------------------*/
9418 :
9419 0 : void IVAS_REND_closeCldfb(
9420 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
9421 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS] )
9422 : {
9423 : Word16 n;
9424 :
9425 0 : FOR( n = 0; n < IVAS_MAX_INPUT_CHANNELS; n++ )
9426 : {
9427 0 : IF( cldfbAna[n] != NULL )
9428 : {
9429 0 : deleteCldfb_ivas_fx( &( cldfbAna[n] ) );
9430 0 : cldfbAna[n] = NULL;
9431 : }
9432 : }
9433 :
9434 0 : FOR( n = 0; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
9435 : {
9436 0 : IF( cldfbSyn[n] != NULL )
9437 : {
9438 0 : deleteCldfb_ivas_fx( &( cldfbSyn[n] ) );
9439 0 : cldfbSyn[n] = NULL;
9440 : }
9441 : }
9442 :
9443 0 : return;
9444 : }
9445 :
9446 :
9447 : /*-------------------------------------------------------------------*
9448 : * IVAS_REND_cldfbSynthesis_wrapper()
9449 : *
9450 : *
9451 : *-------------------------------------------------------------------*/
9452 :
9453 0 : void IVAS_REND_cldfbAnalysis_ts_wrapper(
9454 : const Word32 *timeIn, /* i : time buffer */
9455 : Word32 realBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : real value buffer */
9456 : Word32 imagBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : imag value buffer */
9457 : const Word16 samplesToProcess, /* i : samples to process */
9458 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb, /* i : filterbank state */
9459 : Word16 Q_in,
9460 : Word16 *Q_out )
9461 : {
9462 :
9463 0 : Word16 Q_cldfb = Q_in;
9464 0 : assert( Q_in == h_cldfb->Q_cldfb_state );
9465 0 : cldfbAnalysis_ts_fx_fixed_q( timeIn, realBuffer, imagBuffer, samplesToProcess, h_cldfb, &Q_cldfb );
9466 :
9467 0 : *Q_out = sub( Q_in, 5 );
9468 :
9469 0 : return;
9470 : }
9471 :
9472 :
9473 : /*-------------------------------------------------------------------*
9474 : * IVAS_REND_cldfbSynthesis_wrapper()
9475 : *
9476 : *
9477 : *-------------------------------------------------------------------*/
9478 :
9479 0 : void IVAS_REND_cldfbSynthesis_wrapper(
9480 : Word32 **realBuffer, /* i : real values */
9481 : Word32 **imagBuffer, /* i : imag values */
9482 : Word32 *timeOut, /* o : output time domain samples */
9483 : const Word16 samplesToProcess, /* i : number of processed samples */
9484 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb, /* i : filter bank state */
9485 : Word16 Q_cldfb,
9486 : Word16 *Q_out )
9487 : {
9488 :
9489 0 : Scale_sig32( h_cldfb->cldfb_state_fx, h_cldfb->p_filter_length, sub( sub( Q_cldfb, 1 ), h_cldfb->Q_cldfb_state ) );
9490 0 : cldfbSynthesis_ivas_fx( realBuffer, imagBuffer, timeOut, samplesToProcess, 0, 0, h_cldfb ); // Q_cldfb - 1
9491 0 : *Q_out = sub( Q_cldfb, 1 );
9492 0 : move16();
9493 0 : h_cldfb->Q_cldfb_state = *Q_out;
9494 0 : move16();
9495 :
9496 0 : return;
9497 : }
9498 :
9499 :
9500 : /*---------------------------------------------------------------------*
9501 : * IVAS_REND_GetHrtfTdHandle( )
9502 : *
9503 : *
9504 : *---------------------------------------------------------------------*/
9505 :
9506 0 : ivas_error IVAS_REND_GetHrtfTdHandle(
9507 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9508 : IVAS_DEC_HRTF_TD_HANDLE **hHrtfTD /* o : TD rend. HRTF handle */
9509 : )
9510 : {
9511 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfTD == NULL )
9512 : {
9513 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
9514 : }
9515 :
9516 0 : *hHrtfTD = &hIvasRend->hHrtfs.hHrtfTD;
9517 :
9518 0 : return IVAS_ERR_OK;
9519 : }
9520 :
9521 :
9522 : /*---------------------------------------------------------------------*
9523 : * IVAS_REND_GetHrtfCRendHandle( )
9524 : *
9525 : *
9526 : *---------------------------------------------------------------------*/
9527 :
9528 0 : ivas_error IVAS_REND_GetHrtfCRendHandle(
9529 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9530 : IVAS_DEC_HRTF_CREND_HANDLE **hHrtfCrend /* o : Crend HRTF handle */
9531 : )
9532 : {
9533 : #ifdef FIX_CREND_SIMPLIFY_CODE
9534 0 : test();
9535 0 : IF( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfCrend == NULL )
9536 : #else
9537 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hSetOfHRTF == NULL )
9538 : #endif
9539 : {
9540 0 : return IVAS_ERR_WRONG_PARAMS;
9541 : }
9542 :
9543 : #ifdef FIX_CREND_SIMPLIFY_CODE
9544 0 : *hHrtfCrend = &hIvasRend->hHrtfs.hHrtfCrend;
9545 : #else
9546 : *hHrtfCrend = &hIvasRend->hHrtfs.hSetOfHRTF;
9547 : #endif
9548 :
9549 0 : return IVAS_ERR_OK;
9550 : }
9551 :
9552 :
9553 : /*---------------------------------------------------------------------*
9554 : * IVAS_REND_GetHrtfFastConvHandle( )
9555 : *
9556 : *
9557 : *---------------------------------------------------------------------*/
9558 :
9559 0 : ivas_error IVAS_REND_GetHrtfFastConvHandle(
9560 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9561 : IVAS_DEC_HRTF_FASTCONV_HANDLE **hHrtfFastConv /* o : FASTCONV HRTF handle */
9562 : )
9563 : {
9564 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfFastConv == NULL )
9565 : {
9566 0 : return IVAS_ERR_WRONG_PARAMS;
9567 : }
9568 :
9569 0 : *hHrtfFastConv = &hIvasRend->hHrtfs.hHrtfFastConv;
9570 :
9571 0 : return IVAS_ERR_OK;
9572 : }
9573 :
9574 :
9575 : /*---------------------------------------------------------------------*
9576 : * IVAS_REND_GetHrtfParamBinHandle( )
9577 : *
9578 : *
9579 : *---------------------------------------------------------------------*/
9580 :
9581 0 : ivas_error IVAS_REND_GetHrtfParamBinHandle(
9582 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9583 : IVAS_DEC_HRTF_PARAMBIN_HANDLE **hHrtfParambin /* o : Parametric binauralizer HRTF handle */
9584 : )
9585 : {
9586 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfParambin == NULL )
9587 : {
9588 0 : return IVAS_ERR_WRONG_PARAMS;
9589 : }
9590 :
9591 0 : *hHrtfParambin = &hIvasRend->hHrtfs.hHrtfParambin;
9592 :
9593 0 : return IVAS_ERR_OK;
9594 : }
9595 :
9596 :
9597 : /*---------------------------------------------------------------------*
9598 : * IVAS_REND_GetHrtfStatisticsHandle( )
9599 : *
9600 : *
9601 : *---------------------------------------------------------------------*/
9602 :
9603 0 : ivas_error IVAS_REND_GetHrtfStatisticsHandle(
9604 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9605 : IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */
9606 : )
9607 : {
9608 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfStatistics == NULL )
9609 : {
9610 0 : return IVAS_ERR_WRONG_PARAMS;
9611 : }
9612 :
9613 0 : *hHrtfStatistics = &hIvasRend->hHrtfs.hHrtfStatistics;
9614 :
9615 0 : return IVAS_ERR_OK;
9616 : }
9617 :
9618 34 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
9619 : input_masa *inputMasa )
9620 : {
9621 : Word16 nchan_out_woLFE;
9622 : Word16 nchan_transport;
9623 : UWord16 i, j, k;
9624 : Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
9625 : Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
9626 : Word32 output_Fs;
9627 : ivas_error error;
9628 : DIRAC_REND_HANDLE hDirACRend;
9629 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
9630 :
9631 34 : error = IVAS_ERR_OK;
9632 34 : move32();
9633 :
9634 34 : hDirACRend = NULL;
9635 34 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
9636 34 : move32();
9637 :
9638 34 : hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
9639 :
9640 : /*-----------------------------------------------------------------*
9641 : * prepare library opening
9642 : *-----------------------------------------------------------------*/
9643 :
9644 34 : IF( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
9645 : {
9646 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
9647 : }
9648 :
9649 34 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
9650 : {
9651 18 : nchan_transport = 2;
9652 18 : move16();
9653 : }
9654 : ELSE
9655 : {
9656 16 : nchan_transport = 1;
9657 16 : move16();
9658 : }
9659 :
9660 : /*-----------------------------------------------------------------*
9661 : * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
9662 : *-----------------------------------------------------------------*/
9663 :
9664 34 : ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
9665 :
9666 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
9667 : {
9668 : /* Copy from ivas_ls_custom_setup */
9669 0 : hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
9670 0 : move16();
9671 0 : hDirACRend->hOutSetup.ls_azimuth_fx = inputMasa->base.ctx.pCustomLsOut->ls_azimuth_fx;
9672 0 : hDirACRend->hOutSetup.ls_elevation_fx = inputMasa->base.ctx.pCustomLsOut->ls_elevation_fx;
9673 :
9674 0 : hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
9675 0 : move16();
9676 0 : hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
9677 0 : move16();
9678 :
9679 0 : hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
9680 0 : move16();
9681 0 : hDirACRend->hOutSetup.is_planar_setup = (Word8) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
9682 0 : move16();
9683 : }
9684 :
9685 34 : nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
9686 34 : move16();
9687 :
9688 34 : test();
9689 34 : IF( hDirACRend->hOutSetup.ls_azimuth_fx != NULL && hDirACRend->hOutSetup.ls_elevation_fx != NULL )
9690 : {
9691 20 : Copy32( hDirACRend->hOutSetup.ls_azimuth_fx, ls_azimuth_fx, nchan_out_woLFE );
9692 20 : Copy32( hDirACRend->hOutSetup.ls_elevation_fx, ls_elevation_fx, nchan_out_woLFE );
9693 : }
9694 :
9695 34 : IF( EQ_16( hDirACRend->hOutSetup.ambisonics_order, -1 ) )
9696 : {
9697 22 : hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
9698 22 : move16();
9699 22 : test();
9700 22 : if ( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_STEREO ) )
9701 : {
9702 2 : hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
9703 2 : move16();
9704 : }
9705 : }
9706 12 : ELSE IF( GE_16( hDirACRend->hOutSetup.ambisonics_order, SBA_FOA_ORDER ) )
9707 : {
9708 12 : Copy32( ls_azimuth_4d4_fx, ls_azimuth_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
9709 12 : Copy32( ls_elevation_4d4_fx, ls_elevation_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
9710 : }
9711 :
9712 : /*-----------------------------------------------------------------*
9713 : * set input parameters
9714 : *-----------------------------------------------------------------*/
9715 :
9716 34 : test();
9717 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
9718 : {
9719 2 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
9720 2 : move32();
9721 2 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
9722 2 : move32();
9723 2 : nchan_out_woLFE = 1;
9724 2 : move16();
9725 : }
9726 32 : ELSE IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
9727 : {
9728 20 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
9729 20 : hDirACRend->panningConf = DIRAC_PANNING_VBAP;
9730 20 : move32();
9731 20 : move32();
9732 : }
9733 12 : ELSE IF( !hDirACRend->hOutSetup.is_loudspeaker_setup && GT_16( nchan_transport, 1 ) )
9734 : {
9735 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
9736 6 : move32();
9737 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
9738 6 : move32();
9739 : }
9740 : ELSE
9741 : {
9742 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
9743 6 : move32();
9744 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
9745 6 : move32();
9746 : }
9747 :
9748 34 : IF( ( hDirACRend->frequency_axis_fx = (Word16 *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( Word16 ) ) ) == NULL )
9749 : {
9750 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9751 : }
9752 34 : set16_fx( hDirACRend->frequency_axis_fx, 0, hSpatParamRendCom->num_freq_bands );
9753 34 : ivas_dirac_dec_get_frequency_axis_fx( hDirACRend->frequency_axis_fx, output_Fs, hSpatParamRendCom->num_freq_bands );
9754 :
9755 34 : test();
9756 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) && EQ_16( nchan_transport, 2 ) )
9757 : {
9758 8 : IF( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
9759 : {
9760 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9761 : }
9762 8 : ivas_masa_init_stereotype_detection_fx( hDirACRend->masa_stereo_type_detect );
9763 : }
9764 : ELSE
9765 : {
9766 26 : hDirACRend->masa_stereo_type_detect = NULL;
9767 : }
9768 :
9769 34 : hSpatParamRendCom->numIsmDirections = 0;
9770 34 : move16();
9771 :
9772 : /*-----------------------------------------------------------------*
9773 : * (re)configure sub-modules
9774 : *-----------------------------------------------------------------*/
9775 :
9776 : /* prototype signal computation */
9777 : /* allocate output setup related arrays */
9778 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
9779 : {
9780 : /* Directional and diffuses components in output LS format */
9781 20 : hDirACRend->num_outputs_diff = nchan_out_woLFE;
9782 20 : move16();
9783 20 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
9784 20 : move16();
9785 : }
9786 14 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9787 : {
9788 : /* Directional and diffuses components in SHD */
9789 : /* Diffuseness components up to 1st order */
9790 6 : hDirACRend->num_outputs_diff = imult1616( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ), ( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ) ) );
9791 6 : hDirACRend->num_outputs_dir = ivas_sba_get_nchan_fx( hDirACRend->hOutSetup.ambisonics_order, 0 );
9792 : }
9793 8 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
9794 : {
9795 6 : hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
9796 6 : move16();
9797 6 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
9798 6 : move16();
9799 : }
9800 2 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
9801 : {
9802 2 : hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
9803 2 : move16();
9804 2 : hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
9805 2 : move16();
9806 : }
9807 : ELSE
9808 : {
9809 0 : assert( 0 && "DirAC: not existing synthesis methods!" );
9810 : }
9811 :
9812 34 : IF( ( hDirACRend->proto_index_dir = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
9813 : {
9814 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9815 : }
9816 :
9817 34 : IF( ( hDirACRend->proto_index_diff = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_diff ) ) == NULL )
9818 : {
9819 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9820 : }
9821 :
9822 34 : set16_fx( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
9823 34 : set16_fx( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
9824 :
9825 34 : hDirACRend->sba_map_tc = sba_map_tc;
9826 :
9827 34 : IF( EQ_16( nchan_transport, 1 ) )
9828 : {
9829 16 : hDirACRend->num_protos_ambi = 1;
9830 16 : move16();
9831 16 : hDirACRend->num_protos_dir = 1;
9832 16 : move16();
9833 16 : hDirACRend->num_protos_diff = 1;
9834 16 : move16();
9835 : }
9836 18 : ELSE IF( EQ_16( nchan_transport, 2 ) )
9837 : {
9838 18 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9839 : {
9840 0 : hDirACRend->num_protos_ambi = 2;
9841 0 : move16();
9842 0 : hDirACRend->num_protos_diff = 1;
9843 0 : move16();
9844 0 : hDirACRend->num_protos_dir = 2;
9845 0 : move16();
9846 0 : hDirACRend->proto_index_dir[1] = 1;
9847 0 : move16();
9848 : }
9849 18 : ELSE IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
9850 : {
9851 : /* Following the foa rendering for code compatibility */
9852 2 : hDirACRend->num_protos_ambi = 2;
9853 2 : move16();
9854 2 : hDirACRend->num_protos_dir = 2;
9855 2 : move16();
9856 2 : hDirACRend->num_protos_diff = 3;
9857 2 : move16();
9858 2 : hDirACRend->proto_index_dir[0] = 0;
9859 2 : move16();
9860 2 : hDirACRend->proto_index_diff[0] = 0;
9861 2 : move16();
9862 : }
9863 : ELSE
9864 : {
9865 16 : hDirACRend->num_protos_ambi = 2;
9866 16 : move16();
9867 16 : hDirACRend->num_protos_diff = 3;
9868 16 : move16();
9869 :
9870 142 : FOR( k = 0; k < hDirACRend->num_outputs_diff; k++ )
9871 : {
9872 126 : IF( ls_azimuth_fx[k] > 0 )
9873 : {
9874 58 : hDirACRend->proto_index_diff[k] = 1;
9875 : }
9876 68 : ELSE IF( ls_azimuth_fx[k] < 0 )
9877 : {
9878 58 : hDirACRend->proto_index_diff[k] = 2;
9879 : }
9880 : ELSE
9881 : {
9882 10 : hDirACRend->proto_index_diff[k] = 0;
9883 : }
9884 126 : move16();
9885 : }
9886 :
9887 16 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
9888 : {
9889 10 : hDirACRend->num_protos_dir = 3;
9890 10 : move16();
9891 10 : Copy( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
9892 : }
9893 : ELSE
9894 : {
9895 6 : hDirACRend->num_protos_dir = 2;
9896 6 : move16();
9897 6 : hDirACRend->proto_index_dir[1] = 1;
9898 6 : move16();
9899 : }
9900 : }
9901 : }
9902 :
9903 : /* direct/diffuse responses */
9904 34 : IF( ( hDirACRend->diffuse_response_function_fx = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
9905 : {
9906 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9907 : }
9908 :
9909 34 : test();
9910 34 : test();
9911 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 ) )
9912 : {
9913 28 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
9914 28 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
9915 : }
9916 : ELSE
9917 : {
9918 6 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
9919 6 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
9920 : }
9921 :
9922 34 : hDirACRend->hoa_encoder_fx = NULL;
9923 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
9924 : {
9925 6 : IF( ( hDirACRend->hoa_encoder_fx = (Word32 *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( Word32 ) ) ) == NULL )
9926 : {
9927 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9928 : }
9929 :
9930 6 : set32_fx( hDirACRend->hoa_encoder_fx, 0, imult1616( nchan_out_woLFE, hDirACRend->num_outputs_diff ) );
9931 6 : compute_hoa_encoder_mtx_fx( ls_azimuth_fx, ls_elevation_fx, hDirACRend->hoa_encoder_fx, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
9932 : }
9933 :
9934 : /* VBAP */
9935 34 : inputMasa->hMasaExtRend->hVBAPdata = NULL;
9936 :
9937 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_VBAP ) )
9938 : {
9939 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 ) )
9940 : {
9941 0 : return error;
9942 : }
9943 : }
9944 :
9945 : /* HOA panning/dec */
9946 34 : hDirACRend->hoa_decoder = NULL;
9947 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) )
9948 : {
9949 14 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
9950 : {
9951 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 ) )
9952 : {
9953 0 : return error;
9954 : }
9955 :
9956 2 : hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
9957 : }
9958 : }
9959 :
9960 : /* decorrelation */
9961 34 : hDirACRend->proto_signal_decorr_on = 1;
9962 34 : move16();
9963 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
9964 : {
9965 2 : hDirACRend->proto_signal_decorr_on = 0;
9966 2 : move16();
9967 : }
9968 :
9969 34 : IF( hDirACRend->proto_signal_decorr_on )
9970 : {
9971 32 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDirACRend->h_freq_domain_decorr_ap_params ),
9972 : &( hDirACRend->h_freq_domain_decorr_ap_state ),
9973 : hSpatParamRendCom->num_freq_bands,
9974 : hDirACRend->num_outputs_diff,
9975 : hDirACRend->num_protos_diff,
9976 : hDirACRend->synthesisConf,
9977 : hDirACRend->frequency_axis_fx,
9978 : nchan_transport,
9979 : output_Fs ) ),
9980 : IVAS_ERR_OK ) )
9981 : {
9982 0 : return error;
9983 : }
9984 : }
9985 :
9986 : /* output synthesis */
9987 34 : IF( NE_32( ( ivas_dirac_dec_output_synthesis_open_fx( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ), IVAS_ERR_OK ) )
9988 : {
9989 0 : return error;
9990 : }
9991 34 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
9992 34 : move16();
9993 :
9994 34 : test();
9995 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9996 : {
9997 12 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
9998 12 : move16();
9999 : }
10000 :
10001 : /*-----------------------------------------------------------------*
10002 : * memory allocation
10003 : *-----------------------------------------------------------------*/
10004 :
10005 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
10006 : {
10007 6 : hDirACRend->proto_frame_f_fx = NULL;
10008 : }
10009 : ELSE
10010 : {
10011 28 : IF( ( hDirACRend->proto_frame_f_fx = (Word32 *) malloc( sizeof( Word32 ) * shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 ) ) ) == NULL )
10012 : {
10013 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
10014 : }
10015 28 : hDirACRend->proto_frame_f_len = shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 );
10016 28 : move16();
10017 : }
10018 :
10019 :
10020 34 : hDirACRend->buffer_energy_fx = NULL;
10021 136 : FOR( i = 0; i < DIRAC_NUM_DIMS; i++ )
10022 : {
10023 3366 : FOR( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
10024 : {
10025 3264 : hDirACRend->buffer_intensity_real_fx[i][j] = NULL;
10026 : }
10027 : }
10028 :
10029 : /* output synthesis */
10030 34 : ivas_dirac_dec_output_synthesis_init_fx( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
10031 :
10032 : /* Allocate stack memory */
10033 34 : IF( NE_32( ( error = ivas_dirac_alloc_mem_fx( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ), IVAS_ERR_OK ) )
10034 : {
10035 0 : return error;
10036 : }
10037 :
10038 34 : inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
10039 :
10040 34 : return error;
10041 : }
10042 :
10043 :
10044 12 : static ivas_error ivas_masa_ext_rend_parambin_init(
10045 : input_masa *inputMasa, /* i/o: MASA external renderer structure */
10046 : const RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration data handle */
10047 : HRTFS_STATISTICS_HANDLE hHrtfStatistics /* i : HRTF statistics */
10048 : )
10049 : {
10050 : DIRAC_DEC_BIN_HANDLE hDiracDecBin;
10051 : HRTFS_PARAMBIN_HANDLE *phHrtfParambin;
10052 : Word16 nBins;
10053 : Word32 output_Fs;
10054 : RENDERER_TYPE renderer_type;
10055 : Word16 j, k, bin;
10056 : Word32 binCenterFreq_fx;
10057 : Word16 tmpFloat_fx;
10058 : ivas_error error;
10059 : Word16 frequency_axis_fx[CLDFB_NO_CHANNELS_MAX];
10060 : const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics;
10061 :
10062 : Word16 pos_idx, num_poses;
10063 : Word16 tmp;
10064 : Word16 tmp_e;
10065 : Word16 tmp2;
10066 :
10067 12 : error = IVAS_ERR_OK;
10068 12 : move32();
10069 :
10070 12 : phHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
10071 : /* Set common variables and defaults */
10072 12 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
10073 12 : move32();
10074 12 : nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
10075 12 : move16();
10076 12 : renderer_type = inputMasa->hMasaExtRend->renderer_type;
10077 12 : move32();
10078 :
10079 12 : num_poses = 1;
10080 12 : move16();
10081 12 : if ( inputMasa->base.ctx.pSplitRendWrapper != NULL )
10082 : {
10083 0 : num_poses = inputMasa->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
10084 0 : move16();
10085 : }
10086 :
10087 24 : for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
10088 : {
10089 12 : hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin[pos_idx];
10090 :
10091 : /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
10092 12 : IF( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
10093 : {
10094 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
10095 : }
10096 :
10097 12 : hDiracDecBin->hTdDecorr = NULL;
10098 12 : hDiracDecBin->hReverb = NULL;
10099 12 : hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
10100 12 : hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
10101 12 : hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
10102 12 : hDiracDecBin->useTdDecorr = 0; /* Always use frequency domain decorrelator in external renderer */
10103 12 : move16();
10104 :
10105 36 : FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
10106 : {
10107 168 : FOR( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
10108 : {
10109 144 : set16_fx( hDiracDecBin->processMtxRe_fx[j][k], 0, nBins );
10110 144 : set16_fx( hDiracDecBin->processMtxIm_fx[j][k], 0, nBins );
10111 : }
10112 :
10113 72 : FOR( k = 0; k < BINAURAL_CHANNELS; k++ )
10114 : {
10115 48 : set16_fx( hDiracDecBin->processMtxDecRe_fx[j][k], 0, nBins );
10116 48 : set16_fx( hDiracDecBin->processMtxDecIm_fx[j][k], 0, nBins );
10117 : }
10118 24 : hDiracDecBin->q_processMtx = Q15;
10119 24 : hDiracDecBin->q_processMtxSCCR = Q15;
10120 24 : hDiracDecBin->q_processMtxPrev = Q15;
10121 24 : hDiracDecBin->q_processMtxPrevSCCR = Q15;
10122 24 : hDiracDecBin->q_processMtxDec = Q15;
10123 24 : hDiracDecBin->q_processMtxDecPrev = Q15;
10124 24 : move16();
10125 24 : move16();
10126 24 : move16();
10127 24 : move16();
10128 24 : move16();
10129 24 : move16();
10130 24 : set_zero_fx( hDiracDecBin->ChEnePrev_fx[j], nBins );
10131 24 : set_zero_fx( hDiracDecBin->ChEneOutPrev_fx[j], nBins );
10132 24 : set16_fx( hDiracDecBin->ChEnePrev_e[j], 0, nBins );
10133 24 : set16_fx( hDiracDecBin->ChEneOutPrev_e[j], 0, nBins );
10134 : }
10135 12 : set_zero_fx( hDiracDecBin->ChCrossRePrev_fx, nBins );
10136 12 : set_zero_fx( hDiracDecBin->ChCrossImPrev_fx, nBins );
10137 12 : set_zero_fx( hDiracDecBin->ChCrossReOutPrev_fx, nBins );
10138 12 : set_zero_fx( hDiracDecBin->ChCrossImOutPrev_fx, nBins );
10139 12 : set16_fx( hDiracDecBin->ChCrossRePrev_e, 0, nBins );
10140 12 : set16_fx( hDiracDecBin->ChCrossImPrev_e, 0, nBins );
10141 12 : set16_fx( hDiracDecBin->ChCrossReOutPrev_e, 0, nBins );
10142 12 : set16_fx( hDiracDecBin->ChCrossImOutPrev_e, 0, nBins );
10143 12 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
10144 12 : move16();
10145 :
10146 732 : FOR( bin = 0; bin < nBins; bin++ )
10147 : {
10148 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*/
10149 : /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
10150 720 : tmp = BASOP_Util_Divide3232_Scale( binCenterFreq_fx, L_shl( 2700, Q15 ), &tmp_e );
10151 720 : IF( tmp_e < 0 )
10152 : {
10153 36 : tmp = shl( tmp, tmp_e ); /*q15*/
10154 36 : tmp_e = 0;
10155 36 : move16();
10156 : }
10157 720 : tmpFloat_fx = s_max( 0, sub( shl_sat( 1, sub( 15, tmp_e ) ), tmp ) ) /*max( 0.0f, 1.0f - binCenterFreq / 2700.0f )*/; /*Q30*/
10158 720 : tmp2 = extract_l( Mult_32_32( binCenterFreq_fx, 1952258 /*=2^31*180/(550)/360*/ ) % 32767 ); //*binCenterFreq_fx * EVS_PI / 550.0f*/
10159 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 );*/
10160 720 : hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( hDiracDecBin->diffuseFieldCoherence_fx[bin], 1 ); /* Q31 */
10161 720 : move32();
10162 720 : move32();
10163 : }
10164 :
10165 : /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
10166 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceX_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
10167 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceY_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
10168 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceZ_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
10169 :
10170 12 : IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC ) ) /* Indication of binaural rendering without room effect */
10171 : {
10172 8 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
10173 8 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
10174 8 : move16();
10175 8 : hDiracDecBin->hReverb = NULL;
10176 : }
10177 4 : ELSE IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) /* Indication of binaural rendering with room effect */
10178 : {
10179 0 : IF( EQ_32( *inputMasa->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
10180 : {
10181 0 : Copy32( ( *phHrtfParambin )->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
10182 0 : pRoomAcoustics = NULL;
10183 : }
10184 : ELSE
10185 : {
10186 0 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28, CLDFB_NO_CHANNELS_MAX );
10187 0 : pRoomAcoustics = &( hRendCfg->roomAcoustics );
10188 : }
10189 0 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
10190 0 : move16();
10191 :
10192 0 : IF( hDiracDecBin->hReverb == NULL && pos_idx == 0 ) /* open reverb only for the main direction */
10193 : {
10194 0 : IF( NE_32( ( error = ivas_binaural_reverb_init_fx( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx, hDiracDecBin->earlyPartEneCorrection_fx ) ), IVAS_ERR_OK ) )
10195 : {
10196 0 : return error;
10197 : }
10198 : }
10199 : }
10200 4 : ELSE IF( EQ_16( renderer_type, RENDERER_STEREO_PARAMETRIC ) )
10201 : {
10202 4 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
10203 4 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
10204 4 : move16();
10205 4 : hDiracDecBin->hReverb = NULL;
10206 4 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
10207 4 : move16();
10208 : }
10209 : ELSE /* Not valid renderer type for this renderer */
10210 : {
10211 0 : assert( false );
10212 : }
10213 :
10214 12 : IF( pos_idx == 0 ) /* open decorrelator only for the main direction */
10215 : {
10216 : /* Always open frequency domain decorrelator */
10217 12 : ivas_dirac_dec_get_frequency_axis_fx( frequency_axis_fx, output_Fs, nBins );
10218 :
10219 12 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
10220 : &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
10221 : nBins,
10222 : BINAURAL_CHANNELS,
10223 : BINAURAL_CHANNELS,
10224 : DIRAC_SYNTHESIS_PSD_LS,
10225 : frequency_axis_fx,
10226 : BINAURAL_CHANNELS,
10227 : output_Fs ) ),
10228 : IVAS_ERR_OK ) )
10229 : {
10230 0 : return error;
10231 : }
10232 : }
10233 :
10234 : /* External renderer uses constant regularization factor */
10235 12 : hDiracDecBin->reqularizationFactor_fx = 6554; /* 0.4f in Q14 */
10236 12 : move16();
10237 :
10238 12 : hDiracDecBin->phHrtfParambin = phHrtfParambin;
10239 :
10240 12 : inputMasa->hMasaExtRend->hDiracDecBin[pos_idx] = hDiracDecBin;
10241 : }
10242 :
10243 12 : return error;
10244 : }
10245 :
10246 :
10247 48 : static ivas_error initMasaExtRenderer(
10248 : input_masa *inputMasa,
10249 : const AUDIO_CONFIG outConfig,
10250 : const RENDER_CONFIG_DATA *hRendCfg,
10251 : hrtf_handles *hrtfs )
10252 : {
10253 : Word16 i;
10254 : ivas_error error;
10255 : MASA_EXT_REND_HANDLE hMasaExtRend;
10256 :
10257 48 : error = IVAS_ERR_OK;
10258 48 : move32();
10259 :
10260 48 : IF( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
10261 : {
10262 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
10263 : }
10264 :
10265 48 : inputMasa->hMasaExtRend = hMasaExtRend;
10266 :
10267 : /* Default init */
10268 48 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
10269 48 : move32();
10270 48 : hMasaExtRend->hDirACRend = NULL;
10271 48 : hMasaExtRend->hSpatParamRendCom = NULL;
10272 432 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
10273 : {
10274 384 : hMasaExtRend->hDiracDecBin[i] = NULL;
10275 : }
10276 48 : hMasaExtRend->hReverb = NULL;
10277 48 : hMasaExtRend->hHrtfParambin = &hrtfs->hHrtfParambin;
10278 48 : hMasaExtRend->hVBAPdata = NULL;
10279 48 : hMasaExtRend->hoa_dec_mtx = NULL;
10280 :
10281 48 : IF( NE_32( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ), IVAS_ERR_OK ) )
10282 : {
10283 0 : return error;
10284 : }
10285 :
10286 48 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
10287 : {
10288 0 : hMasaExtRend->nchan_output = add( inputMasa->base.ctx.pCustomLsOut->num_spk, inputMasa->base.ctx.pCustomLsOut->num_lfe );
10289 0 : move16();
10290 : }
10291 48 : ELSE IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ), IVAS_ERR_OK ) )
10292 : {
10293 0 : return error;
10294 : }
10295 :
10296 48 : SWITCH( outConfig )
10297 : {
10298 4 : case IVAS_AUDIO_CONFIG_MONO:
10299 4 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
10300 : {
10301 2 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
10302 2 : move32();
10303 : }
10304 : ELSE
10305 : {
10306 : /* 1TC MASA to mono does not need rendering. */
10307 2 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
10308 2 : move32();
10309 : }
10310 4 : BREAK;
10311 :
10312 4 : case IVAS_AUDIO_CONFIG_STEREO:
10313 4 : hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
10314 4 : move32();
10315 4 : BREAK;
10316 :
10317 32 : case IVAS_AUDIO_CONFIG_5_1:
10318 : case IVAS_AUDIO_CONFIG_7_1:
10319 : case IVAS_AUDIO_CONFIG_5_1_2:
10320 : case IVAS_AUDIO_CONFIG_5_1_4:
10321 : case IVAS_AUDIO_CONFIG_7_1_4:
10322 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
10323 : case IVAS_AUDIO_CONFIG_FOA:
10324 : case IVAS_AUDIO_CONFIG_HOA2:
10325 : case IVAS_AUDIO_CONFIG_HOA3:
10326 32 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
10327 32 : move32();
10328 32 : BREAK;
10329 :
10330 8 : case IVAS_AUDIO_CONFIG_BINAURAL:
10331 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
10332 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
10333 8 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
10334 8 : move32();
10335 8 : BREAK;
10336 :
10337 0 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
10338 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
10339 0 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
10340 0 : move32();
10341 0 : BREAK;
10342 :
10343 0 : default:
10344 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
10345 : }
10346 :
10347 48 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
10348 : {
10349 : Word16 subframe;
10350 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 ) )
10351 : {
10352 0 : return error;
10353 : }
10354 : /* Simple population of the metadata index map as no adaptation is present */
10355 46 : set16_fx( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
10356 230 : FOR( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
10357 : {
10358 184 : hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
10359 184 : move16();
10360 : }
10361 46 : hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
10362 46 : move16();
10363 : }
10364 :
10365 48 : IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_DIRAC ) )
10366 : {
10367 34 : IF( NE_32( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ), IVAS_ERR_OK ) )
10368 : {
10369 0 : return error;
10370 : }
10371 : }
10372 :
10373 48 : test();
10374 48 : test();
10375 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 ) )
10376 : {
10377 12 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
10378 : {
10379 8 : IF( NE_32( ( error = ivas_dirac_dec_binaural_copy_hrtfs_fx( inputMasa->hMasaExtRend->hHrtfParambin ) ), IVAS_ERR_OK ) )
10380 : {
10381 0 : return error;
10382 : }
10383 : }
10384 12 : if ( NE_32( ( error = ivas_masa_ext_rend_parambin_init( inputMasa, hRendCfg, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
10385 : {
10386 0 : return error;
10387 : }
10388 : }
10389 :
10390 : /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
10391 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
10392 : {
10393 96 : hMasaExtRend->cldfbAnaRend[i] = NULL;
10394 : }
10395 :
10396 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
10397 : {
10398 768 : hMasaExtRend->cldfbSynRend[i] = NULL;
10399 : }
10400 :
10401 48 : IF( NE_32( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
10402 : {
10403 116 : FOR( i = 0; i < hMasaExtRend->nchan_input; i++ )
10404 : {
10405 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 ) )
10406 : {
10407 0 : return error;
10408 : }
10409 : }
10410 :
10411 364 : FOR( i = 0; i < hMasaExtRend->nchan_output; i++ )
10412 : {
10413 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 ) )
10414 : {
10415 0 : return error;
10416 : }
10417 : }
10418 : }
10419 :
10420 48 : inputMasa->hMasaExtRend = hMasaExtRend;
10421 :
10422 48 : return IVAS_ERR_OK;
10423 : }
10424 :
10425 :
10426 666 : static void freeMasaExtRenderer(
10427 : MASA_EXT_REND_HANDLE *hMasaExtRendOut )
10428 : {
10429 : MASA_EXT_REND_HANDLE hMasaExtRend;
10430 : Word16 i;
10431 :
10432 666 : test();
10433 666 : IF( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
10434 : {
10435 618 : return;
10436 : }
10437 :
10438 48 : hMasaExtRend = *hMasaExtRendOut;
10439 :
10440 48 : IF( hMasaExtRend->hDirACRend != NULL )
10441 : {
10442 34 : ivas_dirac_rend_close_fx( &hMasaExtRend->hDirACRend );
10443 : }
10444 :
10445 48 : IF( hMasaExtRend->hSpatParamRendCom != NULL )
10446 : {
10447 46 : ivas_spat_hSpatParamRendCom_close_fx( &hMasaExtRend->hSpatParamRendCom );
10448 : }
10449 :
10450 432 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
10451 : {
10452 384 : if ( hMasaExtRend->hDiracDecBin[i] != NULL )
10453 : {
10454 12 : ivas_dirac_dec_close_binaural_data_fx( &hMasaExtRend->hDiracDecBin[i] );
10455 : }
10456 : }
10457 :
10458 48 : IF( hMasaExtRend->hReverb != NULL )
10459 : {
10460 0 : ivas_binaural_reverb_close_fx( &hMasaExtRend->hReverb );
10461 : }
10462 :
10463 48 : IF( hMasaExtRend->hHrtfParambin != NULL )
10464 : {
10465 48 : ivas_HRTF_parambin_binary_close_fx( hMasaExtRend->hHrtfParambin );
10466 : }
10467 :
10468 48 : IF( hMasaExtRend->hVBAPdata != NULL )
10469 : {
10470 20 : vbap_free_data_fx( &hMasaExtRend->hVBAPdata );
10471 : }
10472 :
10473 48 : IF( hMasaExtRend->hoa_dec_mtx != NULL )
10474 : {
10475 2 : free( hMasaExtRend->hoa_dec_mtx );
10476 : }
10477 :
10478 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
10479 : {
10480 96 : IF( hMasaExtRend->cldfbAnaRend[i] != NULL )
10481 : {
10482 70 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbAnaRend[i] );
10483 : }
10484 : }
10485 :
10486 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
10487 : {
10488 768 : IF( hMasaExtRend->cldfbSynRend[i] != NULL )
10489 : {
10490 318 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbSynRend[i] );
10491 : }
10492 : }
10493 :
10494 48 : free( hMasaExtRend );
10495 48 : *hMasaExtRendOut = NULL;
10496 :
10497 48 : return;
10498 : }
10499 :
10500 25500 : static void intermidiate_ext_dirac_render(
10501 : MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure */
10502 : Word16 to_fix )
10503 : {
10504 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
10505 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
10506 : DIRAC_DEC_STACK_MEM DirAC_mem;
10507 : Word16 ch;
10508 : DIRAC_REND_HANDLE hDirACRend;
10509 : Word16 subframe_idx;
10510 : Word16 slot_idx;
10511 : Word16 nchan_transport;
10512 : Word16 tmp;
10513 :
10514 25500 : hDirACRend = hMasaExtRend->hDirACRend;
10515 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
10516 25500 : nchan_transport = hMasaExtRend->nchan_input;
10517 : DIRAC_OUTPUT_SYNTHESIS_STATE *h_dirac_output_synthesis_state;
10518 :
10519 25500 : h_dirac_output_synthesis_state = &( hDirACRend->h_output_synthesis_psd_state );
10520 :
10521 25500 : subframe_idx = hSpatParamRendCom->subframes_rendered;
10522 25500 : move16();
10523 :
10524 25500 : DirAC_mem = hDirACRend->stack_mem;
10525 :
10526 25500 : IF( to_fix )
10527 : {
10528 12750 : DirAC_mem.reference_power_smooth_q[0] = DirAC_mem.reference_power_q[0] = Q31;
10529 12750 : DirAC_mem.reference_power_smooth_q[1] = DirAC_mem.reference_power_q[1] = Q31;
10530 12750 : move16();
10531 12750 : move16();
10532 12750 : move16();
10533 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
10534 : {
10535 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 */
10536 30736 : hDirACRend->h_output_synthesis_psd_state.direct_responses_q = Q30;
10537 30736 : move16();
10538 : }
10539 :
10540 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx )
10541 : {
10542 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 );
10543 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) */
10544 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 );
10545 12750 : move16();
10546 : }
10547 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx )
10548 : {
10549 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 );
10550 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) */
10551 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 );
10552 12750 : move16();
10553 : }
10554 :
10555 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx )
10556 : {
10557 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 ) );
10558 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) */
10559 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 );
10560 10500 : move16();
10561 : }
10562 :
10563 12750 : Word16 num_channels_dir = hDirACRend->num_outputs_dir;
10564 12750 : move16();
10565 :
10566 12750 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
10567 : {
10568 7500 : num_channels_dir = hDirACRend->hOutSetup.nchan_out_woLFE;
10569 7500 : move16();
10570 : }
10571 :
10572 12750 : IF( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx )
10573 : {
10574 12750 : tmp = L_norm_arr( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, imult1616( num_channels_dir, hSpatParamRendCom->num_freq_bands ) );
10575 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) */
10576 12750 : h_dirac_output_synthesis_state->q_cy_auto_diff_smooth = add( h_dirac_output_synthesis_state->q_cy_auto_diff_smooth, tmp );
10577 12750 : move16();
10578 : }
10579 :
10580 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx )
10581 : {
10582 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 );
10583 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) */
10584 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 );
10585 12750 : move16();
10586 : }
10587 :
10588 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 */
10589 12750 : hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q = Q26;
10590 12750 : move16();
10591 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 */
10592 12750 : hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q = Q26;
10593 12750 : move16();
10594 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx )
10595 : {
10596 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 ) );
10597 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) */
10598 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 );
10599 10500 : move16();
10600 : }
10601 :
10602 12750 : IF( EQ_16( hDirACRend->proto_signal_decorr_on, 1 ) )
10603 : {
10604 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 );
10605 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) */
10606 12000 : hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer = add( hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer, tmp );
10607 12000 : move16();
10608 : }
10609 :
10610 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len > 0 )
10611 : {
10612 : Word16 shift, norm1, norm2;
10613 : Word32 tmp1, tmp2;
10614 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 );
10615 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 );
10616 :
10617 12000 : IF( tmp1 == 0 )
10618 : {
10619 32 : norm1 = 31;
10620 32 : move16();
10621 : }
10622 : ELSE
10623 : {
10624 11968 : norm1 = norm_l( tmp1 );
10625 : }
10626 :
10627 12000 : IF( tmp2 == 0 )
10628 : {
10629 32 : norm2 = 31;
10630 32 : move16();
10631 : }
10632 : ELSE
10633 : {
10634 11968 : norm2 = norm_l( tmp2 );
10635 : }
10636 :
10637 12000 : shift = s_min( norm1, norm2 );
10638 :
10639 12000 : Word16 hr_exp = sub( 31, shift );
10640 :
10641 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) */
10642 12000 : hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q = sub( 31, hr_exp );
10643 12000 : move16();
10644 : }
10645 :
10646 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
10647 : {
10648 : /* CLDFB Analysis*/
10649 77744 : FOR( ch = 0; ch < nchan_transport; ch++ )
10650 : {
10651 47008 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
10652 47008 : move16();
10653 : }
10654 : }
10655 12750 : hDirACRend->proto_frame_dec_f_q = sub( 31, hDirACRend->proto_frame_dec_f_q );
10656 12750 : move16();
10657 :
10658 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx )
10659 : {
10660 10500 : tmp = 0;
10661 10500 : move16();
10662 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 ) )
10663 : {
10664 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 ) ) );
10665 : }
10666 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 ) )
10667 : {
10668 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) */
10669 : }
10670 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 );
10671 10500 : move16();
10672 10500 : tmp = 0;
10673 10500 : move16();
10674 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 ) )
10675 : {
10676 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 ) ) ) );
10677 : }
10678 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 ) )
10679 : {
10680 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) */
10681 : }
10682 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 );
10683 10500 : move16();
10684 10500 : tmp = 0;
10685 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 ) )
10686 : {
10687 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 ) ) );
10688 : }
10689 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 ) )
10690 : {
10691 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) */
10692 : }
10693 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] );
10694 10500 : move16();
10695 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 ) )
10696 : {
10697 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 ) ) ) );
10698 : }
10699 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 ) )
10700 : {
10701 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) */
10702 : }
10703 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] );
10704 10500 : move16();
10705 : }
10706 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx != NULL )
10707 : {
10708 :
10709 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 );
10710 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) */
10711 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 );
10712 10500 : move16();
10713 : }
10714 :
10715 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx != NULL )
10716 : {
10717 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 );
10718 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) */
10719 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 );
10720 9750 : move16();
10721 : }
10722 : }
10723 : ELSE
10724 : {
10725 43350 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[hSpatParamRendCom->subframes_rendered]; slot_idx++ )
10726 : {
10727 : /* CLDFB Analysis*/
10728 77400 : FOR( ch = 0; ch < nchan_transport; ch++ )
10729 : {
10730 46800 : scale_sig32( hMasaExtRend->cldfbAnaRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbAnaRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state ) ); /* Q11 */
10731 46800 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
10732 46800 : move16();
10733 : }
10734 : }
10735 :
10736 123000 : FOR( ch = 0; ch < hDirACRend->hOutSetup.nchan_out_woLFE + hDirACRend->hOutSetup.num_lfe; ch++ )
10737 : {
10738 110250 : scale_sig32( hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbSynRend[0]->Q_cldfb_state ) ); /* Q11 */
10739 110250 : hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
10740 110250 : move16();
10741 : }
10742 : }
10743 :
10744 25500 : return;
10745 : }
10746 :
10747 :
10748 666 : static ivas_error printConfigInfo_rend(
10749 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
10750 : )
10751 : {
10752 : ivas_error error;
10753 : Word8 config_str[50];
10754 :
10755 : /*-----------------------------------------------------------------*
10756 : * Print output audio configuration
10757 : *-----------------------------------------------------------------*/
10758 :
10759 666 : IF( NE_32( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ), IVAS_ERR_OK ) )
10760 : {
10761 0 : return error;
10762 : }
10763 :
10764 666 : fprintf( stdout, "Output configuration: %s\n", config_str );
10765 :
10766 : /*-----------------------------------------------------------------*
10767 : * Print renderer configurations
10768 : *-----------------------------------------------------------------*/
10769 :
10770 666 : fprintf( stdout, "Output sampling rate: %d Hz\n", hIvasRend->sampleRateOut );
10771 :
10772 666 : if ( hIvasRend->headRotData.headRotEnabled )
10773 : {
10774 94 : fprintf( stdout, "Head-tracking: ON\n" );
10775 : }
10776 :
10777 666 : test();
10778 666 : test();
10779 666 : test();
10780 666 : test();
10781 666 : IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) ||
10782 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) ||
10783 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ||
10784 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
10785 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
10786 : {
10787 188 : fprintf( stdout, "Render framesize: %dms\n", i_mult( hIvasRend->num_subframes, 5 ) );
10788 : }
10789 :
10790 666 : return IVAS_ERR_OK;
10791 : }
10792 :
10793 :
10794 : /*---------------------------------------------------------------------*
10795 : * IVAS_REND_PrintInputConfig()
10796 : *
10797 : *
10798 : *---------------------------------------------------------------------*/
10799 :
10800 729 : void IVAS_REND_PrintInputConfig(
10801 : const IVAS_AUDIO_CONFIG inputConfig /* i : input audio configuration */
10802 : )
10803 : {
10804 : Word8 config_str[50];
10805 :
10806 729 : get_channel_config( inputConfig, &config_str[0] );
10807 729 : fprintf( stdout, "Input configuration: %s\n", config_str );
10808 :
10809 729 : return;
10810 : }
10811 :
10812 :
10813 : /*---------------------------------------------------------------------*
10814 : * IVAS_REND_PrintConfig()
10815 : *
10816 : *
10817 : *---------------------------------------------------------------------*/
10818 :
10819 666 : ivas_error IVAS_REND_PrintConfig(
10820 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
10821 : )
10822 : {
10823 666 : if ( hIvasRend == NULL )
10824 : {
10825 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
10826 : }
10827 :
10828 666 : return printConfigInfo_rend( hIvasRend );
10829 : }
10830 :
10831 :
10832 : /*---------------------------------------------------------------------*
10833 : * IVAS_REND_PrintDisclaimer()
10834 : *
10835 : * Print IVAS disclaimer to console
10836 : *---------------------------------------------------------------------*/
10837 :
10838 666 : void IVAS_REND_PrintDisclaimer( void )
10839 : {
10840 666 : print_disclaimer( stderr );
10841 :
10842 666 : return;
10843 : }
|