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