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 215021437 : static Word32 *getSmplPtr_fx(
329 : IVAS_REND_AudioBuffer buffer,
330 : const UWord32 chnlIdx,
331 : const UWord32 smplIdx )
332 : {
333 215021437 : 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 4569484 : FOR( chnlIdx = 0; chnlIdx < (UWord32) buffer.config.numChannels; ++chnlIdx )
452 : {
453 1512693436 : FOR( smplIdx = 0; smplIdx < (UWord32) buffer.config.numSamplesPerChannel; ++smplIdx )
454 : {
455 1508769600 : array[chnlIdx][smplIdx] = *readPtr++;
456 1508769600 : 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 8577247 : IVAS_REND_AudioConfigType getAudioConfigType(
578 : const AUDIO_CONFIG config )
579 : {
580 : IVAS_REND_AudioConfigType type;
581 :
582 8577247 : SWITCH( config )
583 : {
584 4218502 : 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 4218502 : type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
593 4218502 : move16();
594 4218502 : BREAK;
595 1511617 : case IVAS_AUDIO_CONFIG_FOA:
596 : case IVAS_AUDIO_CONFIG_HOA2:
597 : case IVAS_AUDIO_CONFIG_HOA3:
598 1511617 : type = IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS;
599 1511617 : move16();
600 1511617 : 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 8577247 : 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 6102527 : ivas_error getAudioConfigNumChannels(
670 : const AUDIO_CONFIG config,
671 : Word16 *numChannels )
672 : {
673 6102527 : 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 1528116 : 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 1528116 : *numChannels = 2;
689 1528116 : move16();
690 1528116 : BREAK;
691 371308 : case IVAS_AUDIO_CONFIG_FOA:
692 371308 : *numChannels = 4;
693 371308 : move16();
694 371308 : 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 365987 : case IVAS_AUDIO_CONFIG_HOA2:
705 365987 : *numChannels = 9;
706 365987 : move16();
707 365987 : BREAK;
708 149099 : case IVAS_AUDIO_CONFIG_5_1_4:
709 149099 : *numChannels = 10;
710 149099 : move16();
711 149099 : BREAK;
712 1155065 : case IVAS_AUDIO_CONFIG_7_1_4:
713 1155065 : *numChannels = 12;
714 1155065 : move16();
715 1155065 : BREAK;
716 366888 : case IVAS_AUDIO_CONFIG_HOA3:
717 366888 : *numChannels = 16;
718 366888 : move16();
719 366888 : BREAK;
720 0 : default:
721 0 : return IVAS_ERR_NUM_CHANNELS_UNKNOWN;
722 : }
723 :
724 6102527 : move16();
725 6102527 : 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 273185 : static ivas_error getAmbisonicsOrder_fx(
853 : AUDIO_CONFIG config,
854 : Word16 *order )
855 : {
856 273185 : SWITCH( config )
857 : {
858 91071 : case IVAS_AUDIO_CONFIG_FOA:
859 91071 : *order = 1;
860 91071 : move16();
861 91071 : BREAK;
862 91057 : case IVAS_AUDIO_CONFIG_HOA2:
863 91057 : *order = 2;
864 91057 : move16();
865 91057 : BREAK;
866 91057 : case IVAS_AUDIO_CONFIG_HOA3:
867 91057 : *order = 3;
868 91057 : move16();
869 91057 : BREAK;
870 0 : default:
871 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" );
872 : }
873 :
874 273185 : 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 77 : 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 77 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inputSba->base.inConfig, &ambiOrderIn ) ), IVAS_ERR_OK ) )
2902 : {
2903 0 : return error;
2904 : }
2905 :
2906 77 : 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 77 : 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 60 : 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 60 : ivas_output_init( &hOutSetup, outConfig );
2926 60 : 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 77 : tmpDecMtx = NULL;
2938 77 : 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 77 : readPtr = &tmpDecMtx[0];
2944 705 : FOR( chOutIdx = 0; chOutIdx < hOutSetup.nchan_out_woLFE + hOutSetup.num_lfe; ++chOutIdx )
2945 : {
2946 10676 : FOR( chInIdx = 0; chInIdx < SBA_NHARM_HOA3; ++chInIdx )
2947 : {
2948 10048 : test();
2949 10048 : IF( hOutSetup.num_lfe > 0 && EQ_16( chOutIdx, hOutSetup.index_lfe[0] ) )
2950 : {
2951 832 : CONTINUE; /* nothing to be rendered to LFE */
2952 : }
2953 9216 : inputSba->hoaDecMtx_fx[chInIdx][chOutIdx] = L_shl_sat( *readPtr++, Q2 ); /* Q29 + Q2 = Q31 */
2954 9216 : move32();
2955 : }
2956 : }
2957 77 : free( tmpDecMtx );
2958 :
2959 77 : 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 24 : case IVAS_AUDIO_CONFIG_BINAURAL:
3041 : #ifdef FIX_1129_EXT_REND_OUTPUT_HIGH
3042 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
3043 : #endif
3044 : {
3045 24 : if ( hRendCfg->split_rend_config.rendererSelection == ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV )
3046 : {
3047 0 : if ( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
3048 : {
3049 0 : return error;
3050 : }
3051 : }
3052 : else
3053 : {
3054 24 : IF( NE_32( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
3055 : {
3056 0 : return error;
3057 : }
3058 : }
3059 : }
3060 24 : BREAK;
3061 12 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
3062 : #ifndef FIX_1129_EXT_REND_OUTPUT_HIGH
3063 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
3064 : #endif
3065 12 : IF( NE_32( ( error = initSbaPanGainsForMcOut( inputSba, IVAS_AUDIO_CONFIG_7_1_4, NULL ) ), IVAS_ERR_OK ) )
3066 : {
3067 0 : return error;
3068 : }
3069 12 : 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 ) )
3070 : {
3071 0 : return error;
3072 : }
3073 12 : BREAK;
3074 0 : default:
3075 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3076 : }
3077 36 : BREAK;
3078 1 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3079 1 : error = IVAS_ERR_OK;
3080 1 : move32();
3081 1 : BREAK; /* Do nothing */
3082 0 : default:
3083 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3084 : }
3085 :
3086 : /* Check error here to keep switch statement more compact */
3087 126 : IF( NE_32( error, IVAS_ERR_OK ) )
3088 : {
3089 0 : return error;
3090 : }
3091 :
3092 126 : return IVAS_ERR_OK;
3093 : }
3094 :
3095 1 : static ivas_error initSbaMasaRendering(
3096 : input_sba *inputSba,
3097 : Word32 inSampleRate )
3098 : {
3099 : ivas_error error;
3100 : Word16 num_poses;
3101 :
3102 1 : num_poses = 1;
3103 1 : move16();
3104 1 : if ( inputSba->base.ctx.pSplitRendWrapper != NULL )
3105 : {
3106 0 : num_poses = inputSba->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
3107 0 : move16();
3108 : }
3109 :
3110 1 : ivas_rend_closeCrend( &inputSba->crendWrapper, num_poses );
3111 :
3112 1 : IF( NE_32( ( error = ivas_dirac_ana_open_fx( &inputSba->hDirAC, inSampleRate ) ), IVAS_ERR_OK ) )
3113 : {
3114 0 : return error;
3115 : }
3116 :
3117 1 : return IVAS_ERR_OK;
3118 : }
3119 :
3120 126 : static ivas_error setRendInputActiveSba(
3121 : void *input,
3122 : const AUDIO_CONFIG inConfig,
3123 : const IVAS_REND_InputId id,
3124 : RENDER_CONFIG_DATA *hRendCfg,
3125 : hrtf_handles *hrtfs )
3126 : {
3127 : ivas_error error;
3128 : rendering_context rendCtx;
3129 : AUDIO_CONFIG outConfig;
3130 : input_sba *inputSba;
3131 : Word16 pos_idx;
3132 :
3133 126 : inputSba = (input_sba *) input;
3134 126 : rendCtx = inputSba->base.ctx;
3135 126 : outConfig = *rendCtx.pOutConfig;
3136 126 : move32();
3137 :
3138 126 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
3139 : {
3140 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
3141 : }
3142 :
3143 126 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputSba->bufferData_fx, MAX_CLDFB_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
3144 : {
3145 0 : return error;
3146 : }
3147 :
3148 126 : initRendInputBase_fx( &inputSba->base, inConfig, id, rendCtx, inputSba->bufferData_fx, MAX_CLDFB_BUFFER_LENGTH );
3149 :
3150 126 : setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
3151 :
3152 126 : inputSba->crendWrapper = NULL;
3153 126 : inputSba->hDirAC = NULL;
3154 1134 : FOR( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
3155 : {
3156 1008 : initRotGains_fx( inputSba->rot_gains_prev_fx[pos_idx] );
3157 : }
3158 126 : inputSba->cldfbRendWrapper.hHrtfFastConv = hrtfs->hHrtfFastConv;
3159 :
3160 126 : test();
3161 126 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
3162 : {
3163 1 : IF( NE_32( ( error = initSbaMasaRendering( inputSba, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
3164 : {
3165 0 : return error;
3166 : }
3167 : }
3168 126 : IF( NE_32( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
3169 : {
3170 0 : return error;
3171 : }
3172 :
3173 126 : return error;
3174 : }
3175 :
3176 666 : static void clearInputSba(
3177 : input_sba *inputSba )
3178 : {
3179 : rendering_context rendCtx;
3180 : Word16 num_poses;
3181 :
3182 666 : rendCtx = inputSba->base.ctx;
3183 :
3184 666 : num_poses = 1;
3185 666 : move16();
3186 666 : if ( rendCtx.pSplitRendWrapper != NULL )
3187 : {
3188 0 : num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
3189 0 : move16();
3190 : }
3191 :
3192 666 : freeInputBaseBufferData_fx( &inputSba->bufferData_fx );
3193 :
3194 666 : initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3195 :
3196 666 : ivas_rend_closeCrend( &inputSba->crendWrapper, num_poses );
3197 :
3198 666 : IF( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
3199 : {
3200 0 : ivas_rend_closeCldfbRend( &inputSba->cldfbRendWrapper );
3201 : }
3202 :
3203 666 : ivas_dirac_ana_close_fx( &( inputSba->hDirAC ) );
3204 :
3205 666 : return;
3206 : }
3207 :
3208 49 : static ivas_error setRendInputActiveMasa(
3209 : void *input,
3210 : const AUDIO_CONFIG inConfig,
3211 : const IVAS_REND_InputId id,
3212 : RENDER_CONFIG_DATA *hRendCfg,
3213 : hrtf_handles *hrtfs )
3214 : {
3215 : ivas_error error;
3216 : rendering_context rendCtx;
3217 : AUDIO_CONFIG outConfig;
3218 : input_masa *inputMasa;
3219 : Word16 numInChannels;
3220 :
3221 49 : inputMasa = (input_masa *) input;
3222 49 : rendCtx = inputMasa->base.ctx;
3223 49 : outConfig = *rendCtx.pOutConfig;
3224 49 : move32();
3225 :
3226 49 : IF( !isIoConfigPairSupported( inConfig, outConfig ) )
3227 : {
3228 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
3229 : }
3230 :
3231 49 : IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMasa->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
3232 : {
3233 0 : return error;
3234 : }
3235 49 : initRendInputBase_fx( &inputMasa->base, inConfig, id, rendCtx, inputMasa->bufferData_fx, MAX_BUFFER_LENGTH );
3236 :
3237 49 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &numInChannels ) ), IVAS_ERR_OK ) )
3238 : {
3239 0 : return error;
3240 : }
3241 :
3242 49 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
3243 : {
3244 1 : inputMasa->metadataHasBeenFed = false;
3245 1 : move16();
3246 : Word16 temp;
3247 1 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
3248 : {
3249 0 : temp = 1;
3250 : }
3251 : ELSE
3252 : {
3253 1 : temp = 2;
3254 : }
3255 1 : move16();
3256 1 : IF( NE_32( ( error = masaPrerendOpen_fx( &inputMasa->hMasaPrerend, temp, *( inputMasa->base.ctx.pOutSampleRate ) ) ), IVAS_ERR_OK ) )
3257 : {
3258 0 : return error;
3259 : }
3260 : }
3261 : ELSE
3262 : {
3263 48 : IF( NE_32( ( error = initMasaExtRenderer( inputMasa, outConfig, hRendCfg, hrtfs ) ), IVAS_ERR_OK ) )
3264 : {
3265 0 : return error;
3266 : }
3267 48 : inputMasa->metadataHasBeenFed = false;
3268 48 : move16();
3269 : }
3270 :
3271 49 : return IVAS_ERR_OK;
3272 : }
3273 :
3274 666 : static void clearInputMasa(
3275 : input_masa *inputMasa )
3276 : {
3277 : rendering_context rendCtx;
3278 :
3279 666 : rendCtx = inputMasa->base.ctx;
3280 :
3281 666 : freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
3282 :
3283 666 : masaPrerendClose_fx( &inputMasa->hMasaPrerend );
3284 :
3285 666 : freeMasaExtRenderer( &inputMasa->hMasaExtRend );
3286 :
3287 666 : initRendInputBase_fx( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3288 :
3289 666 : return;
3290 : }
3291 :
3292 :
3293 : /*-------------------------------------------------------------------------
3294 : * IVAS_REND_Open()
3295 : *
3296 : *
3297 : *------------------------------------------------------------------------*/
3298 :
3299 666 : ivas_error IVAS_REND_Open(
3300 : IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */
3301 : const Word32 outputSampleRate, /* i : output sampling rate */
3302 : const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */
3303 : const bool asHrtfBinary, /* i : load hrtf binary file */
3304 : const Word16 nonDiegeticPan, /* i : non-diegetic object flag */
3305 : const Word32 nonDiegeticPanGain, /* i : non-diegetic panning gain Q31*/
3306 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3307 : const Word16 Opt_Headrotation, /* i : indicates whether head-rotation is used */
3308 : const Word16 Opt_ExternalOrientation, /* i : indicates whether external orientations are used */
3309 : #endif
3310 : const Word16 num_subframes /* i : number of subframes */
3311 : )
3312 : {
3313 : Word16 i;
3314 : Word16 j;
3315 : IVAS_REND_HANDLE hIvasRend;
3316 : ivas_error error;
3317 : Word16 numOutChannels;
3318 :
3319 : /* Validate function arguments */
3320 666 : IF( phIvasRend == NULL )
3321 : {
3322 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3323 : }
3324 :
3325 666 : IF( NE_32( ( error = validateOutputAudioConfig( outConfig ) ), IVAS_ERR_OK ) )
3326 : {
3327 0 : return error;
3328 : }
3329 :
3330 666 : IF( NE_32( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ), IVAS_ERR_OK ) )
3331 : {
3332 0 : return error;
3333 : }
3334 :
3335 666 : *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
3336 666 : IF( *phIvasRend == NULL )
3337 : {
3338 0 : return IVAS_ERR_FAILED_ALLOC;
3339 : }
3340 :
3341 666 : hIvasRend = *phIvasRend;
3342 666 : hIvasRend->sampleRateOut = outputSampleRate;
3343 666 : hIvasRend->outputConfig = outConfig;
3344 666 : hIvasRend->customLsOut = defaultCustomLs();
3345 666 : hIvasRend->hLimiter = NULL;
3346 666 : hIvasRend->efapOutWrapper.hEfap = NULL;
3347 666 : hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
3348 666 : hIvasRend->num_subframes = num_subframes;
3349 :
3350 : /* Initialize limiter */
3351 666 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
3352 : {
3353 0 : return error;
3354 : }
3355 :
3356 666 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ), IVAS_ERR_OK ) )
3357 : {
3358 0 : return error;
3359 : }
3360 :
3361 : /* Initialize headrotation data */
3362 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3363 666 : hIvasRend->headRotData.headRotEnabled = 0;
3364 666 : IF( Opt_Headrotation )
3365 : {
3366 : #endif
3367 94 : IF( NE_32( ( error = initHeadRotation_fx( hIvasRend ) ), IVAS_ERR_OK ) )
3368 : {
3369 0 : return error;
3370 : }
3371 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3372 : }
3373 : #endif
3374 :
3375 : /* Initialize external orientation data */
3376 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3377 666 : hIvasRend->hExternalOrientationData = NULL;
3378 666 : IF( Opt_ExternalOrientation )
3379 : {
3380 : #endif
3381 0 : IF( NE_32( ( error = ivas_external_orientation_open( &( hIvasRend->hExternalOrientationData ), num_subframes ) ), IVAS_ERR_OK ) )
3382 : {
3383 0 : return error;
3384 : }
3385 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3386 : }
3387 : #endif
3388 :
3389 : /* Initilize combined orientation data */
3390 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3391 666 : hIvasRend->hCombinedOrientationData = NULL;
3392 666 : IF( Opt_Headrotation || Opt_ExternalOrientation )
3393 : {
3394 : #endif
3395 94 : IF( NE_32( ( error = ivas_combined_orientation_open( &( hIvasRend->hCombinedOrientationData ), outputSampleRate, num_subframes ) ), IVAS_ERR_OK ) )
3396 : {
3397 0 : return error;
3398 : }
3399 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3400 : }
3401 : #endif
3402 :
3403 : /* Initialize EFAP */
3404 666 : IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
3405 : {
3406 0 : return error;
3407 : }
3408 :
3409 : /* Initialize inputs */
3410 666 : hIvasRend->splitRendWrapper = NULL;
3411 666 : test();
3412 666 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
3413 : {
3414 0 : if ( ( hIvasRend->splitRendWrapper = (SPLIT_REND_WRAPPER *) malloc( sizeof( SPLIT_REND_WRAPPER ) ) ) == NULL )
3415 : {
3416 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS renderer handle" );
3417 : }
3418 :
3419 0 : isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
3420 : }
3421 :
3422 3330 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
3423 : {
3424 2664 : initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3425 2664 : hIvasRend->inputsIsm[i].crendWrapper = NULL;
3426 2664 : hIvasRend->inputsIsm[i].hReverb = NULL;
3427 2664 : hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
3428 21312 : FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j )
3429 : {
3430 18648 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3431 18648 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3432 : }
3433 2664 : hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
3434 2664 : move16();
3435 2664 : hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
3436 2664 : move32();
3437 2664 : hIvasRend->inputsIsm[i].hOMasa = NULL;
3438 2664 : hIvasRend->inputsIsm[i].bufferData_fx = NULL;
3439 : }
3440 :
3441 1332 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3442 : {
3443 666 : initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3444 :
3445 666 : hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
3446 666 : hIvasRend->inputsMc[i].crendWrapper = NULL;
3447 666 : hIvasRend->inputsMc[i].hReverb = NULL;
3448 666 : hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
3449 666 : hIvasRend->inputsMc[i].bufferData_fx = NULL;
3450 666 : hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL;
3451 666 : hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
3452 666 : move16();
3453 666 : hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
3454 666 : move32();
3455 666 : hIvasRend->inputsMc[i].hMcMasa = NULL;
3456 5328 : FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j )
3457 : {
3458 4662 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3459 4662 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3460 : }
3461 : }
3462 :
3463 1332 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3464 : {
3465 666 : initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3466 :
3467 666 : hIvasRend->inputsSba[i].crendWrapper = NULL;
3468 666 : hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend = NULL;
3469 666 : hIvasRend->inputsSba[i].cldfbRendWrapper.hHrtfFastConv = NULL;
3470 666 : hIvasRend->inputsSba[i].bufferData_fx = NULL;
3471 666 : hIvasRend->inputsSba[i].hDirAC = NULL;
3472 : }
3473 :
3474 1332 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3475 : {
3476 666 : initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3477 :
3478 666 : hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
3479 666 : hIvasRend->inputsMasa[i].bufferData_fx = NULL;
3480 666 : hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
3481 666 : hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
3482 666 : move16();
3483 : }
3484 :
3485 666 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
3486 666 : hIvasRend->hHrtfs.hHrtfParambin = NULL;
3487 666 : hIvasRend->hHrtfs.hHrtfTD = NULL;
3488 666 : hIvasRend->hHrtfs.hSetOfHRTF = NULL;
3489 666 : hIvasRend->hHrtfs.hHrtfStatistics = NULL;
3490 666 : IF( asHrtfBinary )
3491 : {
3492 0 : IF( NE_32( ( error = ivas_HRTF_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfTD ) ) ), IVAS_ERR_OK ) )
3493 : {
3494 0 : return error;
3495 : }
3496 0 : IF( NE_32( ( error = ivas_HRTF_CRend_binary_open_fx( &( hIvasRend->hHrtfs.hSetOfHRTF ) ) ), IVAS_ERR_OK ) )
3497 : {
3498 0 : return error;
3499 : }
3500 0 : IF( NE_32( ( error = ivas_HRTF_fastconv_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfFastConv ) ) ), IVAS_ERR_OK ) )
3501 : {
3502 0 : return error;
3503 : }
3504 0 : IF( NE_32( ( error = ivas_HRTF_parambin_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfParambin ) ) ), IVAS_ERR_OK ) )
3505 : {
3506 0 : return error;
3507 : }
3508 0 : IF( NE_32( ( error = ivas_HRTF_statistics_binary_open( &( hIvasRend->hHrtfs.hHrtfStatistics ) ) ), IVAS_ERR_OK ) )
3509 : {
3510 0 : return error;
3511 : }
3512 : }
3513 :
3514 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3515 666 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
3516 : {
3517 : #endif
3518 60 : IF( NE_32( ( error = ivas_HRTF_statistics_init( &( hIvasRend->hHrtfs.hHrtfStatistics ), hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
3519 : {
3520 0 : return error;
3521 : }
3522 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
3523 : }
3524 : #endif
3525 :
3526 666 : return IVAS_ERR_OK;
3527 : }
3528 :
3529 :
3530 152 : static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup(
3531 : const IVAS_CUSTOM_LS_DATA rendCustomLsLayout )
3532 : {
3533 : Word16 i;
3534 : LSSETUP_CUSTOM_STRUCT customLs;
3535 :
3536 : /* Copy layout description */
3537 152 : customLs.num_spk = rendCustomLsLayout.num_spk;
3538 152 : move16();
3539 152 : Copy32( rendCustomLsLayout.azimuth_fx, customLs.ls_azimuth_fx, rendCustomLsLayout.num_spk );
3540 152 : Copy32( rendCustomLsLayout.elevation_fx, customLs.ls_elevation_fx, rendCustomLsLayout.num_spk );
3541 152 : customLs.is_planar_setup = 1;
3542 152 : move16();
3543 776 : FOR( i = 0; i < rendCustomLsLayout.num_spk; ++i )
3544 : {
3545 776 : IF( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
3546 : {
3547 152 : customLs.is_planar_setup = 0;
3548 152 : move16();
3549 152 : BREAK;
3550 : }
3551 : }
3552 :
3553 152 : customLs.num_lfe = rendCustomLsLayout.num_lfe;
3554 152 : move16();
3555 152 : Copy( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
3556 :
3557 152 : return customLs;
3558 : }
3559 :
3560 :
3561 152 : static ivas_error validateCustomLsLayout_fx(
3562 : const IVAS_CUSTOM_LS_DATA layout )
3563 : {
3564 : Word16 i;
3565 :
3566 : /* Negative number of speakers or LFEs makes no sense */
3567 152 : test();
3568 152 : IF( layout.num_spk < 0 || layout.num_lfe < 0 )
3569 : {
3570 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3571 : }
3572 :
3573 : /* There must be at least one speaker or LFE in the layout */
3574 152 : IF( add( layout.num_spk, layout.num_lfe ) <= 0 )
3575 : {
3576 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3577 : }
3578 :
3579 : /* LFE indices must be positive */
3580 152 : FOR( i = 0; i < layout.num_lfe; ++i )
3581 : {
3582 0 : IF( layout.lfe_idx[i] < 0 )
3583 : {
3584 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3585 : }
3586 : }
3587 :
3588 152 : return IVAS_ERR_OK;
3589 : }
3590 :
3591 :
3592 : /*-------------------------------------------------------------------*
3593 : * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
3594 : *
3595 : *
3596 : *-------------------------------------------------------------------*/
3597 :
3598 47 : ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
3599 : IVAS_REND_HANDLE hIvasRend,
3600 : const IVAS_CUSTOM_LS_DATA layout )
3601 : {
3602 : Word16 i, numOutChannels;
3603 : ivas_error error;
3604 : input_mc *inputMc;
3605 : input_sba *inputSba;
3606 :
3607 : /* Validate function arguments */
3608 47 : IF( hIvasRend == NULL )
3609 : {
3610 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3611 : }
3612 :
3613 47 : IF( NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
3614 : {
3615 : /* Specifying details of custom speaker layout only makes sense if output config is set to custom speaker layout */
3616 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3617 : }
3618 :
3619 47 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
3620 : {
3621 0 : return error;
3622 : }
3623 :
3624 47 : hIvasRend->customLsOut = makeCustomLsSetup( layout );
3625 :
3626 : /* Re-initialize limiter - number of output channels may have changed */
3627 47 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
3628 : {
3629 0 : return error;
3630 : }
3631 :
3632 47 : IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
3633 : {
3634 0 : return error;
3635 : }
3636 :
3637 : /* Re-initialize EFAP - output layout has changed or has been fully defined for the first time */
3638 47 : IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, hIvasRend->outputConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
3639 : {
3640 0 : return error;
3641 : }
3642 :
3643 : /* Re-initialize panning gains for each active MC input, This includes re-initializing
3644 : * LFE handling for the new output layout, which means custom LFE handling is overwritten,
3645 : * if previously set for any MC input. */
3646 94 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3647 : {
3648 47 : inputMc = &hIvasRend->inputsMc[i];
3649 47 : IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3650 : {
3651 : /* Input inactive, skip. */
3652 47 : CONTINUE;
3653 : }
3654 :
3655 0 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
3656 :
3657 0 : IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
3658 : {
3659 0 : return error;
3660 : }
3661 : }
3662 :
3663 : /* Re-initialize panning gains for each active SBA input */
3664 94 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3665 : {
3666 47 : inputSba = &hIvasRend->inputsSba[i];
3667 :
3668 47 : IF( EQ_32( inputSba->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3669 : {
3670 : /* Input inactive, skip. */
3671 47 : CONTINUE;
3672 : }
3673 0 : IF( NE_32( ( error = updateSbaPanGains( inputSba, hIvasRend->outputConfig, hIvasRend->hRendererConfig, NULL, NULL ) ), IVAS_ERR_OK ) )
3674 : {
3675 0 : return error;
3676 : }
3677 : }
3678 :
3679 47 : return IVAS_ERR_OK;
3680 : }
3681 :
3682 : /*-------------------------------------------------------------------*
3683 : * IVAS_REND_NumOutChannels()
3684 : *
3685 : *
3686 : *-------------------------------------------------------------------*/
3687 :
3688 1127519 : ivas_error IVAS_REND_NumOutChannels(
3689 : IVAS_REND_CONST_HANDLE hIvasRend,
3690 : Word16 *numOutChannels )
3691 : {
3692 : ivas_error error;
3693 :
3694 : /* Validate function arguments */
3695 1127519 : test();
3696 1127519 : IF( hIvasRend == NULL || numOutChannels == NULL )
3697 : {
3698 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3699 : }
3700 :
3701 : /* Handle special cases where additional info is needed from the renderer, otherwise use getAudioConfigNumChannels() */
3702 1127519 : SWITCH( hIvasRend->outputConfig )
3703 : {
3704 36003 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3705 36003 : *numOutChannels = add( hIvasRend->customLsOut.num_spk, hIvasRend->customLsOut.num_lfe );
3706 36003 : move16();
3707 36003 : BREAK;
3708 1091516 : default:
3709 1091516 : IF( NE_32( ( error = getAudioConfigNumChannels( hIvasRend->outputConfig, numOutChannels ) ), IVAS_ERR_OK ) )
3710 : {
3711 0 : return error;
3712 : }
3713 1091516 : BREAK;
3714 : }
3715 :
3716 1127519 : return IVAS_ERR_OK;
3717 : }
3718 :
3719 :
3720 973 : static IVAS_REND_InputId makeInputId(
3721 : AUDIO_CONFIG config,
3722 : const Word32 inputIndex )
3723 : {
3724 : /* Put config type in second byte (from LSB), put index + 1 in first byte
3725 : *
3726 : * Index is incremented here so that a valid ID can never be 0. */
3727 973 : return (IVAS_REND_InputId) UL_or( UL_lshl( ( (UWord32) getAudioConfigType( config ) ), 8 ), L_add( inputIndex, 1 ) );
3728 : }
3729 :
3730 :
3731 3133018 : static ivas_error getInputById(
3732 : IVAS_REND_HANDLE hIvasRend,
3733 : IVAS_REND_InputId inputId,
3734 : void **ppInput )
3735 : {
3736 : Word32 inputIndex;
3737 : IVAS_REND_AudioConfigType configType;
3738 : input_base *pInputBase;
3739 :
3740 : /* Reverse makeInputId() */
3741 3133018 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3742 3133018 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3743 :
3744 : /* Validate values derived from input ID */
3745 3133018 : IF( inputIndex < 0 )
3746 : {
3747 0 : return IVAS_ERR_INVALID_INPUT_ID;
3748 : }
3749 3133018 : SWITCH( configType )
3750 : {
3751 2495576 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3752 2495576 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3753 : {
3754 0 : return IVAS_ERR_INVALID_INPUT_ID;
3755 : }
3756 2495576 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3757 2495576 : BREAK;
3758 360012 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3759 360012 : IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
3760 : {
3761 0 : return IVAS_ERR_INVALID_INPUT_ID;
3762 : }
3763 360012 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3764 360012 : BREAK;
3765 251881 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3766 251881 : IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
3767 : {
3768 0 : return IVAS_ERR_INVALID_INPUT_ID;
3769 : }
3770 251881 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3771 251881 : BREAK;
3772 25549 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3773 25549 : IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
3774 : {
3775 0 : return IVAS_ERR_INVALID_INPUT_ID;
3776 : }
3777 25549 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3778 25549 : BREAK;
3779 0 : default:
3780 0 : return IVAS_ERR_INVALID_INPUT_ID;
3781 : }
3782 :
3783 : /* Ensure input ID matches and that input is active */
3784 3133018 : test();
3785 3133018 : IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3786 : {
3787 0 : return IVAS_ERR_INVALID_INPUT_ID;
3788 : }
3789 :
3790 : /* Validation done, set value via output parameter */
3791 3133018 : *ppInput = pInputBase;
3792 :
3793 3133018 : return IVAS_ERR_OK;
3794 : }
3795 :
3796 :
3797 630413 : static ivas_error getConstInputById(
3798 : IVAS_REND_CONST_HANDLE hIvasRend,
3799 : const IVAS_REND_InputId inputId,
3800 : const void **ppInput )
3801 : {
3802 : Word32 inputIndex;
3803 : IVAS_REND_AudioConfigType configType;
3804 : const input_base *pInputBase;
3805 :
3806 : /* Reverse makeInputId() */
3807 630413 : inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
3808 630413 : configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
3809 :
3810 : /* Validate values derived from input ID */
3811 630413 : IF( inputIndex < 0 )
3812 : {
3813 0 : return IVAS_ERR_INVALID_INPUT_ID;
3814 : }
3815 630413 : SWITCH( configType )
3816 : {
3817 426 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3818 426 : IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
3819 : {
3820 0 : return IVAS_ERR_INVALID_INPUT_ID;
3821 : }
3822 426 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3823 426 : BREAK;
3824 359907 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3825 359907 : IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
3826 : {
3827 0 : return IVAS_ERR_INVALID_INPUT_ID;
3828 : }
3829 359907 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3830 359907 : BREAK;
3831 251881 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3832 251881 : IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
3833 : {
3834 0 : return IVAS_ERR_INVALID_INPUT_ID;
3835 : }
3836 251881 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3837 251881 : BREAK;
3838 18199 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3839 18199 : IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
3840 : {
3841 0 : return IVAS_ERR_INVALID_INPUT_ID;
3842 : }
3843 18199 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3844 18199 : BREAK;
3845 0 : default:
3846 0 : return IVAS_ERR_INVALID_INPUT_ID;
3847 : }
3848 :
3849 : /* Ensure input ID matches and that input is active */
3850 630413 : test();
3851 630413 : IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3852 : {
3853 0 : return IVAS_ERR_INVALID_INPUT_ID;
3854 : }
3855 :
3856 : /* Validation done, set value via output parameter */
3857 630413 : *ppInput = pInputBase;
3858 :
3859 630413 : return IVAS_ERR_OK;
3860 : }
3861 :
3862 973 : static ivas_error findFreeInputSlot_fx(
3863 : const void *inputs,
3864 : const Word32 inputStructSize,
3865 : const Word32 maxInputs,
3866 : Word32 *inputIndex )
3867 : {
3868 : /* Using a void pointer and a separately provided size is a hack for this function
3869 : to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
3870 : Assumptions:
3871 : - input_base is always the first member in the input struct
3872 : - provided size is correct
3873 : */
3874 :
3875 : Word32 i;
3876 : bool canAddInput;
3877 : const UWord8 *pByte;
3878 : const input_base *pInputBase;
3879 :
3880 973 : canAddInput = false;
3881 973 : move16();
3882 :
3883 : /* Find first unused input in array */
3884 1353 : FOR( ( i = 0, pByte = inputs ); i < maxInputs; ( ++i, pByte += inputStructSize ) )
3885 : {
3886 1353 : pInputBase = (const input_base *) pByte;
3887 :
3888 1353 : IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
3889 : {
3890 973 : *inputIndex = i;
3891 973 : move32();
3892 973 : canAddInput = true;
3893 973 : move16();
3894 973 : BREAK;
3895 : }
3896 : }
3897 :
3898 973 : IF( !canAddInput )
3899 : {
3900 0 : return IVAS_ERR_TOO_MANY_INPUTS;
3901 : }
3902 :
3903 973 : return IVAS_ERR_OK;
3904 : }
3905 :
3906 :
3907 : /*-------------------------------------------------------------------------
3908 : * Function getCldfbRendFlag()
3909 : *
3910 : *
3911 : *------------------------------------------------------------------------*/
3912 :
3913 0 : static Word16 getCldfbRendFlag(
3914 : IVAS_REND_HANDLE hIvasRend, /* i : Renderer handle */
3915 : const IVAS_REND_AudioConfigType new_configType )
3916 : {
3917 : Word16 i;
3918 0 : Word16 numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0;
3919 : Word16 isCldfbRend;
3920 :
3921 0 : move16();
3922 0 : move16();
3923 0 : move16();
3924 0 : move16();
3925 :
3926 0 : isCldfbRend = 0;
3927 0 : move16();
3928 :
3929 0 : IF( hIvasRend->hRendererConfig != NULL )
3930 : {
3931 0 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3932 : {
3933 0 : numMasaInputs = add( numMasaInputs, ( hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ? 0 : 1 );
3934 0 : move16();
3935 : }
3936 0 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3937 : {
3938 0 : numSbaInputs = add( numSbaInputs, ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1 );
3939 0 : move16();
3940 : }
3941 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
3942 : {
3943 0 : numIsmInputs = add( numIsmInputs, ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1 );
3944 0 : move16();
3945 : }
3946 0 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3947 : {
3948 0 : numMcInputs = add( numMcInputs, ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1 );
3949 0 : move16();
3950 : }
3951 :
3952 0 : IF( GT_16( numIsmInputs, 0 ) || GT_16( numMcInputs, 0 ) )
3953 : {
3954 0 : isCldfbRend = 0;
3955 0 : move16();
3956 : }
3957 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 ) ) )
3958 : {
3959 0 : isCldfbRend = 1;
3960 0 : move16();
3961 : }
3962 : }
3963 :
3964 0 : return isCldfbRend;
3965 : }
3966 :
3967 :
3968 : /*-------------------------------------------------------------------------
3969 : * Function ivas_pre_rend_init()
3970 : *
3971 : *
3972 : *------------------------------------------------------------------------*/
3973 :
3974 0 : static ivas_error ivas_pre_rend_init(
3975 : SPLIT_REND_WRAPPER *pSplitRendWrapper,
3976 : IVAS_REND_AudioBuffer *pSplitRendEncBuffer,
3977 : ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config,
3978 : IVAS_REND_HeadRotData headRotData,
3979 : const Word32 outputSampleRate,
3980 : const AUDIO_CONFIG outConfig,
3981 : const Word16 cldfb_in_flag,
3982 : const Word16 num_subframes )
3983 : {
3984 : ivas_error error;
3985 : IVAS_REND_AudioBufferConfig bufConfig;
3986 :
3987 0 : test();
3988 0 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
3989 : {
3990 0 : IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
3991 : {
3992 0 : ISAR_PRE_REND_GetMultiBinPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData, headRotData.sr_pose_pred_axis );
3993 : }
3994 0 : ELSE IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) )
3995 : {
3996 0 : isar_renderSplitUpdateNoCorrectionPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData );
3997 : }
3998 :
3999 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 )
4000 : {
4001 0 : return error;
4002 : }
4003 :
4004 : /*allocate for CLDFB in and change to TD during process if needed*/
4005 0 : bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL;
4006 0 : bufConfig.numChannels = i_mult( BINAURAL_CHANNELS, pSplitRendWrapper->multiBinPoseData.num_poses );
4007 0 : bufConfig.is_cldfb = 1;
4008 0 : pSplitRendEncBuffer->config = bufConfig;
4009 0 : move16();
4010 0 : move16();
4011 0 : move16();
4012 0 : move32();
4013 :
4014 0 : IF( ( pSplitRendEncBuffer->data_fx = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL )
4015 : {
4016 0 : return IVAS_ERR_FAILED_ALLOC;
4017 : }
4018 :
4019 0 : pSplitRendEncBuffer->q_factor = 0;
4020 0 : pSplitRendEncBuffer->pq_fact = &pSplitRendEncBuffer->q_factor;
4021 : }
4022 : ELSE
4023 : {
4024 : IVAS_REND_AudioBufferConfig bufConfig2;
4025 :
4026 0 : bufConfig2.numSamplesPerChannel = 0;
4027 0 : bufConfig2.numChannels = 0;
4028 0 : bufConfig2.is_cldfb = 0;
4029 0 : pSplitRendEncBuffer->config = bufConfig2;
4030 0 : pSplitRendEncBuffer->data_fx = NULL;
4031 0 : pSplitRendEncBuffer->pq_fact = NULL;
4032 0 : pSplitRendEncBuffer->q_factor = 0;
4033 0 : move16();
4034 0 : move16();
4035 0 : move16();
4036 0 : move32();
4037 0 : move32();
4038 : }
4039 :
4040 0 : return IVAS_ERR_OK;
4041 : }
4042 :
4043 :
4044 : /*-------------------------------------------------------------------*
4045 : * IVAS_REND_AddInput()
4046 : *
4047 : *
4048 : *-------------------------------------------------------------------*/
4049 :
4050 973 : ivas_error IVAS_REND_AddInput_fx(
4051 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4052 : const AUDIO_CONFIG inConfig, /* i : audio config for a new input */
4053 : IVAS_REND_InputId *inputId /* o : ID of the new input */
4054 : )
4055 : {
4056 : ivas_error error;
4057 : Word32 maxNumInputsOfType;
4058 : void *inputsArray;
4059 : Word32 inputStructSize;
4060 : ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles *hrtfs );
4061 : Word32 inputIndex;
4062 :
4063 : /* Validate function arguments */
4064 973 : test();
4065 973 : IF( hIvasRend == NULL || inputId == NULL )
4066 : {
4067 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4068 : }
4069 :
4070 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 )
4071 : {
4072 : Word16 cldfb_in_flag;
4073 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) );
4074 :
4075 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 )
4076 : {
4077 0 : return error;
4078 : }
4079 : }
4080 :
4081 :
4082 973 : SWITCH( getAudioConfigType( inConfig ) )
4083 : {
4084 426 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
4085 426 : maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
4086 426 : inputsArray = hIvasRend->inputsIsm;
4087 426 : inputStructSize = sizeof( *hIvasRend->inputsIsm );
4088 426 : activateInput = setRendInputActiveIsm;
4089 426 : move32();
4090 426 : move32();
4091 426 : BREAK;
4092 372 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
4093 372 : maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
4094 372 : inputsArray = hIvasRend->inputsMc;
4095 372 : inputStructSize = sizeof( *hIvasRend->inputsMc );
4096 372 : activateInput = setRendInputActiveMc;
4097 372 : move32();
4098 372 : move32();
4099 372 : BREAK;
4100 126 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
4101 126 : maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
4102 126 : inputsArray = hIvasRend->inputsSba;
4103 126 : inputStructSize = sizeof( *hIvasRend->inputsSba );
4104 126 : activateInput = setRendInputActiveSba;
4105 126 : move32();
4106 126 : move32();
4107 126 : BREAK;
4108 49 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
4109 49 : maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
4110 49 : inputsArray = hIvasRend->inputsMasa;
4111 49 : inputStructSize = sizeof( *hIvasRend->inputsMasa );
4112 49 : activateInput = setRendInputActiveMasa;
4113 49 : move32();
4114 49 : move32();
4115 49 : BREAK;
4116 0 : default:
4117 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4118 : }
4119 :
4120 : /* Find first free input in array corresponding to input type */
4121 973 : IF( NE_32( ( error = findFreeInputSlot_fx( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ), IVAS_ERR_OK ) )
4122 : {
4123 0 : return error;
4124 : }
4125 :
4126 973 : *inputId = makeInputId( inConfig, inputIndex );
4127 973 : move16();
4128 973 : IF( NE_32( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ), IVAS_ERR_OK ) )
4129 : {
4130 0 : return error;
4131 : }
4132 :
4133 973 : return IVAS_ERR_OK;
4134 : }
4135 :
4136 :
4137 : /*-------------------------------------------------------------------*
4138 : * IVAS_REND_ConfigureCustomInputLoudspeakerLayout()
4139 : *
4140 : *
4141 : * Note: this will reset any custom LFE routing set for the input
4142 : *-------------------------------------------------------------------*/
4143 105 : ivas_error IVAS_REND_ConfigureCustomInputLoudspeakerLayout(
4144 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4145 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4146 : const IVAS_CUSTOM_LS_DATA layout /* i : custom loudspeaker layout for input */
4147 : )
4148 : {
4149 : input_mc *inputMc;
4150 : ivas_error error;
4151 :
4152 : /* Validate function arguments */
4153 105 : IF( hIvasRend == NULL )
4154 : {
4155 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4156 : }
4157 :
4158 105 : IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
4159 : {
4160 0 : return error;
4161 : }
4162 :
4163 105 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputMc ) ), IVAS_ERR_OK ) )
4164 : {
4165 0 : return error;
4166 : }
4167 :
4168 105 : IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
4169 : {
4170 : /* Specifying details of custom speaker layout only makes sense if input config is set to custom speaker layout */
4171 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4172 : }
4173 :
4174 : /* Re-initialize panning gains for the MC input, This includes re-initializing LFE handling
4175 : * for the new input layout, which means custom LFE handling is overwritten, if previously
4176 : * set for the MC input. */
4177 105 : inputMc->customLsInput = makeCustomLsSetup( layout );
4178 :
4179 105 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
4180 :
4181 105 : IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inputMc->base.inConfig, &inputMc->customLsInput ) ), IVAS_ERR_OK ) )
4182 : {
4183 0 : return error;
4184 : }
4185 :
4186 105 : test();
4187 105 : test();
4188 :
4189 105 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
4190 : {
4191 36 : IF( NE_32( ( error = initMcBinauralRendering( inputMc, inputMc->base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
4192 : {
4193 0 : return error;
4194 : }
4195 : }
4196 :
4197 105 : IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
4198 : {
4199 0 : return error;
4200 : }
4201 :
4202 105 : return IVAS_ERR_OK;
4203 : }
4204 :
4205 : /*-------------------------------------------------------------------*
4206 : * IVAS_REND_SetInputGain()
4207 : *
4208 : *
4209 : *-------------------------------------------------------------------*/
4210 973 : ivas_error IVAS_REND_SetInputGain_fx(
4211 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4212 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4213 : const Word32 gain /* i : linear gain (not in dB) Q30 */
4214 : )
4215 : {
4216 : input_base *inputBase;
4217 : ivas_error error;
4218 :
4219 : /* Validate function arguments */
4220 973 : IF( hIvasRend == NULL )
4221 : {
4222 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4223 : }
4224 :
4225 973 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4226 : {
4227 0 : return error;
4228 : }
4229 :
4230 973 : inputBase->gain_fx = gain;
4231 973 : move32();
4232 :
4233 973 : return IVAS_ERR_OK;
4234 : }
4235 :
4236 : /*-------------------------------------------------------------------*
4237 : * IVAS_REND_SetInputLfeMtx()
4238 : *
4239 : *
4240 : *-------------------------------------------------------------------*/
4241 0 : ivas_error IVAS_REND_SetInputLfeMtx_fx(
4242 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4243 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4244 : const IVAS_REND_LfePanMtx_fx *lfePanMtx /* i : LFE panning matrix */
4245 : )
4246 : {
4247 : Word16 i;
4248 : input_base *pInputBase;
4249 : input_mc *pInputMc;
4250 : ivas_error error;
4251 :
4252 : /* Validate function arguments */
4253 0 : IF( hIvasRend == NULL )
4254 : {
4255 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4256 : }
4257 :
4258 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
4259 : {
4260 0 : return error;
4261 : }
4262 :
4263 0 : IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
4264 : {
4265 : /* Custom LFE panning matrix only makes sense with channel-based input */
4266 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4267 : }
4268 0 : pInputMc = (input_mc *) pInputBase;
4269 :
4270 : /* copy LFE panning matrix */
4271 0 : FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; i++ )
4272 : {
4273 0 : Copy32( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS );
4274 : }
4275 :
4276 0 : IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
4277 : {
4278 0 : return error;
4279 : }
4280 :
4281 0 : return IVAS_ERR_OK;
4282 : }
4283 :
4284 : /*-------------------------------------------------------------------*
4285 : * IVAS_REND_SetInputLfePos()
4286 : *
4287 : *
4288 : *-------------------------------------------------------------------*/
4289 :
4290 0 : ivas_error IVAS_REND_SetInputLfePos_fx(
4291 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4292 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4293 : const Word32 inputGain, /* i : Input gain to be applied to the LFE channel(s) Q31 */
4294 : const Word16 outputAzimuth, /* i : Output azimuth position Q0 */
4295 : const Word16 outputElevation /* i : Output elevation position Q0 */
4296 : )
4297 : {
4298 : input_base *pInputBase;
4299 : input_mc *pInputMc;
4300 : ivas_error error;
4301 :
4302 : /* Validate function arguments */
4303 0 : IF( hIvasRend == NULL )
4304 : {
4305 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4306 : }
4307 :
4308 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
4309 : {
4310 0 : return error;
4311 : }
4312 :
4313 0 : IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
4314 : {
4315 : /* Custom LFE routing only makes sense with channel-based input */
4316 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4317 : }
4318 0 : pInputMc = (input_mc *) pInputBase;
4319 :
4320 0 : pInputMc->lfeRouting.pan_lfe = true;
4321 0 : move16();
4322 0 : pInputMc->lfeRouting.lfeInputGain_fx = inputGain; /* Q31 */
4323 0 : move32();
4324 0 : pInputMc->lfeRouting.lfeOutputAzimuth_fx = outputAzimuth; /* Q0 */
4325 0 : move16();
4326 0 : pInputMc->lfeRouting.lfeOutputElevation_fx = outputElevation; /* Q0 */
4327 0 : move16();
4328 :
4329 0 : IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
4330 : {
4331 0 : return error;
4332 : }
4333 :
4334 0 : return IVAS_ERR_OK;
4335 : }
4336 :
4337 : /*-------------------------------------------------------------------*
4338 : * IVAS_REND_RemoveInput()
4339 : *
4340 : *
4341 : *-------------------------------------------------------------------*/
4342 : /* ToDo; unused function */
4343 0 : ivas_error IVAS_REND_RemoveInput(
4344 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4345 : const IVAS_REND_InputId inputId /* i : ID of the input */
4346 : )
4347 : {
4348 : ivas_error error;
4349 : input_base *inputBase;
4350 :
4351 : /* Validate function arguments */
4352 0 : IF( hIvasRend == NULL )
4353 : {
4354 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4355 : }
4356 :
4357 0 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4358 : {
4359 0 : return error;
4360 : }
4361 :
4362 0 : SWITCH( getAudioConfigType( inputBase->inConfig ) )
4363 : {
4364 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
4365 0 : clearInputIsm( (input_ism *) inputBase );
4366 0 : BREAK;
4367 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
4368 0 : clearInputMc( (input_mc *) inputBase );
4369 0 : BREAK;
4370 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
4371 0 : clearInputSba( (input_sba *) inputBase );
4372 0 : BREAK;
4373 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
4374 0 : clearInputMasa( (input_masa *) inputBase );
4375 0 : BREAK;
4376 0 : default:
4377 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4378 : }
4379 :
4380 0 : return IVAS_ERR_OK;
4381 : }
4382 :
4383 :
4384 : /*-------------------------------------------------------------------*
4385 : * IVAS_REND_GetInputNumChannels()
4386 : *
4387 : *
4388 : *-------------------------------------------------------------------*/
4389 630413 : ivas_error IVAS_REND_GetInputNumChannels(
4390 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
4391 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4392 : Word16 *numChannels /* o : number of channels of the input */
4393 : )
4394 : {
4395 : ivas_error error;
4396 : const input_base *pInput;
4397 :
4398 : /* Validate function arguments */
4399 630413 : test();
4400 630413 : IF( hIvasRend == NULL || numChannels == NULL )
4401 : {
4402 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4403 : }
4404 :
4405 630413 : IF( NE_32( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ), IVAS_ERR_OK ) )
4406 : {
4407 0 : return error;
4408 : }
4409 :
4410 630413 : IF( NE_32( ( error = getRendInputNumChannels( pInput, numChannels ) ), IVAS_ERR_OK ) )
4411 : {
4412 0 : return error;
4413 : }
4414 :
4415 630413 : return IVAS_ERR_OK;
4416 : }
4417 :
4418 : /*-------------------------------------------------------------------*
4419 : * IVAS_REND_GetNumAllObjects()
4420 : *
4421 : *
4422 : *-------------------------------------------------------------------*/
4423 426 : ivas_error IVAS_REND_GetNumAllObjects(
4424 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
4425 : Word16 *numChannels /* o : number of all objects */
4426 : )
4427 : {
4428 426 : test();
4429 426 : IF( hIvasRend == NULL || numChannels == NULL )
4430 : {
4431 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4432 : }
4433 :
4434 426 : test();
4435 426 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
4436 : {
4437 1 : *numChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
4438 1 : move16();
4439 : }
4440 :
4441 426 : return IVAS_ERR_OK;
4442 : }
4443 :
4444 :
4445 : /*-------------------------------------------------------------------*
4446 : * IVAS_REND_GetDelay()
4447 : *
4448 : *
4449 : *-------------------------------------------------------------------*/
4450 :
4451 0 : ivas_error IVAS_REND_GetDelay_fx(
4452 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
4453 : Word16 *nSamples, /* o : Renderer delay in samples */
4454 : Word32 *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
4455 : )
4456 : {
4457 : /* TODO tmu : this function only returns the maximum delay across all inputs
4458 : * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform)
4459 : */
4460 : Word16 i;
4461 : Word32 latency_ns;
4462 : Word32 max_latency_ns;
4463 :
4464 0 : Word32 timescale_by_ns[7] = { 0, 17180, 34360, 0, 68719, 0, 103079 };
4465 0 : move32();
4466 0 : move32();
4467 0 : move32();
4468 0 : move32();
4469 0 : move32();
4470 0 : move32();
4471 0 : move32();
4472 :
4473 : /* Validate function arguments */
4474 0 : test();
4475 0 : test();
4476 0 : IF( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
4477 : {
4478 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4479 : }
4480 :
4481 0 : *timeScale = hIvasRend->sampleRateOut;
4482 0 : move32();
4483 0 : assert( *timeScale == 8000 || *timeScale == 16000 || *timeScale == 32000 || *timeScale == 48000 );
4484 0 : *nSamples = 0;
4485 0 : move16();
4486 0 : max_latency_ns = 0;
4487 0 : move32();
4488 :
4489 : /* Compute the maximum delay across all inputs */
4490 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
4491 : {
4492 0 : IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4493 : {
4494 0 : IF( hIvasRend->inputsIsm[i].crendWrapper != NULL )
4495 : {
4496 0 : latency_ns = hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns;
4497 : }
4498 : ELSE
4499 : {
4500 0 : latency_ns = 0;
4501 : }
4502 0 : move32();
4503 :
4504 0 : latency_ns = L_max( latency_ns, hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns );
4505 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4506 : }
4507 : }
4508 :
4509 0 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
4510 : {
4511 0 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4512 : {
4513 0 : IF( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) )
4514 : {
4515 0 : latency_ns = hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns;
4516 : }
4517 : ELSE
4518 : {
4519 0 : latency_ns = 0;
4520 : }
4521 :
4522 0 : move32();
4523 :
4524 0 : latency_ns = L_max( latency_ns, hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns );
4525 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4526 : }
4527 : }
4528 :
4529 0 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
4530 : {
4531 0 : IF( NE_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4532 : {
4533 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
4534 0 : test();
4535 0 : IF( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL )
4536 : #else
4537 : IF( hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL )
4538 : #endif
4539 : {
4540 0 : IF( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV )
4541 : {
4542 0 : latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
4543 0 : move32();
4544 : }
4545 : ELSE
4546 : {
4547 0 : IF( ( hIvasRend->inputsSba[i].crendWrapper != NULL ) )
4548 : {
4549 0 : latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
4550 : }
4551 : ELSE
4552 : {
4553 0 : latency_ns = 0;
4554 : }
4555 0 : move32();
4556 : }
4557 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4558 : }
4559 0 : ELSE IF( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL )
4560 : {
4561 0 : latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
4562 0 : move32();
4563 0 : latency_ns = L_add( latency_ns, IVAS_FB_DEC_DELAY_NS );
4564 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4565 : }
4566 : ELSE
4567 : {
4568 0 : IF( hIvasRend->inputsSba[i].crendWrapper != NULL )
4569 : {
4570 0 : latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
4571 : }
4572 : ELSE
4573 : {
4574 0 : latency_ns = 0;
4575 : }
4576 0 : move32();
4577 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4578 : }
4579 : }
4580 : }
4581 :
4582 0 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
4583 : {
4584 0 : IF( NE_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4585 : {
4586 0 : latency_ns = (Word32) ( IVAS_FB_DEC_DELAY_NS );
4587 0 : move32();
4588 0 : max_latency_ns = L_max( max_latency_ns, latency_ns );
4589 : }
4590 : }
4591 :
4592 : //*nSamples = (Word16) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
4593 0 : Word32 temp = Mpy_32_32( *timeScale, 268436 ); // Q0 + Q31 - Q31 -> Q0, ( 1 / 8000 ) * 2 ^ 31
4594 0 : *nSamples = extract_l( Mpy_32_32_r( max_latency_ns, timescale_by_ns[temp] ) );
4595 0 : move16();
4596 :
4597 0 : return IVAS_ERR_OK;
4598 : }
4599 :
4600 :
4601 : /*-------------------------------------------------------------------*
4602 : * IVAS_REND_FeedInputAudio()
4603 : *
4604 : *
4605 : *-------------------------------------------------------------------*/
4606 :
4607 1877090 : ivas_error IVAS_REND_FeedInputAudio_fx(
4608 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4609 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4610 : const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */
4611 : )
4612 : {
4613 : ivas_error error;
4614 : input_base *inputBase;
4615 : Word16 numInputChannels;
4616 : Word16 cldfb2tdShift;
4617 :
4618 : /* Validate function arguments */
4619 1877090 : test();
4620 1877090 : IF( hIvasRend == NULL || inputAudio.data_fx == NULL )
4621 : {
4622 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4623 : }
4624 :
4625 1877090 : test();
4626 1877090 : cldfb2tdShift = ( inputAudio.config.is_cldfb ) ? 1 : 0;
4627 :
4628 1877090 : IF( inputAudio.config.numSamplesPerChannel <= 0 || ( MAX_BUFFER_LENGTH_PER_CHANNEL < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
4629 : ( ( shl( MAX_BUFFER_LENGTH_PER_CHANNEL, cldfb2tdShift ) ) < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 1 ) )
4630 : {
4631 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
4632 : }
4633 :
4634 1877090 : test();
4635 1877090 : IF( inputAudio.config.numChannels <= 0 || LT_16( MAX_INPUT_CHANNELS, inputAudio.config.numChannels ) )
4636 : {
4637 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4638 : }
4639 :
4640 1877090 : test();
4641 1877090 : move32(); // move added for typecasting
4642 1877090 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
4643 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) &&
4644 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) &&
4645 : 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 ) ) )
4646 : {
4647 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
4648 : }
4649 :
4650 1877090 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4651 : {
4652 0 : return error;
4653 : }
4654 :
4655 1877090 : IF( NE_32( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ), IVAS_ERR_OK ) )
4656 : {
4657 0 : return error;
4658 : }
4659 1877090 : test();
4660 1877090 : test();
4661 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 ) )
4662 : {
4663 150 : numInputChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
4664 150 : move16();
4665 : }
4666 :
4667 1877090 : IF( NE_16( numInputChannels, inputAudio.config.numChannels ) )
4668 : {
4669 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4670 : }
4671 :
4672 1877090 : inputBase->inputBuffer.config = inputAudio.config;
4673 :
4674 1877090 : MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
4675 :
4676 1877090 : inputBase->numNewSamplesPerChannel = shr( inputAudio.config.numSamplesPerChannel, cldfb2tdShift );
4677 1877090 : move32();
4678 :
4679 1877090 : return IVAS_ERR_OK;
4680 : }
4681 :
4682 :
4683 : /*-------------------------------------------------------------------*
4684 : * IVAS_REND_FeedInputObjectMetadata()
4685 : *
4686 : *
4687 : *-------------------------------------------------------------------*/
4688 :
4689 1247500 : ivas_error IVAS_REND_FeedInputObjectMetadata(
4690 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4691 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4692 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
4693 : )
4694 : {
4695 : input_base *inputBase;
4696 : input_ism *inputIsm;
4697 : ivas_error error;
4698 :
4699 : /* Validate function arguments */
4700 1247500 : IF( hIvasRend == NULL )
4701 : {
4702 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4703 : }
4704 :
4705 1247500 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4706 : {
4707 0 : return error;
4708 : }
4709 :
4710 1247500 : IF( NE_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
4711 : {
4712 : /* Object metadata should only be fed for object inputs */
4713 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4714 : }
4715 :
4716 1247500 : inputIsm = (input_ism *) inputBase;
4717 1247500 : inputIsm->previousPos = inputIsm->currentPos;
4718 1247500 : inputIsm->currentPos = objectPosition;
4719 :
4720 1247500 : return IVAS_ERR_OK;
4721 : }
4722 :
4723 :
4724 : /*-------------------------------------------------------------------*
4725 : * IVAS_REND_FeedInputObjectMetadataToOMasa()
4726 : *
4727 : *
4728 : *-------------------------------------------------------------------*/
4729 600 : ivas_error IVAS_REND_FeedInputObjectMetadataToOMasa(
4730 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4731 : const Word16 inputIndex, /* i : Index of the input */
4732 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
4733 : )
4734 : {
4735 : /* Validate function arguments */
4736 600 : IF( hIvasRend == NULL )
4737 : {
4738 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4739 : }
4740 :
4741 : /* Set position to OMasa struct */
4742 600 : hIvasRend->inputsIsm->hOMasa->ism_azimuth_fx[inputIndex] = objectPosition.azimuth_fx;
4743 600 : move32();
4744 600 : hIvasRend->inputsIsm->hOMasa->ism_elevation_fx[inputIndex] = objectPosition.elevation_fx;
4745 600 : move32();
4746 :
4747 600 : return IVAS_ERR_OK;
4748 : }
4749 :
4750 :
4751 : /*-------------------------------------------------------------------*
4752 : * IVAS_REND_FeedInputMasaMetadata()
4753 : *
4754 : *
4755 : *-------------------------------------------------------------------*/
4756 :
4757 7350 : ivas_error IVAS_REND_FeedInputMasaMetadata(
4758 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4759 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4760 : IVAS_MASA_METADATA_HANDLE masaMetadata /* i : MASA metadata frame */
4761 : )
4762 : {
4763 : ivas_error error;
4764 : input_base *inputBase;
4765 : input_masa *inputMasa;
4766 :
4767 : /* Validate function arguments */
4768 7350 : IF( hIvasRend == NULL )
4769 : {
4770 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4771 : }
4772 :
4773 7350 : IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
4774 : {
4775 0 : return error;
4776 : }
4777 :
4778 7350 : IF( NE_32( getAudioConfigType( inputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
4779 : {
4780 : /* MASA metadata should only be fed for MASA inputs */
4781 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4782 : }
4783 :
4784 7350 : inputMasa = (input_masa *) inputBase;
4785 7350 : inputMasa->masaMetadata = *masaMetadata;
4786 7350 : inputMasa->metadataHasBeenFed = true;
4787 7350 : move16();
4788 :
4789 7350 : return IVAS_ERR_OK;
4790 : }
4791 :
4792 :
4793 : /*-------------------------------------------------------------------*
4794 : * IVAS_REND_InitConfig()
4795 : *
4796 : *
4797 : *-------------------------------------------------------------------*/
4798 :
4799 666 : ivas_error IVAS_REND_InitConfig(
4800 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4801 : const AUDIO_CONFIG outAudioConfig /* i : output audioConfig */
4802 : )
4803 : {
4804 : ivas_error error;
4805 : bool rendererConfigEnabled;
4806 :
4807 666 : rendererConfigEnabled = EQ_32( getAudioConfigType( outAudioConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
4808 :
4809 666 : IF( rendererConfigEnabled )
4810 : {
4811 188 : hIvasRend->rendererConfigEnabled = 1;
4812 188 : move16();
4813 : }
4814 : ELSE
4815 : {
4816 478 : hIvasRend->rendererConfigEnabled = 0;
4817 478 : move16();
4818 : }
4819 :
4820 666 : IF( rendererConfigEnabled )
4821 : {
4822 188 : IF( NE_32( ( error = ivas_render_config_open( &( hIvasRend->hRendererConfig ) ) ), IVAS_ERR_OK ) )
4823 : {
4824 0 : return error;
4825 : }
4826 188 : IF( NE_32( ( error = ivas_render_config_init_from_rom_fx( &hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
4827 : {
4828 0 : return error;
4829 : }
4830 : }
4831 : ELSE
4832 : {
4833 478 : hIvasRend->hRendererConfig = NULL;
4834 : }
4835 :
4836 666 : return IVAS_ERR_OK;
4837 : }
4838 :
4839 :
4840 : /*-------------------------------------------------------------------*
4841 : * IVAS_REND_GetRenderConfig()
4842 : *
4843 : *
4844 : *-------------------------------------------------------------------*/
4845 :
4846 0 : Word16 IVAS_REND_GetRenderConfig(
4847 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
4848 : const IVAS_RENDER_CONFIG_HANDLE hRCout /* o : Render configuration handle */
4849 : )
4850 : {
4851 : RENDER_CONFIG_HANDLE hRCin;
4852 :
4853 0 : test();
4854 0 : test();
4855 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL || hRCout == NULL )
4856 : {
4857 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4858 : }
4859 :
4860 0 : hRCin = hIvasRend->hRendererConfig;
4861 : #ifndef FIX_587_DEFAULT_REVERB
4862 : hRCout->roomAcoustics.override = hRCin->roomAcoustics.override;
4863 : #endif
4864 0 : hRCout->roomAcoustics.nBands = hRCin->roomAcoustics.nBands;
4865 0 : hRCout->roomAcoustics.acousticPreDelay_fx = hRCin->roomAcoustics.acousticPreDelay_fx;
4866 0 : hRCout->roomAcoustics.inputPreDelay_fx = hRCin->roomAcoustics.inputPreDelay_fx;
4867 0 : Copy( hRCin->directivity_fx, hRCout->directivity_fx, 3 * MAX_NUM_OBJECTS );
4868 : #ifndef FIX_587_DEFAULT_REVERB
4869 : move16();
4870 : #endif
4871 0 : move16();
4872 0 : move32();
4873 0 : move32();
4874 :
4875 0 : Copy32( hRCin->roomAcoustics.pFc_input_fx, hRCout->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
4876 0 : Copy32( hRCin->roomAcoustics.pAcoustic_rt60_fx, hRCout->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
4877 0 : Copy32( hRCin->roomAcoustics.pAcoustic_dsr_fx, hRCout->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
4878 :
4879 0 : hRCout->split_rend_config.splitRendBitRate = ISAR_MAX_SPLIT_REND_BITRATE;
4880 0 : hRCout->split_rend_config.dof = 3;
4881 0 : hRCout->split_rend_config.hq_mode = 0;
4882 0 : hRCout->split_rend_config.codec_delay_ms = 0;
4883 0 : hRCout->split_rend_config.isar_frame_size_ms = 20;
4884 0 : hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
4885 0 : hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
4886 0 : hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
4887 0 : hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
4888 0 : hRCout->split_rend_config.lc3plus_highres = 0;
4889 :
4890 0 : hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er;
4891 0 : hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
4892 0 : move16();
4893 0 : move32();
4894 :
4895 0 : return IVAS_ERR_OK;
4896 : }
4897 :
4898 :
4899 : /*-------------------------------------------------------------------*
4900 : * IVAS_REND_FeedRenderConfig()
4901 : *
4902 : *
4903 : *-------------------------------------------------------------------*/
4904 :
4905 0 : Word16 IVAS_REND_FeedRenderConfig(
4906 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
4907 : const IVAS_RENDER_CONFIG_DATA renderConfig /* i : Render configuration struct */
4908 : )
4909 : {
4910 : RENDER_CONFIG_HANDLE hRenderConfig;
4911 : #ifdef FIX_1053_REVERB_RECONFIGURATION
4912 : UWord16 i;
4913 : input_ism *pIsmInput;
4914 : input_masa *pMasaInput;
4915 : input_mc *pMcInput;
4916 : input_sba *pSbaInput;
4917 : ivas_error error;
4918 : #else
4919 : ivas_error error;
4920 : #endif
4921 :
4922 0 : test();
4923 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
4924 : {
4925 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4926 : }
4927 0 : hRenderConfig = hIvasRend->hRendererConfig;
4928 :
4929 : #ifndef FIX_587_DEFAULT_REVERB
4930 : hRenderConfig->roomAcoustics.override = renderConfig.roomAcoustics.override;
4931 : move16();
4932 : #endif
4933 0 : hRenderConfig->roomAcoustics.nBands = renderConfig.roomAcoustics.nBands;
4934 0 : move16();
4935 0 : hRenderConfig->roomAcoustics.acousticPreDelay_fx = renderConfig.roomAcoustics.acousticPreDelay_fx;
4936 0 : move32();
4937 0 : hRenderConfig->roomAcoustics.inputPreDelay_fx = renderConfig.roomAcoustics.inputPreDelay_fx;
4938 0 : move32();
4939 0 : Copy32( renderConfig.roomAcoustics.pFc_input_fx, hRenderConfig->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
4940 0 : Copy32( renderConfig.roomAcoustics.pAcoustic_rt60_fx, hRenderConfig->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
4941 0 : Copy32( renderConfig.roomAcoustics.pAcoustic_dsr_fx, hRenderConfig->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
4942 0 : Copy( renderConfig.directivity_fx, hRenderConfig->directivity_fx, 3 * MAX_NUM_OBJECTS );
4943 :
4944 0 : hRenderConfig->roomAcoustics.use_er = 0;
4945 0 : move16();
4946 0 : IF( EQ_16( renderConfig.roomAcoustics.use_er, 1 ) )
4947 : {
4948 0 : hRenderConfig->roomAcoustics.use_er = renderConfig.roomAcoustics.use_er;
4949 0 : move16();
4950 0 : hRenderConfig->roomAcoustics.lowComplexity = renderConfig.roomAcoustics.lowComplexity;
4951 0 : move32();
4952 0 : hRenderConfig->roomAcoustics.dimensions = renderConfig.roomAcoustics.dimensions;
4953 0 : hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.roomAcoustics.ListenerOrigin;
4954 :
4955 0 : Copy32( renderConfig.roomAcoustics.AbsCoeff_fx, hRenderConfig->roomAcoustics.AbsCoeff_fx, IVAS_ROOM_ABS_COEFF );
4956 : }
4957 :
4958 : #ifdef FIX_1053_REVERB_RECONFIGURATION
4959 : /* Re-initialize reverb instance if already available */
4960 : /* ISM inputs */
4961 0 : for ( i = 0, pIsmInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pIsmInput )
4962 : {
4963 0 : IF( EQ_32( pIsmInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4964 : {
4965 : /* Skip inactive inputs */
4966 0 : continue;
4967 : }
4968 0 : if ( pIsmInput->hReverb != NULL )
4969 : {
4970 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pIsmInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
4971 : {
4972 0 : return error;
4973 : }
4974 : }
4975 0 : if ( pIsmInput->crendWrapper != NULL && pIsmInput->crendWrapper->hCrend[0] != NULL )
4976 : {
4977 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 ) )
4978 : {
4979 0 : return error;
4980 : }
4981 : }
4982 : }
4983 :
4984 : /* MASA inputs */
4985 0 : for ( i = 0, pMasaInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pMasaInput )
4986 : {
4987 0 : IF( EQ_32( pMasaInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
4988 : {
4989 : /* Skip inactive inputs */
4990 0 : continue;
4991 : }
4992 :
4993 0 : if ( pMasaInput->hMasaExtRend != NULL )
4994 : {
4995 0 : if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
4996 : {
4997 0 : ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
4998 : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
4999 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 ) )
5000 : #else
5001 : 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 ) )
5002 : #endif
5003 : {
5004 0 : return error;
5005 : }
5006 : }
5007 0 : if ( pMasaInput->hMasaExtRend->hReverb != NULL )
5008 : {
5009 0 : ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hReverb );
5010 : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
5011 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 ) )
5012 : #else
5013 : 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 ) )
5014 : #endif
5015 : {
5016 0 : return error;
5017 : }
5018 : }
5019 : }
5020 : }
5021 :
5022 : /* Multi-channel inputs */
5023 0 : for ( i = 0, pMcInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pMcInput )
5024 : {
5025 0 : IF( EQ_32( pMcInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5026 : {
5027 : /* Skip inactive inputs */
5028 0 : continue;
5029 : }
5030 :
5031 0 : if ( pMcInput->hReverb != NULL )
5032 : {
5033 0 : IF( NE_32( ( error = ivas_reverb_open_fx( &pMcInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
5034 : {
5035 0 : return error;
5036 : }
5037 : }
5038 0 : if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
5039 : {
5040 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 ) )
5041 : {
5042 0 : return error;
5043 : }
5044 : }
5045 : }
5046 :
5047 : /* SBA inputs */
5048 0 : for ( i = 0, pSbaInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pSbaInput )
5049 : {
5050 0 : IF( EQ_32( pSbaInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5051 : {
5052 : /* Skip inactive inputs */
5053 0 : continue;
5054 : }
5055 0 : if ( pSbaInput->crendWrapper != NULL && pSbaInput->crendWrapper->hCrend[0] != NULL && pSbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
5056 : {
5057 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 ) )
5058 : {
5059 0 : return error;
5060 : }
5061 : }
5062 : }
5063 : #endif
5064 :
5065 0 : hRenderConfig->split_rend_config = renderConfig.split_rend_config;
5066 : /* Overwrite any pose correction settings if 0 DOF (no pose correction) was selected */
5067 0 : IF( EQ_16( hRenderConfig->split_rend_config.dof, 0 ) )
5068 : {
5069 0 : hRenderConfig->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
5070 : }
5071 :
5072 0 : hRenderConfig->split_rend_config.codec = renderConfig.split_rend_config.codec;
5073 :
5074 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 )
5075 : {
5076 0 : return error;
5077 : }
5078 :
5079 : /* Must re-initialize split rendering config in case renderer config is updated after adding renderer inputs */
5080 : /* if its not initialized yet then no need to re-initialize, initialization will happen while adding inputs*/
5081 0 : IF( hIvasRend->splitRendEncBuffer.data_fx != NULL && hIvasRend->hRendererConfig != NULL )
5082 : {
5083 : Word16 cldfb_in_flag;
5084 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
5085 0 : IF( hIvasRend->splitRendWrapper != NULL )
5086 : {
5087 0 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
5088 0 : free( hIvasRend->splitRendWrapper );
5089 0 : hIvasRend->splitRendWrapper = NULL;
5090 : }
5091 :
5092 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 )
5093 : {
5094 0 : return error;
5095 : }
5096 : }
5097 :
5098 0 : return IVAS_ERR_OK;
5099 : }
5100 :
5101 : /*-------------------------------------------------------------------*
5102 : * IVAS_REND_SetHeadRotation()
5103 : *
5104 : *
5105 : *-------------------------------------------------------------------*/
5106 288060 : ivas_error IVAS_REND_SetHeadRotation(
5107 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5108 : const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */
5109 : const IVAS_VECTOR3 Pos, /* i : listener positions for next rendering call */
5110 : const ISAR_SPLIT_REND_ROT_AXIS rot_axis, /* i : external control for rotation axis for split rendering */
5111 : const Word16 sf_idx /* i : subframe index */
5112 : )
5113 : {
5114 : Word16 i;
5115 : IVAS_QUATERNION rotQuat;
5116 : ivas_error error;
5117 :
5118 : /* Validate function arguments */
5119 288060 : IF( hIvasRend == NULL )
5120 : {
5121 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5122 : }
5123 :
5124 288060 : IF( NE_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
5125 : {
5126 : /* Head rotation can be set only with binaural output */
5127 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
5128 : }
5129 :
5130 288060 : hIvasRend->headRotData.headRotEnabled = 1;
5131 288060 : move16();
5132 :
5133 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
5134 576120 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
5135 : {
5136 288060 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5137 : {
5138 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 ) )
5139 : {
5140 0 : return error;
5141 : }
5142 : }
5143 : }
5144 :
5145 : /* check for Euler angle signaling */
5146 288060 : IF( EQ_32( headRot.w_fx, L_negate( 12582912 ) ) && EQ_16( headRot.q_fact, Q22 ) )
5147 : {
5148 0 : Euler2Quat_fx( deg2rad_fx( headRot.x_fx ), deg2rad_fx( headRot.y_fx ), deg2rad_fx( headRot.z_fx ), &rotQuat );
5149 0 : modify_Quat_q_fx( &rotQuat, &rotQuat, Q29 );
5150 : }
5151 : ELSE
5152 : {
5153 288060 : rotQuat = headRot;
5154 : }
5155 :
5156 288060 : Word32 updateRate_fx = 1677721600; // value is 200 in Q23
5157 288060 : rotQuat.w_fx = L_shl( rotQuat.w_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5158 288060 : rotQuat.x_fx = L_shl( rotQuat.x_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5159 288060 : rotQuat.y_fx = L_shl( rotQuat.y_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5160 288060 : rotQuat.z_fx = L_shl( rotQuat.z_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
5161 :
5162 288060 : move32();
5163 288060 : move32();
5164 288060 : move32();
5165 288060 : move32();
5166 :
5167 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5168 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5169 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5170 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) ); /* Q29 */
5171 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5172 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5173 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5174 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
5175 :
5176 288060 : move32();
5177 288060 : move32();
5178 288060 : move32();
5179 288060 : move32();
5180 288060 : move32();
5181 288060 : move32();
5182 288060 : move32();
5183 288060 : move32();
5184 :
5185 288060 : hIvasRend->headRotData.hOrientationTracker->refRot.q_fact = Q29;
5186 288060 : hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact = Q29;
5187 288060 : move16();
5188 288060 : move16();
5189 288060 : rotQuat.q_fact = Q29;
5190 :
5191 288060 : move16();
5192 288060 : IF( NE_32( ( error = ivas_orient_trk_Process_fx( hIvasRend->headRotData.hOrientationTracker, rotQuat, updateRate_fx, &hIvasRend->headRotData.headPositions[sf_idx] ) ), IVAS_ERR_OK ) )
5193 : {
5194 0 : return error;
5195 : }
5196 :
5197 288060 : hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
5198 :
5199 288060 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
5200 :
5201 288060 : return IVAS_ERR_OK;
5202 : }
5203 :
5204 : /*-------------------------------------------------------------------*
5205 : * IVAS_REND_DisableHeadRotation()
5206 : *
5207 : *
5208 : *-------------------------------------------------------------------*/
5209 946116 : ivas_error IVAS_REND_DisableHeadRotation(
5210 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
5211 : )
5212 : {
5213 : Word16 i;
5214 : ivas_error error;
5215 :
5216 : /* Validate function arguments */
5217 946116 : IF( hIvasRend == NULL )
5218 : {
5219 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5220 : }
5221 :
5222 946116 : hIvasRend->headRotData.headRotEnabled = 0;
5223 946116 : move32();
5224 :
5225 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
5226 946116 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
5227 : {
5228 360048 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
5229 : {
5230 180024 : IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
5231 : {
5232 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 ) )
5233 : {
5234 :
5235 0 : return error;
5236 : }
5237 : }
5238 : }
5239 : }
5240 :
5241 946116 : return IVAS_ERR_OK;
5242 : }
5243 :
5244 :
5245 : /*-------------------------------------------------------------------*
5246 : * IVAS_REND_SetSplitRendBFI()
5247 : *
5248 : *
5249 : *-------------------------------------------------------------------*/
5250 :
5251 0 : ivas_error IVAS_REND_SetSplitRendBFI(
5252 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5253 : const Word16 bfi /* i : Bad Frame Indicator */
5254 : )
5255 : {
5256 0 : hIvasRend->splitRendBFI = bfi;
5257 :
5258 0 : return IVAS_ERR_OK;
5259 : }
5260 :
5261 :
5262 : /*-------------------------------------------------------------------*
5263 : * IVAS_REND_SetOrientationTrackingMode()
5264 : *
5265 : *
5266 : *-------------------------------------------------------------------*/
5267 :
5268 666 : ivas_error IVAS_REND_SetOrientationTrackingMode(
5269 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5270 : const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i : Head orientation tracking type */
5271 : )
5272 : {
5273 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
5274 666 : if ( hIvasRend->headRotData.headRotEnabled == 0 )
5275 : {
5276 572 : return IVAS_ERR_OK;
5277 : }
5278 : #endif
5279 :
5280 94 : return ivas_orient_trk_SetTrackingType_fx( hIvasRend->headRotData.hOrientationTracker, orientation_tracking );
5281 : }
5282 :
5283 :
5284 : /*-------------------------------------------------------------------*
5285 : * IVAS_REND_SetReferenceRotation()
5286 : *
5287 : *
5288 : *-------------------------------------------------------------------*/
5289 :
5290 0 : ivas_error IVAS_REND_SetReferenceRotation(
5291 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5292 : const IVAS_QUATERNION refRot /* i : Reference rotation */
5293 : )
5294 : {
5295 : ivas_error error;
5296 :
5297 : /* Validate function arguments */
5298 0 : IF( hIvasRend == NULL )
5299 : {
5300 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5301 : }
5302 :
5303 0 : error = ivas_orient_trk_SetReferenceRotation_fx( hIvasRend->headRotData.hOrientationTracker, refRot );
5304 :
5305 0 : IF( NE_32( error, IVAS_ERR_OK ) )
5306 : {
5307 :
5308 0 : return error;
5309 : }
5310 0 : return IVAS_ERR_OK;
5311 : }
5312 :
5313 :
5314 : /*-------------------------------------------------------------------*
5315 : * IVAS_REND_GetMainOrientation()
5316 : *
5317 : *
5318 : *-------------------------------------------------------------------*/
5319 :
5320 :
5321 : /*-------------------------------------------------------------------*
5322 : * IVAS_REND_GetTrackedRotation()
5323 : *
5324 : *
5325 : *-------------------------------------------------------------------*/
5326 :
5327 :
5328 : /*---------------------------------------------------------------------*
5329 : * IVAS_REND_SetReferenceVector( )
5330 : *
5331 : * Sets a reference vector spanning from listenerPos to refPos. Only
5332 : * available in OTR_TRACKING_REF_VEC and OTR_TRACKING_REF_VEC_LEV modes.
5333 : *---------------------------------------------------------------------*/
5334 :
5335 0 : ivas_error IVAS_REND_SetReferenceVector(
5336 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5337 : const IVAS_VECTOR3 listenerPos, /* i : Listener position */
5338 : const IVAS_VECTOR3 refPos /* i : Reference position */
5339 : )
5340 : {
5341 0 : test();
5342 0 : IF( hIvasRend == NULL || hIvasRend->headRotData.hOrientationTracker == NULL )
5343 : {
5344 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5345 : }
5346 :
5347 0 : return ivas_orient_trk_SetReferenceVector_fx( hIvasRend->headRotData.hOrientationTracker, listenerPos, refPos );
5348 : }
5349 :
5350 :
5351 : /*---------------------------------------------------------------------*
5352 : * IVAS_REND_SetExternalOrientation()
5353 : *
5354 : *
5355 : *---------------------------------------------------------------------*/
5356 :
5357 0 : ivas_error IVAS_REND_SetExternalOrientation(
5358 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5359 : IVAS_QUATERNION *orientation, /* i : external orientation data */
5360 : Word8 enableHeadRotation, /* i : flag to enable head rotation for this frame */
5361 : Word8 enableExternalOrientation, /* i : flag to enable external orientation for this frame */
5362 : Word8 enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */
5363 : Word16 numFramesToTargetOrientation, /* i : number of frames until target orientation is reached */
5364 : const Word16 sf_idx /* i : subframe index */
5365 : )
5366 : {
5367 : /* Validate function arguments */
5368 0 : test();
5369 0 : IF( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL )
5370 : {
5371 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5372 : }
5373 :
5374 0 : IF( orientation == NULL )
5375 : {
5376 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = 0;
5377 0 : move16();
5378 : }
5379 : ELSE
5380 : {
5381 0 : QuaternionInverse_fx( *orientation, &hIvasRend->hExternalOrientationData->Quaternions[sf_idx] );
5382 :
5383 0 : hIvasRend->hExternalOrientationData->enableHeadRotation[sf_idx] = enableHeadRotation;
5384 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = enableExternalOrientation;
5385 0 : hIvasRend->hExternalOrientationData->enableRotationInterpolation[sf_idx] = enableRotationInterpolation;
5386 0 : hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[sf_idx] = numFramesToTargetOrientation;
5387 0 : move16();
5388 0 : move16();
5389 0 : move16();
5390 0 : move16();
5391 : }
5392 :
5393 0 : return IVAS_ERR_OK;
5394 : }
5395 :
5396 :
5397 : /*---------------------------------------------------------------------*
5398 : * IVAS_REND_CombineHeadAndExternalOrientation()
5399 : *
5400 : *
5401 : *---------------------------------------------------------------------*/
5402 :
5403 1126140 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
5404 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
5405 : )
5406 : {
5407 1126140 : IF( hIvasRend == NULL )
5408 : {
5409 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5410 : }
5411 1126140 : ivas_error error = combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
5412 :
5413 1126140 : return error;
5414 : }
5415 :
5416 :
5417 : /*---------------------------------------------------------------------*
5418 : * IVAS_REND_GetCombinedOrientation()
5419 : *
5420 : *
5421 : *---------------------------------------------------------------------*/
5422 :
5423 :
5424 : /*-------------------------------------------------------------------*
5425 : * Local functions
5426 : *-------------------------------------------------------------------*/
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 : /* Take one channel from input buffer and copy it to each channel
5433 : in output buffer, with different gain applied per output channel.
5434 : This function takes 2 gain vectors - one for the beginning and one
5435 : for the end of the buffer. Gain values are lineraly interpolated
5436 : for all samples in between. */
5437 4992179 : static void renderBufferChannelLerp_fx(
5438 : const IVAS_REND_AudioBuffer inAudio,
5439 : const Word32 inChannelIdx,
5440 : const Word32 *const gainsCurrent, /* Q31 */
5441 : const Word32 *const gainsPrev, /* Q31 */
5442 : IVAS_REND_AudioBuffer outAudio )
5443 : {
5444 : const Word32 *inSmpl;
5445 : Word32 *outSmpl;
5446 : Word32 fadeIn;
5447 : Word32 fadeOut;
5448 : Word32 i;
5449 : const Word32 *lastInSmpl;
5450 : Word16 outChnlIdx;
5451 : Word32 currentGain; /* Q31 */
5452 : Word32 previousGain; /* Q31 */
5453 :
5454 : /* Pointer to behind last input sample */
5455 4992179 : lastInSmpl = getSmplPtr_fx( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
5456 :
5457 47433367 : FOR( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
5458 : {
5459 42441188 : currentGain = gainsCurrent[outChnlIdx];
5460 42441188 : move32();
5461 42441188 : if ( gainsPrev == NULL )
5462 : {
5463 39044000 : previousGain = 0;
5464 39044000 : move32();
5465 : }
5466 : else
5467 : {
5468 3397188 : previousGain = gainsPrev[outChnlIdx];
5469 3397188 : move32();
5470 : }
5471 :
5472 : /* Process current output channel only if applying non-zero gains */
5473 42441188 : test();
5474 42441188 : test();
5475 42441188 : IF( GT_32( L_abs( currentGain ), EPSILON_FX ) || ( gainsPrev != NULL && GT_32( L_abs( previousGain ), EPSILON_FX ) ) )
5476 : {
5477 : /* Reset input pointer to the beginning of input channel */
5478 23944469 : inSmpl = getSmplPtr_fx( inAudio, inChannelIdx, 0 );
5479 :
5480 : /* Set output pointer to first output channel sample */
5481 23944469 : outSmpl = getSmplPtr_fx( outAudio, outChnlIdx, 0 );
5482 :
5483 23944469 : test();
5484 23944469 : IF( gainsPrev == NULL || LE_32( L_abs( L_sub( L_shr( previousGain, 1 ), L_shr( currentGain, 1 ) ) ), EPSILON_FX ) )
5485 : {
5486 : /* If no interpolation from previous frame, apply current gain */
5487 : DO
5488 : {
5489 8798392080 : *outSmpl = L_add( Mpy_32_32( currentGain, ( *inSmpl ) ), *outSmpl );
5490 8798392080 : move32();
5491 8798392080 : ++outSmpl;
5492 8798392080 : ++inSmpl;
5493 : }
5494 8798392080 : WHILE( inSmpl != lastInSmpl );
5495 : }
5496 : ELSE
5497 : {
5498 1996136 : i = 0;
5499 1996136 : Word32 tmp = Q31_BY_SUB_FRAME_240;
5500 1996136 : Word32 tmp1 = 239; /* L_SUBFRAME_48k - 1 */
5501 1996136 : move32();
5502 1996136 : move32();
5503 1996136 : move32();
5504 1996136 : SWITCH( outAudio.config.numSamplesPerChannel )
5505 : {
5506 1051037 : case NUM_SAMPLES_960:
5507 1051037 : tmp = Q31_BY_NUM_SAMPLES_960;
5508 1051037 : tmp1 = 959; /* NUM_SAMPLES_960 - 1 */
5509 1051037 : move32();
5510 1051037 : move32();
5511 1051037 : BREAK;
5512 0 : case NUM_SAMPLES_720:
5513 0 : tmp = Q31_BY_NUM_SAMPLES_720;
5514 0 : tmp1 = 719; /* NUM_SAMPLES_720 - 1 */
5515 0 : move32();
5516 0 : move32();
5517 0 : BREAK;
5518 0 : case NUM_SAMPLES_640:
5519 0 : tmp = Q31_BY_NUM_SAMPLES_640;
5520 0 : tmp1 = 639; /* NUM_SAMPLES_640 - 1 */
5521 0 : move32();
5522 0 : move32();
5523 0 : BREAK;
5524 0 : case NUM_SAMPLES_320:
5525 0 : tmp = Q31_BY_NUM_SAMPLES_320;
5526 0 : tmp1 = 319; /* NUM_SAMPLES_320 - 1 */
5527 0 : move32();
5528 0 : move32();
5529 0 : BREAK;
5530 0 : case L_SUBFRAME_32k:
5531 0 : tmp = Q31_BY_NUM_SAMPLES_160;
5532 0 : tmp1 = 159; /* NUM_SAMPLES_160 - 1 */
5533 0 : move32();
5534 0 : move32();
5535 0 : BREAK;
5536 945099 : case L_SUBFRAME_48k:
5537 945099 : tmp = Q31_BY_SUB_FRAME_240;
5538 945099 : tmp1 = 239; /* L_SUBFRAME_48k - 1 */
5539 945099 : move32();
5540 945099 : move32();
5541 945099 : BREAK;
5542 0 : case L_SUBFRAME_16k:
5543 0 : tmp = Q31_BY_SUB_FRAME_80;
5544 0 : tmp1 = 79; /* L_SUBFRAME_16k - 1 */
5545 0 : move32();
5546 0 : move32();
5547 0 : BREAK;
5548 0 : case L_SUBFRAME_8k:
5549 0 : tmp = Q31_BY_SUB_FRAME_40;
5550 0 : tmp1 = 39; /* L_SUBFRAME_8k - 1 */
5551 0 : move32();
5552 0 : move32();
5553 0 : BREAK;
5554 0 : default:
5555 0 : BREAK;
5556 : }
5557 : /* Otherwise use weighted average between previous and current gain */
5558 1233823144 : DO
5559 : {
5560 1235819280 : IF( EQ_32( i, tmp1 ) )
5561 : {
5562 1996136 : fadeIn = ONE_IN_Q31;
5563 1996136 : move32();
5564 : }
5565 : ELSE
5566 : {
5567 1233823144 : fadeIn = UL_Mpy_32_32( i, tmp );
5568 : }
5569 1235819280 : fadeOut = L_sub( ONE_IN_Q31, fadeIn );
5570 :
5571 1235819280 : *outSmpl = L_add( Mpy_32_32( L_add( Mpy_32_32( fadeIn, currentGain ), Mpy_32_32( fadeOut, previousGain ) ), ( *inSmpl ) ), *outSmpl );
5572 1235819280 : move32();
5573 1235819280 : ++outSmpl;
5574 1235819280 : ++inSmpl;
5575 1235819280 : ++i;
5576 : }
5577 1235819280 : WHILE( inSmpl != lastInSmpl );
5578 : }
5579 : }
5580 : }
5581 :
5582 4992179 : return;
5583 : }
5584 :
5585 :
5586 : /* Take one channel from input buffer and copy it to each channel
5587 : in output buffer, with different gain applied per output channel */
5588 4044679 : static void renderBufferChannel_fx(
5589 : const IVAS_REND_AudioBuffer inAudio,
5590 : const Word32 inChannelIdx,
5591 : const Word32 *const outputGains, /* Q31 */
5592 : IVAS_REND_AudioBuffer outAudio )
5593 : {
5594 4044679 : renderBufferChannelLerp_fx( inAudio, inChannelIdx, outputGains, NULL, outAudio );
5595 :
5596 4044679 : return;
5597 : }
5598 :
5599 70522 : static ivas_error chooseCrossfade_fx(
5600 : const IVAS_REND_HeadRotData *headRotData,
5601 : const Word32 **pCrossfade /* Q31 */ )
5602 : {
5603 70522 : *pCrossfade = headRotData->crossfade_fx;
5604 :
5605 70522 : return IVAS_ERR_OK;
5606 : }
5607 :
5608 :
5609 25504 : static ivas_error rotateFrameMc_fx(
5610 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
5611 : AUDIO_CONFIG inConfig, /* i : Input Audio config */
5612 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs, /* i : Input Custom LS setup */
5613 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
5614 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
5615 : rotation_gains_Word32 gains_prev, /* i/o: Previous frame rotation gains */
5616 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
5617 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
5618 : )
5619 : {
5620 : Word16 i;
5621 : Word16 j;
5622 : const Word32 *crossfade; /* Q31 */
5623 : Word16 num_subframes;
5624 : Word16 subframe_idx, subframe_len;
5625 : Word32 azimuth_fx, elevation_fx; /* Q22 */
5626 : Word16 is_planar_setup, lfe_idx;
5627 : Word16 nchan;
5628 : Word16 ch_in, ch_out;
5629 : Word16 ch_in_woLFE, ch_out_woLFE;
5630 25504 : Word32 *readPtr, *writePtr = NULL;
5631 : const Word32 *ls_azimuth, *ls_elevation;
5632 : rotation_matrix_fx Rmat_fx;
5633 : rotation_gains_Word32 gains;
5634 : Word32 tmp_gains[MAX_INPUT_CHANNELS]; /* Q30 */
5635 : ivas_error error;
5636 :
5637 25504 : push_wmops( "rotateFrameMc_fx" );
5638 25504 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
5639 : {
5640 0 : return error;
5641 : }
5642 25504 : IF( ( hCombinedOrientationData != NULL ) )
5643 : {
5644 25504 : num_subframes = ( *hCombinedOrientationData )->num_subframes;
5645 : }
5646 : ELSE
5647 : {
5648 0 : num_subframes = MAX_PARAM_SPATIAL_SUBFRAMES;
5649 : }
5650 25504 : move16();
5651 :
5652 25504 : IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
5653 : {
5654 12500 : IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ), IVAS_ERR_OK ) )
5655 : {
5656 0 : return error;
5657 : }
5658 : }
5659 : ELSE
5660 : {
5661 13004 : nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe );
5662 : }
5663 :
5664 25504 : IF( NE_32( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ), IVAS_ERR_OK ) )
5665 : {
5666 0 : return error;
5667 : }
5668 :
5669 : /* initialize gains to passthrough */
5670 319068 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
5671 : {
5672 293564 : set32_fx( gains[ch_in], 0, nchan );
5673 293564 : gains[ch_in][ch_in] = ONE_IN_Q30;
5674 293564 : move32();
5675 : }
5676 :
5677 : /* subframe loop */
5678 : Word16 tmp_e;
5679 25504 : Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e );
5680 25504 : tmp = shr( tmp, negate( add( 1, tmp_e ) ) );
5681 25504 : subframe_len = tmp;
5682 25504 : move16();
5683 :
5684 66314 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5685 : {
5686 163240 : FOR( i = 0; i < 3; i++ )
5687 : {
5688 122430 : IF( hCombinedOrientationData != NULL )
5689 : {
5690 489720 : FOR( j = 0; j < 3; j++ )
5691 : {
5692 367290 : Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
5693 367290 : move32();
5694 : }
5695 : }
5696 : ELSE
5697 : {
5698 : /* Set to identity */
5699 0 : set32_fx( Rmat_fx[i], 0, 3 );
5700 0 : Rmat_fx[i][i] = ONE_IN_Q30;
5701 0 : move32();
5702 : }
5703 : }
5704 :
5705 510570 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
5706 : {
5707 : /* skip LFE */
5708 469760 : IF( EQ_16( ch_in, lfe_idx ) )
5709 : {
5710 20000 : CONTINUE;
5711 : }
5712 :
5713 : /* input channel index without LFE */
5714 449760 : test();
5715 449760 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_in, lfe_idx ) ) )
5716 : {
5717 85600 : ch_in_woLFE = sub( ch_in, 1 );
5718 : }
5719 : ELSE
5720 : {
5721 364160 : ch_in_woLFE = ch_in;
5722 364160 : move16();
5723 : }
5724 :
5725 :
5726 : /* gains for current subframe rotation */
5727 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 );
5728 :
5729 449760 : test();
5730 449760 : test();
5731 449760 : IF( hEFAPdata != NULL && ( NE_32( ls_azimuth[ch_in_woLFE], azimuth_fx ) || NE_32( ls_elevation[ch_in_woLFE], elevation_fx ) ) )
5732 : {
5733 144730 : efap_determine_gains_fx( hEFAPdata, tmp_gains, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
5734 :
5735 1444790 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
5736 : {
5737 : /* skip LFE */
5738 1300060 : IF( EQ_16( ch_out, lfe_idx ) )
5739 : {
5740 144730 : CONTINUE;
5741 : }
5742 :
5743 : /* output channel index without LFE */
5744 1155330 : test();
5745 1155330 : IF( ( lfe_idx > 0 ) && ( GE_16( ch_out, lfe_idx ) ) )
5746 : {
5747 721140 : ch_out_woLFE = sub( ch_out, 1 );
5748 : }
5749 : ELSE
5750 : {
5751 434190 : ch_out_woLFE = ch_out;
5752 434190 : move16();
5753 : }
5754 :
5755 1155330 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
5756 1155330 : move32();
5757 : }
5758 : }
5759 : }
5760 :
5761 : /* apply panning gains by mtx multiplication */
5762 510570 : FOR( ch_out = 0; ch_out < nchan; ch_out++ )
5763 : {
5764 6541120 : FOR( ch_in = 0; ch_in < nchan; ch_in++ )
5765 : {
5766 6071360 : writePtr = getSmplPtr_fx( outAudio, ch_out, imult1616( subframe_idx, subframe_len ) ); /* Qx */
5767 6071360 : readPtr = getSmplPtr_fx( inAudio, ch_in, imult1616( subframe_idx, subframe_len ) ); /* Qx */
5768 : /* crossfade with previous rotation gains */
5769 1463197760 : FOR( i = 0; i < subframe_len; i++ )
5770 : {
5771 1457126400 : *writePtr =
5772 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] ) ),
5773 1457126400 : Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); /* Qx - 1 */
5774 1457126400 : move32();
5775 1457126400 : readPtr++;
5776 1457126400 : writePtr++;
5777 : }
5778 : }
5779 : }
5780 :
5781 : /* move gains to gains_prev */
5782 510570 : FOR( i = 0; i < nchan; i++ )
5783 : {
5784 469760 : MVR2R_WORD32( gains[i], gains_prev[i], nchan );
5785 : }
5786 : }
5787 :
5788 25504 : pop_wmops();
5789 25504 : return IVAS_ERR_OK;
5790 : }
5791 :
5792 :
5793 45018 : static ivas_error rotateFrameSba_fx(
5794 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
5795 : const AUDIO_CONFIG inConfig, /* i : Input Audio config */
5796 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
5797 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
5798 : Word16 gains_prev[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS], /* i/o: Previous frame rotation gains Q14 */
5799 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
5800 : )
5801 : {
5802 : Word16 i, l, n, m;
5803 : Word16 m1, m2;
5804 : Word16 shd_rot_max_order;
5805 : const Word32 *crossfade; /* Q31 */
5806 : Word16 num_subframes;
5807 : Word16 subframe_idx, subframe_len;
5808 : Word32 *writePtr;
5809 : Word32 tmpRot[2 * HEADROT_ORDER + 1];
5810 : Word16 gains[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; /* Q14 */
5811 : Word32 temp;
5812 : Word32 Rmat[3][3]; /* Q30 */
5813 : ivas_error error;
5814 : Word16 idx, exp;
5815 : Word32 cf, oneminuscf; /* Q31 */
5816 : Word32 val;
5817 :
5818 45018 : push_wmops( "rotateFrameSba" );
5819 :
5820 45018 : IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
5821 : {
5822 0 : return error;
5823 : }
5824 45018 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
5825 45018 : move16();
5826 :
5827 45018 : IF( NE_32( ( error = getAmbisonicsOrder_fx( inConfig, &shd_rot_max_order ) ), IVAS_ERR_OK ) )
5828 : {
5829 0 : return error;
5830 : }
5831 :
5832 : // subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
5833 45018 : subframe_len = BASOP_Util_Divide1616_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &exp );
5834 45018 : subframe_len = shr( subframe_len, sub( 15, exp ) );
5835 117063 : FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5836 : {
5837 : /* initialize rotation matrices with zeros */
5838 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5839 : {
5840 1152720 : set16_fx( gains[i], 0, HEADROT_SHMAT_DIM );
5841 : }
5842 :
5843 288180 : FOR( i = 0; i < 3; i++ )
5844 : {
5845 216135 : IF( hCombinedOrientationData != NULL )
5846 : {
5847 864540 : FOR( l = 0; l < 3; l++ )
5848 : {
5849 648405 : Rmat[i][l] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][l]; /* Q30 */
5850 648405 : move32();
5851 : }
5852 : }
5853 : ELSE
5854 : {
5855 : /* Set to identity */
5856 0 : set32_fx( Rmat[i], 0, 3 );
5857 0 : Rmat[i][i] = ONE_IN_Q30;
5858 0 : move32();
5859 : }
5860 : }
5861 : /* calculate ambisonics rotation matrices for the previous and current frames */
5862 72045 : SHrotmatgen_fx( gains, Rmat, shd_rot_max_order );
5863 :
5864 : #ifdef DEBUGGING
5865 : dbgwrite_txt( (const float *) ( gains[0] ), HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_code_gains.txt", NULL );
5866 : dbgwrite_txt( (const float *) ( Rmat[0] ), 3 * 3, "Fixed_code_Rmat.txt", NULL );
5867 : #endif
5868 17362845 : FOR( i = 0; i < subframe_len; i++ )
5869 : {
5870 17290800 : idx = add( imult1616( subframe_idx, subframe_len ), i );
5871 : // cf = crossfade[i];
5872 17290800 : cf = crossfade[i];
5873 17290800 : move32();
5874 17290800 : oneminuscf = L_sub( ONE_IN_Q31, cf );
5875 : /* As the rotation matrix becomes block diagonal in a SH basis, we can*/
5876 : /* apply each angular-momentum block individually to save complexity. */
5877 :
5878 : /* loop over l blocks */
5879 17290800 : m1 = 1;
5880 17290800 : m2 = 4;
5881 17290800 : move16();
5882 17290800 : move16();
5883 51872400 : FOR( l = 1; l <= shd_rot_max_order; l++ )
5884 : {
5885 : /* compute mtx-vector product for this l */
5886 184435200 : FOR( n = m1; n < m2; n++ )
5887 : {
5888 149853600 : tmpRot[n - m1] = 0;
5889 149853600 : move32();
5890 876067200 : FOR( m = m1; m < m2; m++ )
5891 : {
5892 726213600 : val = inAudio.data_fx[m * inAudio.config.numSamplesPerChannel + idx];
5893 : /* crossfade with previous rotation gains */
5894 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 );
5895 726213600 : tmpRot[n - m1] = L_add( L_shl( temp, 1 ), tmpRot[n - m1] );
5896 726213600 : move32();
5897 726213600 : move32();
5898 : }
5899 : }
5900 : /* write back the result */
5901 184435200 : FOR( n = m1; n < m2; n++ )
5902 : {
5903 149853600 : writePtr = getSmplPtr_fx( outAudio, n, idx );
5904 149853600 : ( *writePtr ) = tmpRot[n - m1];
5905 149853600 : move32();
5906 : }
5907 34581600 : m1 = m2;
5908 34581600 : move16();
5909 34581600 : m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
5910 : }
5911 : }
5912 :
5913 : /* move SHrotmat to SHrotmat_prev */
5914 1224765 : FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5915 : {
5916 1152720 : Copy( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
5917 : }
5918 : }
5919 45018 : pop_wmops();
5920 :
5921 45018 : return IVAS_ERR_OK;
5922 : }
5923 :
5924 :
5925 150000 : static ivas_error renderIsmToBinaural(
5926 : input_ism *ismInput,
5927 : IVAS_REND_AudioBuffer outAudio )
5928 : {
5929 : Word32 tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5930 : ivas_error error;
5931 : Word16 ism_md_subframe_update_ext;
5932 : Word16 i;
5933 150000 : Word16 exp = *outAudio.pq_fact;
5934 150000 : move16();
5935 :
5936 150000 : push_wmops( "renderIsmToBinaural" );
5937 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5938 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 */ ) );
5939 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer );
5940 :
5941 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5942 : {
5943 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
5944 : }
5945 :
5946 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,
5947 : *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer, &exp ) ),
5948 : IVAS_ERR_OK ) )
5949 : {
5950 0 : return error;
5951 : }
5952 :
5953 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
5954 : {
5955 2400000 : Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
5956 : }
5957 :
5958 150000 : IF( ismInput->hReverb != NULL )
5959 : {
5960 0 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
5961 : {
5962 0 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
5963 : {
5964 0 : tmpTDRendBuffer[i][j] = L_shl( tmpTDRendBuffer[i][j], Q2 ); /* Q(exp + 2) */
5965 0 : move32();
5966 : }
5967 : }
5968 : }
5969 150000 : accumulate2dArrayToBuffer_fx( tmpTDRendBuffer, &outAudio );
5970 :
5971 150000 : pop_wmops();
5972 :
5973 150000 : return IVAS_ERR_OK;
5974 : }
5975 :
5976 :
5977 0 : static Word16 getNumSubframesInBuffer(
5978 : const IVAS_REND_AudioBuffer *buffer,
5979 : const Word32 sampleRate )
5980 : {
5981 : Word16 cldfb2tdShift;
5982 :
5983 0 : cldfb2tdShift = buffer->config.is_cldfb ? 1 : 0;
5984 :
5985 0 : Word16 scale, temp = extract_l( Mpy_32_32( sampleRate, 10737418 /* 1 / FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
5986 0 : temp = BASOP_Util_Divide1616_Scale( buffer->config.numSamplesPerChannel, temp, &scale );
5987 0 : temp = shr( temp, sub( 15, scale ) ); /* Q0 */
5988 0 : temp = shr( temp, cldfb2tdShift );
5989 :
5990 0 : return temp;
5991 : }
5992 :
5993 :
5994 150000 : static ivas_error renderIsmToBinauralRoom(
5995 : input_ism *ismInput,
5996 : IVAS_REND_AudioBuffer outAudio,
5997 : Word16 *exp )
5998 : {
5999 : Word16 position_changed;
6000 : Word16 i, j;
6001 : Word32 azi_rot, ele_rot; /* Q22 */
6002 : Word16 subframe_idx;
6003 : Word16 tmp;
6004 : rotation_matrix_fx Rmat;
6005 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6006 : ivas_error error;
6007 : pan_vector_fx currentPanGains;
6008 : IVAS_REND_AudioBuffer tmpMcBuffer;
6009 : IVAS_ISM_METADATA rotatedPosPrev;
6010 : IVAS_ISM_METADATA rotatedPos;
6011 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6012 : Word8 combinedOrientationEnabled;
6013 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6014 :
6015 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6016 : {
6017 2400000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6018 : }
6019 :
6020 150000 : push_wmops( "renderIsmToBinauralRoom" );
6021 :
6022 150000 : rotatedPosPrev = defaultObjectPosition();
6023 150000 : rotatedPos = defaultObjectPosition();
6024 :
6025 150000 : hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
6026 150000 : combinedOrientationEnabled = 0;
6027 150000 : move16();
6028 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
6029 150000 : IF( *hCombinedOrientationData != NULL )
6030 : #else
6031 : IF( hCombinedOrientationData != NULL )
6032 : #endif
6033 : {
6034 75000 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6035 : {
6036 75000 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6037 : {
6038 75000 : combinedOrientationEnabled = 1;
6039 75000 : move16();
6040 75000 : BREAK;
6041 : }
6042 : }
6043 : }
6044 :
6045 150000 : IF( combinedOrientationEnabled )
6046 : {
6047 150000 : FOR( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
6048 : {
6049 300000 : FOR( i = 0; i < 3; i++ )
6050 : {
6051 225000 : test();
6052 225000 : IF( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
6053 : {
6054 900000 : FOR( j = 0; j < 3; j++ )
6055 : {
6056 675000 : Rmat[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
6057 675000 : move32();
6058 : }
6059 : }
6060 : ELSE
6061 : {
6062 : /* Set to identity */
6063 0 : set_zero_fx( Rmat[i], 3 );
6064 0 : Rmat[i][i] = ONE_IN_Q30;
6065 0 : move32();
6066 : }
6067 : }
6068 : }
6069 : }
6070 :
6071 : /* get previous position */
6072 150000 : IF( combinedOrientationEnabled )
6073 : {
6074 75000 : rotateAziEle_fx_frac_az_el( ismInput->previousPos.azimuth_fx, ismInput->previousPos.elevation_fx, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
6075 75000 : rotatedPosPrev.azimuth_fx = azi_rot;
6076 75000 : move32();
6077 75000 : rotatedPosPrev.elevation_fx = ele_rot;
6078 75000 : move32();
6079 : }
6080 : ELSE
6081 : {
6082 75000 : rotatedPosPrev.azimuth_fx = ismInput->previousPos.azimuth_fx;
6083 75000 : move32();
6084 75000 : rotatedPosPrev.elevation_fx = ismInput->previousPos.elevation_fx;
6085 75000 : move32();
6086 : }
6087 :
6088 : /* get current position */
6089 150000 : IF( combinedOrientationEnabled )
6090 : {
6091 75000 : rotateAziEle_fx_frac_az_el( ismInput->currentPos.azimuth_fx, ismInput->currentPos.elevation_fx, &azi_rot, &ele_rot, Rmat, 0 );
6092 75000 : rotatedPos.azimuth_fx = azi_rot;
6093 75000 : move32();
6094 75000 : rotatedPos.elevation_fx = ele_rot;
6095 75000 : move32();
6096 : }
6097 : ELSE
6098 : {
6099 75000 : rotatedPos.azimuth_fx = ismInput->currentPos.azimuth_fx;
6100 75000 : move32();
6101 75000 : rotatedPos.elevation_fx = ismInput->currentPos.elevation_fx;
6102 75000 : move32();
6103 : }
6104 :
6105 150000 : test();
6106 150000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &rotatedPos, &rotatedPosPrev );
6107 150000 : move16();
6108 :
6109 : /* set previous gains if this is the first frame */
6110 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 ) )
6111 : {
6112 0 : return error;
6113 : }
6114 :
6115 : /* compute gains only if position changed */
6116 150000 : IF( position_changed )
6117 : {
6118 64693 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper, rotatedPos.azimuth_fx, rotatedPos.elevation_fx, currentPanGains ) ),
6119 : IVAS_ERR_OK ) )
6120 : {
6121 0 : return error;
6122 : }
6123 : }
6124 :
6125 : /* intermediate rendering to 7_1_4 */
6126 150000 : tmpMcBuffer = ismInput->base.inputBuffer;
6127 :
6128 150000 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
6129 : {
6130 0 : return error;
6131 : }
6132 :
6133 150000 : tmpMcBuffer.config.numChannels = tmp;
6134 150000 : move16();
6135 150000 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
6136 150000 : set_zero_fx( tmpMcBuffer.data_fx, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
6137 :
6138 150000 : IF( position_changed )
6139 : {
6140 64693 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains, ismInput->prev_pan_gains_fx, tmpMcBuffer );
6141 : }
6142 : ELSE
6143 : {
6144 85307 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, tmpMcBuffer );
6145 : }
6146 :
6147 150000 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpRendBuffer );
6148 :
6149 : /* save gains for next frame */
6150 600000 : FOR( i = 0; i < 3; i++ )
6151 : {
6152 450000 : Copy32( Rmat[i], ismInput->rot_mat_prev[i], 3 );
6153 : }
6154 :
6155 150000 : IF( position_changed )
6156 : {
6157 64693 : Copy32( currentPanGains, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
6158 : }
6159 :
6160 : CREND_HANDLE hCrend;
6161 150000 : hCrend = ismInput->crendWrapper->hCrend[0];
6162 150000 : IF( hCrend->reflections != NULL )
6163 : {
6164 0 : test();
6165 0 : IF( EQ_32( hCrend->reflections->use_er, 1 ) && EQ_32( hCrend->reflections->is_ready, 1 ) )
6166 : {
6167 0 : FOR( i = 0; i < 150; i++ )
6168 : {
6169 0 : hCrend->reflections->shoebox_data.gains.data_fx[i] = L_shl( hCrend->reflections->shoebox_data.gains.data_fx[i], Q9 );
6170 0 : move32();
6171 : }
6172 : }
6173 : }
6174 :
6175 : #ifdef FIX_1843_IO_QFACTOR_INIT
6176 150000 : *ismInput->crendWrapper->p_io_qfactor = *exp;
6177 : #endif
6178 : /* render 7_1_4 with BRIRs */
6179 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 ) )
6180 : {
6181 0 : return error;
6182 : }
6183 :
6184 150000 : IF( hCrend->hReverb != NULL )
6185 : {
6186 0 : *exp = sub( *exp, 2 );
6187 0 : move16();
6188 : }
6189 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
6190 :
6191 150000 : free( tmpMcBuffer.data_fx );
6192 :
6193 150000 : pop_wmops();
6194 :
6195 150000 : return IVAS_ERR_OK;
6196 : }
6197 :
6198 :
6199 150000 : static ivas_error renderIsmToBinauralReverb(
6200 : input_ism *ismInput,
6201 : IVAS_REND_AudioBuffer outAudio )
6202 : {
6203 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6204 : ivas_error error;
6205 : Word16 ism_md_subframe_update_ext, i;
6206 150000 : Word16 exp = *outAudio.pq_fact;
6207 150000 : move16();
6208 :
6209 150000 : push_wmops( "renderIsmToBinauralRoom" );
6210 :
6211 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6212 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 */ ) );
6213 150000 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
6214 :
6215 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6216 : {
6217 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
6218 : }
6219 :
6220 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 ) )
6221 : {
6222 0 : return error;
6223 : }
6224 :
6225 2550000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6226 : {
6227 2400000 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( 11, exp ) ) ); /* Q(exp) */
6228 : }
6229 :
6230 150000 : IF( ismInput->hReverb != NULL )
6231 : {
6232 450000 : FOR( i = 0; i < outAudio.config.numChannels; i++ )
6233 : {
6234 115500000 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
6235 : {
6236 115200000 : tmpRendBuffer_fx[i][j] = L_shl( tmpRendBuffer_fx[i][j], 2 ); /* Q(exp + 2) */
6237 115200000 : move16();
6238 : }
6239 : }
6240 : }
6241 150000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6242 150000 : pop_wmops();
6243 :
6244 150000 : return IVAS_ERR_OK;
6245 : }
6246 :
6247 :
6248 569500 : static ivas_error renderIsmToMc(
6249 : input_ism *ismInput,
6250 : const IVAS_REND_AudioBuffer outAudio )
6251 : {
6252 : Word8 position_changed;
6253 : pan_vector_fx currentPanGains_fx; /* Q31 */
6254 : ivas_error error;
6255 :
6256 569500 : push_wmops( "renderIsmToMc" );
6257 :
6258 569500 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6259 569500 : move32();
6260 569500 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6261 569500 : move32();
6262 569500 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6263 569500 : move32();
6264 569500 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6265 569500 : move32();
6266 :
6267 569500 : test();
6268 569500 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
6269 569500 : move16();
6270 569500 : IF( EQ_32( *ismInput->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_STEREO ) )
6271 : {
6272 83500 : IF( ismInput->nonDiegeticPan )
6273 : {
6274 7500 : currentPanGains_fx[0] = L_add( L_shr( ismInput->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); /* Q31 */
6275 7500 : currentPanGains_fx[1] = L_sub( ONE_IN_Q31, currentPanGains_fx[0] ); /* Q31 */
6276 7500 : ismInput->prev_pan_gains_fx[0] = currentPanGains_fx[0]; /* Q31 */
6277 7500 : ismInput->prev_pan_gains_fx[1] = currentPanGains_fx[1]; /* Q31 */
6278 7500 : move32();
6279 7500 : move32();
6280 7500 : move32();
6281 7500 : move32();
6282 : }
6283 : ELSE
6284 : {
6285 76000 : set32_fx( currentPanGains_fx, 0, MAX_OUTPUT_CHANNELS );
6286 :
6287 : Word16 gains_fx[2];
6288 : Word16 azimuth_tmp, elevation_tmp;
6289 :
6290 76000 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
6291 76000 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
6292 :
6293 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
6294 76000 : currentPanGains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
6295 76000 : currentPanGains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
6296 76000 : move32();
6297 76000 : move32();
6298 :
6299 76000 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
6300 76000 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
6301 :
6302 76000 : set32_fx( ismInput->prev_pan_gains_fx, 0, MAX_OUTPUT_CHANNELS );
6303 76000 : ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
6304 76000 : ismInput->prev_pan_gains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
6305 76000 : ismInput->prev_pan_gains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
6306 76000 : move32();
6307 76000 : move32();
6308 : }
6309 : }
6310 : ELSE
6311 : {
6312 : /* compute gains only if position changed */
6313 486000 : IF( position_changed )
6314 : {
6315 : // TODO tmu review when #215 is resolved
6316 207304 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
6317 : ismInput->currentPos.azimuth_fx,
6318 : ismInput->currentPos.elevation_fx,
6319 : currentPanGains_fx ) ),
6320 : IVAS_ERR_OK ) )
6321 : {
6322 0 : return error;
6323 : }
6324 : }
6325 :
6326 : /* set previous gains if this is the first frame */
6327 486000 : IF( !ismInput->firstFrameRendered )
6328 : {
6329 : // TODO tmu review when #215 is resolved
6330 188 : IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
6331 : ismInput->previousPos.azimuth_fx,
6332 : ismInput->previousPos.elevation_fx,
6333 : ismInput->prev_pan_gains_fx ) ),
6334 : IVAS_ERR_OK ) )
6335 : {
6336 0 : return error;
6337 : }
6338 : /* fix2float to be removed */
6339 : }
6340 : }
6341 :
6342 : /* Assume num channels in audio buffer to be 1.
6343 : * This should have been validated in IVAS_REND_FeedInputAudio() */
6344 569500 : IF( position_changed )
6345 : {
6346 244300 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains_fx, ismInput->prev_pan_gains_fx, outAudio );
6347 : }
6348 : ELSE
6349 : {
6350 325200 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, outAudio );
6351 : }
6352 :
6353 569500 : IF( position_changed )
6354 : {
6355 244300 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
6356 : }
6357 :
6358 569500 : pop_wmops();
6359 :
6360 :
6361 569500 : return IVAS_ERR_OK;
6362 : }
6363 :
6364 :
6365 228000 : static ivas_error renderIsmToSba(
6366 : input_ism *ismInput,
6367 : const AUDIO_CONFIG outConfig,
6368 : const IVAS_REND_AudioBuffer outAudio )
6369 : {
6370 : Word16 i;
6371 : Word8 position_changed;
6372 : Word16 ambiOrderOut;
6373 : Word16 numOutChannels;
6374 : pan_vector_fx currentPanGains_fx;
6375 : ivas_error error;
6376 228000 : error = IVAS_ERR_OK;
6377 228000 : move32();
6378 :
6379 228000 : ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6380 228000 : ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6381 228000 : ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6382 228000 : ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
6383 228000 : move32();
6384 228000 : move32();
6385 228000 : move32();
6386 228000 : move32();
6387 :
6388 228000 : push_wmops( "renderIsmToSba" );
6389 :
6390 228000 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
6391 : {
6392 0 : return error;
6393 : }
6394 :
6395 228000 : IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &ambiOrderOut ) ), IVAS_ERR_OK ) )
6396 : {
6397 0 : return error;
6398 : }
6399 :
6400 228000 : test();
6401 228000 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
6402 228000 : move16();
6403 :
6404 : /* set previous gains if this is the first frame */
6405 : Word16 azimuth_tmp, elevation_tmp;
6406 228000 : IF( !ismInput->firstFrameRendered )
6407 : {
6408 : // TODO tmu review when #215 is resolved
6409 84 : azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
6410 84 : elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
6411 84 : ivas_dirac_dec_get_response_fx( azimuth_tmp, elevation_tmp, ismInput->prev_pan_gains_fx, ambiOrderOut, Q29 );
6412 1428 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6413 : {
6414 1344 : ismInput->prev_pan_gains_fx[i] = L_shl_sat( ismInput->prev_pan_gains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
6415 1344 : move32();
6416 : }
6417 : }
6418 :
6419 : /* compute gains only if position changed */
6420 228000 : IF( position_changed )
6421 : {
6422 : // TODO tmu review when #215 is resolved
6423 88848 : azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
6424 88848 : elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
6425 88848 : ivas_dirac_dec_get_response_fx( azimuth_tmp, elevation_tmp, currentPanGains_fx, ambiOrderOut, Q29 );
6426 1510416 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6427 : {
6428 1421568 : currentPanGains_fx[i] = L_shl_sat( currentPanGains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
6429 1421568 : move32();
6430 : }
6431 : }
6432 :
6433 : /* Assume num channels in audio buffer to be 1.
6434 : * This should have been validated in IVAS_REND_FeedInputAudio() */
6435 228000 : IF( position_changed )
6436 : {
6437 88848 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains_fx, ismInput->prev_pan_gains_fx, outAudio );
6438 : }
6439 : ELSE
6440 : {
6441 139152 : renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, outAudio );
6442 : }
6443 :
6444 228000 : IF( position_changed )
6445 : {
6446 88848 : Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
6447 : }
6448 228000 : pop_wmops();
6449 :
6450 228000 : return error;
6451 : }
6452 :
6453 :
6454 0 : static ivas_error renderIsmToSplitBinaural(
6455 : input_ism *ismInput,
6456 : const IVAS_REND_AudioBuffer outAudio )
6457 : {
6458 : ivas_error error;
6459 : Word32 tmpProcessing[MAX_NUM_OBJECTS][L_FRAME48k];
6460 : Word16 pos_idx;
6461 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
6462 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
6463 : IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
6464 : IVAS_QUATERNION localHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
6465 : Word16 i;
6466 : Word32 tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
6467 0 : Word16 output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
6468 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
6469 : Word16 ism_md_subframe_update_ext, exp;
6470 :
6471 0 : push_wmops( "renderIsmToSplitBinaural" );
6472 :
6473 0 : pSplitRendWrapper = ismInput->base.ctx.pSplitRendWrapper;
6474 0 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
6475 :
6476 0 : exp = *outAudio.pq_fact;
6477 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6478 0 : ism_md_subframe_update_ext = (Word16) Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, ONE_BY_SUBFRAME_LEN_MS_Q31 );
6479 :
6480 0 : pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData;
6481 :
6482 0 : IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
6483 : {
6484 0 : FOR( i = 1; i < pCombinedOrientationData->num_subframes; ++i )
6485 : {
6486 0 : Copy_Quat_fx( &pCombinedOrientationData->Quaternions[0], &pCombinedOrientationData->Quaternions[i] );
6487 : }
6488 : }
6489 :
6490 : /* Save current head positions */
6491 0 : FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6492 : {
6493 0 : Copy_Quat_fx( &pCombinedOrientationData->Quaternions[i], &originalHeadRot[i] );
6494 : }
6495 :
6496 : /* Copy input audio to a processing buffer. */
6497 0 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
6498 :
6499 :
6500 0 : FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6501 : {
6502 : /* Update head positions */
6503 0 : IF( NE_16( pos_idx, 0 ) )
6504 : {
6505 : Word16 q_fact_orig;
6506 0 : FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6507 : {
6508 0 : pCombinedOrientationData->Quaternions[i].w_fx = L_negate( 12582912 ); // Q22
6509 0 : q_fact_orig = originalHeadRot[i].q_fact;
6510 0 : modify_Quat_q_fx( &originalHeadRot[i], &localHeadRot[i], Q22 );
6511 : /*euler*/
6512 0 : Quat2EulerDegree_fx( localHeadRot[i], &pCombinedOrientationData->Quaternions[i].z_fx, &pCombinedOrientationData->Quaternions[i].y_fx, &pCombinedOrientationData->Quaternions[i].x_fx );
6513 0 : pCombinedOrientationData->Quaternions[i].x_fx = L_add( pCombinedOrientationData->Quaternions[i].x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
6514 0 : pCombinedOrientationData->Quaternions[i].y_fx = L_add( pCombinedOrientationData->Quaternions[i].y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
6515 0 : pCombinedOrientationData->Quaternions[i].z_fx = L_add( pCombinedOrientationData->Quaternions[i].z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
6516 :
6517 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] );
6518 :
6519 0 : modify_Quat_q_fx( &pCombinedOrientationData->Quaternions[i], &pCombinedOrientationData->Quaternions[i], q_fact_orig );
6520 : }
6521 : }
6522 :
6523 :
6524 0 : FOR( i = 0; i < MAX_NUM_OBJECTS; ++i )
6525 : {
6526 0 : Scale_sig32( tmpProcessing[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
6527 : }
6528 :
6529 : /* Render */
6530 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,
6531 : NULL, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, output_frame, tmpProcessing, &exp ) ) != IVAS_ERR_OK )
6532 : {
6533 0 : return error;
6534 : }
6535 :
6536 0 : FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
6537 : {
6538 0 : Scale_sig32( tmpProcessing[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
6539 : }
6540 :
6541 0 : IF( ismInput->hReverb != NULL )
6542 : {
6543 0 : FOR( i = 0; i < BINAURAL_CHANNELS; i++ )
6544 : {
6545 0 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
6546 : {
6547 0 : tmpProcessing[i][j] = L_shl( tmpProcessing[i][j], Q2 ); /* Q(exp + 2) */
6548 0 : move32();
6549 : }
6550 : }
6551 : }
6552 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
6553 : * overwrite original audio, which is still needed for rendering next head pose. */
6554 0 : Copy32( tmpProcessing[0], tmpBinaural[i_mult( 2, pos_idx )], output_frame );
6555 0 : Copy32( tmpProcessing[1], tmpBinaural[add( i_mult( 2, pos_idx ), 1 )], output_frame );
6556 :
6557 : /* Overwrite processing buffer with original input audio again */
6558 0 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
6559 : }
6560 :
6561 : /* Restore original head rotation */
6562 0 : FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6563 : {
6564 0 : Copy_Quat_fx( &originalHeadRot[i], &pCombinedOrientationData->Quaternions[i] );
6565 : }
6566 :
6567 0 : accumulate2dArrayToBuffer_fx( tmpBinaural, &outAudio );
6568 0 : pop_wmops();
6569 :
6570 : /* Encoding to split rendering bitstream done at a higher level */
6571 0 : return IVAS_ERR_OK;
6572 : }
6573 :
6574 :
6575 150 : static void renderIsmToMasa(
6576 : input_ism *ismInput,
6577 : IVAS_REND_AudioBuffer outAudio,
6578 : Word16 *exp )
6579 : {
6580 : Word32 tmpRendBuffer_fx[MAX_NUM_OBJECTS][L_FRAME48k];
6581 : Word16 i, guard_bits, q_min, q_diff;
6582 :
6583 150 : push_wmops( "renderIsmToMasa" );
6584 :
6585 150 : copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
6586 :
6587 150 : q_min = MAX_16;
6588 150 : move16();
6589 :
6590 750 : FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
6591 : {
6592 600 : q_min = s_min( q_min, L_norm_arr( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel ) );
6593 : }
6594 :
6595 150 : guard_bits = find_guarded_bits_fx( ismInput->base.inputBuffer.config.numSamplesPerChannel );
6596 150 : q_min = sub( add( q_min, *outAudio.pq_fact ), guard_bits );
6597 150 : q_diff = sub( q_min, *outAudio.pq_fact );
6598 :
6599 750 : FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
6600 : {
6601 600 : scale_sig32( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel, q_diff ); // *outAudio.pq_fact -> q_min
6602 : }
6603 :
6604 150 : ivas_omasa_ana_fx( ismInput->hOMasa, tmpRendBuffer_fx, &q_min, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
6605 :
6606 150 : *exp = q_min;
6607 150 : move16();
6608 :
6609 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6610 :
6611 150 : pop_wmops();
6612 :
6613 150 : return;
6614 : }
6615 :
6616 1247650 : static ivas_error renderInputIsm(
6617 : input_ism *ismInput,
6618 : const AUDIO_CONFIG outConfig,
6619 : const IVAS_REND_AudioBuffer outAudio )
6620 : {
6621 : ivas_error error;
6622 : IVAS_REND_AudioBuffer inAudio;
6623 1247650 : Word16 exp = *outAudio.pq_fact;
6624 1247650 : move16();
6625 :
6626 1247650 : error = IVAS_ERR_OK;
6627 1247650 : move32();
6628 1247650 : inAudio = ismInput->base.inputBuffer;
6629 :
6630 1247650 : IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
6631 : {
6632 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" );
6633 : }
6634 1247650 : ismInput->base.numNewSamplesPerChannel = 0;
6635 1247650 : move32();
6636 :
6637 : /* Apply input gain to new audio */
6638 1247650 : v_multc_fixed( inAudio.data_fx, ismInput->base.gain_fx, inAudio.data_fx, imult1616( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
6639 1247650 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 );
6640 1247650 : move16();
6641 1247650 : exp = *outAudio.pq_fact;
6642 1247650 : move16();
6643 :
6644 : /* set combined orientation subframe info to start info */
6645 1247650 : ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
6646 :
6647 :
6648 1247650 : SWITCH( getAudioConfigType( outConfig ) )
6649 : {
6650 569500 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6651 569500 : error = renderIsmToMc( ismInput, outAudio );
6652 569500 : BREAK;
6653 228000 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6654 228000 : error = renderIsmToSba( ismInput, outConfig, outAudio );
6655 228000 : BREAK;
6656 450000 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6657 : SWITCH( outConfig )
6658 : {
6659 150000 : case IVAS_AUDIO_CONFIG_BINAURAL:
6660 150000 : error = renderIsmToBinaural( ismInput, outAudio );
6661 150000 : BREAK;
6662 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6663 150000 : error = renderIsmToBinauralRoom( ismInput, outAudio, &exp );
6664 150000 : BREAK;
6665 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
6666 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
6667 0 : error = renderIsmToSplitBinaural( ismInput, outAudio );
6668 0 : break;
6669 150000 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6670 150000 : error = renderIsmToBinauralReverb( ismInput, outAudio );
6671 150000 : BREAK;
6672 0 : default:
6673 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6674 : }
6675 450000 : BREAK;
6676 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6677 150 : renderIsmToMasa( ismInput, outAudio, &exp );
6678 150 : BREAK;
6679 0 : default:
6680 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6681 : }
6682 :
6683 : /* Check error here to keep switch statement more compact */
6684 1247650 : IF( NE_32( error, IVAS_ERR_OK ) )
6685 : {
6686 0 : return error;
6687 : }
6688 :
6689 1247650 : ismInput->firstFrameRendered = TRUE;
6690 1247650 : move16();
6691 :
6692 1247650 : *outAudio.pq_fact = exp;
6693 1247650 : move16();
6694 :
6695 1247650 : return error;
6696 : }
6697 :
6698 1126140 : static ivas_error renderActiveInputsIsm(
6699 : IVAS_REND_HANDLE hIvasRend,
6700 : IVAS_REND_AudioBuffer outAudio )
6701 : {
6702 : Word16 i;
6703 : input_ism *pCurrentInput;
6704 : ivas_error error;
6705 1126140 : Word16 input_q = outAudio.q_factor;
6706 1126140 : move16();
6707 5630700 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
6708 : {
6709 4504560 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
6710 : {
6711 : /* Skip inactive inputs */
6712 3256910 : CONTINUE;
6713 : }
6714 :
6715 1247650 : *outAudio.pq_fact = input_q;
6716 1247650 : move16();
6717 1247650 : IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
6718 : {
6719 0 : return error;
6720 : }
6721 2925119650 : FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
6722 : {
6723 2923872000 : outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
6724 2923872000 : move32();
6725 : }
6726 1247650 : *outAudio.pq_fact = sub( input_q, 1 );
6727 1247650 : move16();
6728 : }
6729 1126140 : return IVAS_ERR_OK;
6730 : }
6731 :
6732 87012 : static ivas_error renderLfeToBinaural_fx(
6733 : const input_mc *mcInput,
6734 : const AUDIO_CONFIG outConfig,
6735 : IVAS_REND_AudioBuffer outAudio,
6736 : Word16 in_q,
6737 : Word16 out_q )
6738 : {
6739 : Word16 lfe_idx;
6740 : Word16 pose_idx, num_poses;
6741 : Word32 gain_fx;
6742 : Word16 ear_idx, i, r_shift;
6743 : Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL];
6744 : Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
6745 : const Word32 *lfeInput;
6746 : Word32 *writePtr;
6747 :
6748 87012 : assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" );
6749 :
6750 87012 : push_wmops( "renderLfeToBinaural" );
6751 87012 : gain_fx = GAIN_LFE_WORD32; /* 1.88364911f in Q30 */
6752 87012 : move32();
6753 :
6754 87012 : IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
6755 : {
6756 48000 : lfe_idx = LFE_CHANNEL;
6757 48000 : move16();
6758 : }
6759 39012 : ELSE IF( mcInput->customLsInput.num_lfe > 0 )
6760 : {
6761 0 : lfe_idx = mcInput->customLsInput.lfe_idx[0];
6762 0 : move16();
6763 : }
6764 : ELSE
6765 : {
6766 : /* no LFE to render */
6767 39012 : pop_wmops();
6768 39012 : return IVAS_ERR_OK;
6769 : }
6770 :
6771 : /* --- Prepare LFE signal to be added to binaural output --- */
6772 48000 : lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 );
6773 48000 : frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
6774 48000 : move16();
6775 48000 : num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
6776 48000 : move16();
6777 48000 : num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame );
6778 :
6779 : /* Assuming LFE should be delayed by less that the duration of one frame */
6780 48000 : assert( mcInput->binauralDelaySmp < frame_size );
6781 :
6782 : /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
6783 48000 : v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
6784 :
6785 : /* Continue filling tmp buffer, now with LFE signal from current frame */
6786 48000 : v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); /* Qx - 1 */
6787 :
6788 : /* Save remaining LFE samples of current frame for next frame */
6789 48000 : MVR2R_WORD32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame );
6790 48000 : r_shift = sub( sub( in_q, 1 ), out_q );
6791 :
6792 48000 : IF( r_shift != 0 )
6793 : {
6794 14533750 : FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ )
6795 : {
6796 14496000 : tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); /* Q(out_q) */
6797 14496000 : move32();
6798 : }
6799 : }
6800 :
6801 : /* Copy LFE to left and right binaural channels for all poses */
6802 48000 : IF( mcInput->base.ctx.pSplitRendWrapper != NULL )
6803 : {
6804 0 : num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
6805 0 : move16();
6806 : }
6807 : ELSE
6808 : {
6809 48000 : num_poses = 1;
6810 48000 : move16();
6811 : }
6812 :
6813 96000 : FOR( pose_idx = 0; pose_idx < num_poses; ++pose_idx )
6814 : {
6815 144000 : FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
6816 : {
6817 96000 : writePtr = getSmplPtr_fx( outAudio, add( i_mult( pose_idx, BINAURAL_CHANNELS ), ear_idx ), 0 );
6818 96000 : move32();
6819 96000 : v_add_fixed_no_hdrm( writePtr, tmpLfeBuffer, writePtr, frame_size ); /* Q(out_q) */
6820 : }
6821 : }
6822 :
6823 48000 : pop_wmops();
6824 :
6825 48000 : return IVAS_ERR_OK;
6826 : }
6827 :
6828 29004 : static ivas_error renderMcToBinaural(
6829 : input_mc *mcInput,
6830 : const AUDIO_CONFIG outConfig,
6831 : IVAS_REND_AudioBuffer outAudio )
6832 : {
6833 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6834 : AUDIO_CONFIG inConfig;
6835 : ivas_error error;
6836 : IVAS_REND_AudioBuffer tmpRotBuffer;
6837 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6838 : Word8 combinedOrientationEnabled;
6839 : Word16 subframe_idx;
6840 : Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS];
6841 : Word16 i;
6842 29004 : Word16 exp = *outAudio.pq_fact;
6843 29004 : move16();
6844 :
6845 493068 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6846 : {
6847 464064 : p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i];
6848 : }
6849 29004 : push_wmops( "renderMcToBinaural" );
6850 :
6851 29004 : inConfig = mcInput->base.inConfig;
6852 29004 : move32();
6853 29004 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6854 29004 : combinedOrientationEnabled = 0;
6855 29004 : move16();
6856 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
6857 29004 : IF( *hCombinedOrientationData != NULL )
6858 : #else
6859 : IF( hCombinedOrientationData != NULL )
6860 : #endif
6861 : {
6862 14502 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6863 : {
6864 14502 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6865 : {
6866 14502 : combinedOrientationEnabled = 1;
6867 14502 : move16();
6868 14502 : BREAK;
6869 : }
6870 : }
6871 : }
6872 :
6873 29004 : test();
6874 29004 : test();
6875 29004 : test();
6876 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 ) ) ) )
6877 : {
6878 18754 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
6879 :
6880 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6881 : {
6882 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
6883 : }
6884 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,
6885 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ),
6886 : IVAS_ERR_OK ) )
6887 : {
6888 0 : return error;
6889 : }
6890 :
6891 318818 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6892 : {
6893 300064 : Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
6894 : }
6895 : }
6896 : ELSE
6897 : {
6898 : /* apply rotation */
6899 10250 : IF( combinedOrientationEnabled )
6900 : {
6901 2250 : tmpRotBuffer = mcInput->base.inputBuffer;
6902 2250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
6903 2250 : set32_fx( tmpRotBuffer.data_fx, 0, imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
6904 :
6905 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 ) )
6906 : {
6907 0 : return error;
6908 : }
6909 :
6910 2250 : exp = sub( *outAudio.pq_fact, 1 );
6911 :
6912 2250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx );
6913 :
6914 2250 : free( tmpRotBuffer.data_fx );
6915 : }
6916 : ELSE
6917 : {
6918 8000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
6919 : }
6920 : // Porting Crend_process function
6921 : CREND_HANDLE hCrend;
6922 10250 : hCrend = mcInput->crendWrapper->hCrend[0];
6923 :
6924 : #ifdef FIX_1843_IO_QFACTOR_INIT
6925 10250 : *mcInput->crendWrapper->p_io_qfactor = exp;
6926 : #endif
6927 : /* call CREND */
6928 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 ) )
6929 : {
6930 0 : return error;
6931 : }
6932 :
6933 10250 : IF( hCrend->hReverb != NULL )
6934 : {
6935 0 : exp = sub( exp, 2 );
6936 : }
6937 : }
6938 :
6939 29004 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
6940 :
6941 29004 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
6942 :
6943 : {
6944 0 : return error;
6945 : }
6946 29004 : *outAudio.pq_fact = exp;
6947 29004 : move16();
6948 :
6949 29004 : pop_wmops();
6950 29004 : return IVAS_ERR_OK;
6951 : }
6952 :
6953 32000 : static ivas_error renderMcToBinauralRoom(
6954 : input_mc *mcInput,
6955 : const AUDIO_CONFIG outConfig,
6956 : IVAS_REND_AudioBuffer outAudio )
6957 : {
6958 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6959 : AUDIO_CONFIG inConfig;
6960 : ivas_error error;
6961 : IVAS_REND_AudioBuffer tmpRotBuffer;
6962 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6963 : Word16 i;
6964 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6965 : Word8 combinedOrientationEnabled;
6966 : Word16 subframe_idx;
6967 32000 : Word16 exp = *outAudio.pq_fact;
6968 32000 : move16();
6969 :
6970 544000 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6971 : {
6972 512000 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6973 : }
6974 :
6975 32000 : push_wmops( "renderMcToBinauralRoom" );
6976 32000 : inConfig = mcInput->base.inConfig;
6977 32000 : move32();
6978 32000 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6979 32000 : combinedOrientationEnabled = 0;
6980 32000 : move16();
6981 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
6982 32000 : IF( *hCombinedOrientationData != NULL )
6983 : #else
6984 : IF( hCombinedOrientationData != NULL )
6985 : #endif
6986 : {
6987 16000 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6988 : {
6989 16000 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6990 : {
6991 16000 : combinedOrientationEnabled = 1;
6992 16000 : move16();
6993 16000 : BREAK;
6994 : }
6995 : }
6996 : }
6997 :
6998 32000 : test();
6999 32000 : test();
7000 32000 : test();
7001 32000 : test();
7002 32000 : test();
7003 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 ) ) ) ) )
7004 : {
7005 5750 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
7006 :
7007 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7008 : {
7009 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
7010 : }
7011 :
7012 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,
7013 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ),
7014 : IVAS_ERR_OK ) )
7015 : {
7016 0 : return error;
7017 : }
7018 :
7019 97750 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7020 : {
7021 92000 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
7022 : }
7023 : }
7024 : ELSE
7025 : {
7026 : /* apply rotation */
7027 26250 : IF( combinedOrientationEnabled )
7028 : {
7029 10250 : tmpRotBuffer = mcInput->base.inputBuffer;
7030 10250 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7031 10250 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
7032 :
7033 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 ) ),
7034 : IVAS_ERR_OK ) )
7035 : {
7036 0 : return error;
7037 : }
7038 :
7039 10250 : exp = sub( *outAudio.pq_fact, 1 );
7040 :
7041 10250 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
7042 10250 : free( tmpRotBuffer.data_fx );
7043 : }
7044 : ELSE
7045 : {
7046 16000 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
7047 : }
7048 : // Porting Crend_process function
7049 : CREND_HANDLE hCrend;
7050 26250 : hCrend = mcInput->crendWrapper->hCrend[0];
7051 :
7052 : #ifdef FIX_1843_IO_QFACTOR_INIT
7053 26250 : *mcInput->crendWrapper->p_io_qfactor = exp;
7054 : #endif
7055 : /* call CREND */
7056 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 ) )
7057 : {
7058 0 : return error;
7059 : }
7060 :
7061 26250 : IF( hCrend->hReverb != NULL )
7062 : {
7063 10250 : exp = sub( exp, Q2 );
7064 : }
7065 : }
7066 :
7067 32000 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
7068 :
7069 32000 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
7070 : {
7071 0 : return error;
7072 : }
7073 32000 : *outAudio.pq_fact = exp;
7074 32000 : move16();
7075 :
7076 32000 : pop_wmops();
7077 32000 : return IVAS_ERR_OK;
7078 : }
7079 :
7080 26008 : static ivas_error renderMcCustomLsToBinauralRoom(
7081 : input_mc *mcInput,
7082 : const AUDIO_CONFIG outConfig,
7083 : IVAS_REND_AudioBuffer outAudio )
7084 : {
7085 : Word16 i;
7086 : Word16 tmp;
7087 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7088 : ivas_error error;
7089 : IVAS_REND_AudioBuffer tmpRotBuffer;
7090 : IVAS_REND_AudioBuffer tmpMcBuffer;
7091 : IVAS_REND_AudioBuffer *tmpBufPtr;
7092 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7093 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7094 : Word8 combinedOrientationEnabled;
7095 : Word16 subframe_idx;
7096 26008 : Word16 exp = *outAudio.pq_fact;
7097 26008 : move16();
7098 26008 : push_wmops( "renderMcCustomLsToBinauralRoom" );
7099 26008 : tmpRotBuffer = outAudio; /* avoid compilation warning */
7100 :
7101 442136 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7102 : {
7103 416128 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7104 : }
7105 :
7106 26008 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
7107 26008 : combinedOrientationEnabled = 0;
7108 26008 : move16();
7109 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
7110 26008 : IF( *hCombinedOrientationData != NULL )
7111 : #else
7112 : IF( hCombinedOrientationData != NULL )
7113 : #endif
7114 : {
7115 13004 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7116 : {
7117 13004 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7118 : {
7119 13004 : combinedOrientationEnabled = 1;
7120 13004 : move16();
7121 13004 : BREAK;
7122 : }
7123 : }
7124 : }
7125 :
7126 : /* apply rotation */
7127 26008 : IF( combinedOrientationEnabled )
7128 : {
7129 13004 : tmpRotBuffer = mcInput->base.inputBuffer;
7130 13004 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7131 13004 : set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
7132 :
7133 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 ) ),
7134 : IVAS_ERR_OK ) )
7135 : {
7136 0 : return error;
7137 : }
7138 13004 : exp = sub( *outAudio.pq_fact, Q1 );
7139 : }
7140 :
7141 : /* intermediate conversion to 7_1_4 */
7142 26008 : tmpMcBuffer = mcInput->base.inputBuffer;
7143 :
7144 26008 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
7145 : {
7146 0 : return error;
7147 : }
7148 :
7149 26008 : tmpMcBuffer.config.numChannels = tmp;
7150 26008 : move16();
7151 26008 : tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
7152 26008 : set32_fx( tmpMcBuffer.data_fx, 0, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
7153 :
7154 26008 : IF( combinedOrientationEnabled )
7155 : {
7156 13004 : tmpBufPtr = &tmpRotBuffer;
7157 : }
7158 : ELSE
7159 : {
7160 13004 : tmpBufPtr = &mcInput->base.inputBuffer;
7161 : }
7162 406136 : FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
7163 : {
7164 380128 : renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer );
7165 : }
7166 26008 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
7167 :
7168 : CREND_HANDLE hCrend;
7169 26008 : hCrend = mcInput->crendWrapper->hCrend[0];
7170 :
7171 : #ifdef FIX_1843_IO_QFACTOR_INIT
7172 26008 : *mcInput->crendWrapper->p_io_qfactor = exp;
7173 : #endif
7174 : /* call CREND */
7175 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 ) )
7176 : {
7177 0 : return error;
7178 : }
7179 :
7180 26008 : IF( hCrend->hReverb != NULL )
7181 : {
7182 13004 : exp = sub( exp, 2 );
7183 : }
7184 :
7185 26008 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
7186 :
7187 26008 : IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
7188 : {
7189 0 : return error;
7190 : }
7191 26008 : *outAudio.pq_fact = exp;
7192 26008 : move16();
7193 26008 : IF( combinedOrientationEnabled )
7194 : {
7195 13004 : free( tmpRotBuffer.data_fx );
7196 : }
7197 26008 : free( tmpMcBuffer.data_fx );
7198 :
7199 26008 : pop_wmops();
7200 26008 : return IVAS_ERR_OK;
7201 : }
7202 :
7203 196617 : static void renderMcToMc(
7204 : const input_mc *mcInput,
7205 : IVAS_REND_AudioBuffer outAudio )
7206 : {
7207 : Word16 i;
7208 : IVAS_REND_AudioBuffer inAudio;
7209 :
7210 196617 : push_wmops( "renderMcToMc" );
7211 196617 : inAudio = mcInput->base.inputBuffer;
7212 :
7213 1507289 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7214 : {
7215 1310672 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
7216 : }
7217 :
7218 196617 : pop_wmops();
7219 196617 : return;
7220 : }
7221 :
7222 75756 : static void renderMcToSba(
7223 : const input_mc *mcInput,
7224 : IVAS_REND_AudioBuffer outAudio )
7225 : {
7226 : Word16 i;
7227 : IVAS_REND_AudioBuffer inAudio;
7228 :
7229 75756 : push_wmops( "renderMcToSba" );
7230 75756 : inAudio = mcInput->base.inputBuffer;
7231 :
7232 591852 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7233 : {
7234 516096 : renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
7235 : }
7236 75756 : pop_wmops();
7237 75756 : return;
7238 : }
7239 :
7240 150 : static void renderMcToMasa(
7241 : input_mc *mcInput,
7242 : IVAS_REND_AudioBuffer outAudio )
7243 : {
7244 150 : push_wmops( "renderMcToMasa" );
7245 : Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7246 150 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
7247 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 );
7248 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
7249 :
7250 150 : pop_wmops();
7251 150 : return;
7252 : }
7253 :
7254 0 : static ivas_error renderMcToSplitBinaural(
7255 : input_mc *mcInput,
7256 : const AUDIO_CONFIG outConfig,
7257 : IVAS_REND_AudioBuffer outAudio )
7258 : {
7259 : Word16 i, j, pos_idx;
7260 : Word16 sf;
7261 : Word16 output_frame;
7262 : ivas_error error;
7263 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
7264 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
7265 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7266 : Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
7267 : Word32 tmpSplitBinauralBuffer[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
7268 : AUDIO_CONFIG inConfig;
7269 : IVAS_REND_AudioBuffer tmpRotBuffer;
7270 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
7271 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
7272 0 : Word16 exp = *outAudio.pq_fact;
7273 0 : move16();
7274 : CREND_HANDLE hCrend;
7275 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
7276 : Word16 q_fact_orig;
7277 :
7278 0 : push_wmops( "renderMcToSplitBinaural" );
7279 0 : inConfig = mcInput->base.inConfig;
7280 0 : move32();
7281 0 : output_frame = mcInput->base.inputBuffer.config.numSamplesPerChannel;
7282 0 : move16();
7283 :
7284 0 : pSplitRendWrapper = mcInput->base.ctx.pSplitRendWrapper;
7285 0 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
7286 0 : move32();
7287 0 : move32();
7288 :
7289 0 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7290 : {
7291 0 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
7292 0 : move32();
7293 : }
7294 :
7295 : /* save current head positions */
7296 0 : pCombinedOrientationDataLocal = *mcInput->base.ctx.pCombinedOrientationData;
7297 0 : move32();
7298 0 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
7299 0 : move32();
7300 0 : IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
7301 : {
7302 0 : FOR( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
7303 : {
7304 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[0], &combinedOrientationDataLocal.Quaternions[sf] );
7305 0 : FOR( i = 0; i < 3; i++ )
7306 : {
7307 0 : FOR( j = 0; j < 3; j++ )
7308 : {
7309 0 : combinedOrientationDataLocal.Rmat_fx[sf][i][j] = combinedOrientationDataLocal.Rmat_fx[0][i][j];
7310 0 : move32();
7311 : }
7312 : }
7313 : }
7314 : }
7315 :
7316 : /* temporary buffer for rotation in source format for CREND */
7317 0 : tmpRotBuffer = mcInput->base.inputBuffer;
7318 0 : move32();
7319 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 ) )
7320 : {
7321 0 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7322 : }
7323 :
7324 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7325 : {
7326 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[i], &Quaternions_orig[i] );
7327 : }
7328 :
7329 0 : FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
7330 : {
7331 : /* Update head positions */
7332 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7333 : {
7334 0 : Quaternions_abs.w_fx = L_negate( 12582912 ); // Q22
7335 0 : q_fact_orig = Quaternions_orig[i].q_fact;
7336 0 : modify_Quat_q_fx( &combinedOrientationDataLocal.Quaternions[i], &combinedOrientationDataLocal.Quaternions[i], Q22 );
7337 : /*euler*/
7338 0 : Quat2EulerDegree_fx( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z_fx, &Quaternions_abs.y_fx, &Quaternions_abs.x_fx );
7339 0 : Quaternions_abs.x_fx = L_add( Quaternions_abs.x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
7340 0 : Quaternions_abs.y_fx = L_add( Quaternions_abs.y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
7341 0 : Quaternions_abs.z_fx = L_add( Quaternions_abs.z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
7342 :
7343 0 : Euler2Quat_fx( deg2rad_fx( Quaternions_abs.x_fx ), deg2rad_fx( Quaternions_abs.y_fx ), deg2rad_fx( Quaternions_abs.z_fx ), &Quaternions_abs );
7344 :
7345 0 : modify_Quat_q_fx( &Quaternions_abs, &Quaternions_abs, q_fact_orig );
7346 :
7347 0 : Copy_Quat_fx( &Quaternions_abs, &combinedOrientationDataLocal.Quaternions[i] );
7348 0 : QuatToRotMat_fx( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat_fx[i] );
7349 0 : modify_Rmat_q_fx( combinedOrientationDataLocal.Rmat_fx[i], combinedOrientationDataLocal.Rmat_fx[i], sub( shl( q_fact_orig, 1 ), 32 ), Q30 );
7350 : }
7351 :
7352 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 ) )
7353 : {
7354 : /* tdrend processing overview:
7355 : * 1. copy from inputBuffer to tmpRendBuffer
7356 : * 2. td_binaural_renderer_ext: inplace processing in tmpRendBuffer
7357 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
7358 : * 4. LFE mixing
7359 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
7360 :
7361 : /* copy input to tdrend input/output buffer */
7362 0 : copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
7363 :
7364 : /* perform rotation in source format to tmpRotBuffer */
7365 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7366 :
7367 0 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
7368 : {
7369 0 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
7370 : }
7371 : /* Render */
7372 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 )
7373 : {
7374 0 : return error;
7375 : }
7376 0 : FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
7377 : {
7378 0 : Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
7379 : }
7380 :
7381 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
7382 : * overwrite original audio, which is still needed for rendering next head pose. */
7383 0 : Copy32( tmpRendBuffer[0], tmpSplitBinauralBuffer[i_mult( 2, pos_idx )], output_frame );
7384 0 : Copy32( tmpRendBuffer[1], tmpSplitBinauralBuffer[add( i_mult( 2, pos_idx ), 1 )], output_frame );
7385 : }
7386 : ELSE
7387 : {
7388 0 : hCrend = mcInput->crendWrapper->hCrend[0];
7389 : /* crend processing overview:
7390 : * 1. rotateFrameMc: inputBuffer to tmpRotBuffer
7391 : * 2. crend_process: tmpRotBuffer to tmpRendBuffer
7392 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
7393 : * 4. LFE mixing
7394 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
7395 :
7396 :
7397 : /* copy input for in-place rotation */
7398 0 : set32_fx( tmpRotBuffer.data_fx, 0, i_mult( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
7399 :
7400 : /* perform rotation in source format to tmpRotBuffer */
7401 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7402 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 )
7403 : {
7404 0 : return error;
7405 : }
7406 0 : IF( EQ_16( pos_idx, 0 ) )
7407 : {
7408 0 : exp = sub( *outAudio.pq_fact, 1 );
7409 : }
7410 :
7411 0 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
7412 :
7413 : #ifdef FIX_1843_IO_QFACTOR_INIT
7414 0 : *mcInput->crendWrapper->p_io_qfactor = exp;
7415 : #endif
7416 : /* call CREND (rotation already performed) */
7417 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 ) )
7418 : {
7419 0 : return error;
7420 : }
7421 :
7422 0 : IF( EQ_16( pos_idx, 0 ) )
7423 : {
7424 0 : IF( hCrend->hReverb != NULL )
7425 : {
7426 0 : exp = sub( exp, 2 );
7427 : }
7428 : }
7429 :
7430 : /* Copy rendererd audio to tmp storage buffer, Copying directly to output would
7431 : * overwrite original audio, which is still needed for rendering next head pose. */
7432 0 : Copy32( tmpRendBuffer[0], tmpSplitBinauralBuffer[i_mult( 2, pos_idx )], output_frame );
7433 0 : Copy32( tmpRendBuffer[1], tmpSplitBinauralBuffer[add( i_mult( 2, pos_idx ), 1 )], output_frame );
7434 : }
7435 :
7436 : /* restore original headrotation data */
7437 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7438 : {
7439 0 : Copy_Quat_fx( &Quaternions_orig[i], &combinedOrientationDataLocal.Quaternions[i] );
7440 : }
7441 : }
7442 :
7443 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 ) )
7444 : {
7445 : /* free temporary buffer for rotation in source format for CREND */
7446 0 : free( tmpRotBuffer.data_fx );
7447 : }
7448 :
7449 0 : accumulate2dArrayToBuffer_fx( tmpSplitBinauralBuffer, &outAudio );
7450 :
7451 0 : IF( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ) != IVAS_ERR_OK )
7452 : {
7453 0 : return error;
7454 : }
7455 0 : *outAudio.pq_fact = exp;
7456 :
7457 0 : pop_wmops();
7458 0 : return IVAS_ERR_OK;
7459 : }
7460 :
7461 :
7462 359535 : static ivas_error renderInputMc(
7463 : input_mc *mcInput,
7464 : const AUDIO_CONFIG outConfig,
7465 : IVAS_REND_AudioBuffer outAudio )
7466 : {
7467 : ivas_error error;
7468 : IVAS_REND_AudioBuffer inAudio;
7469 359535 : error = IVAS_ERR_OK;
7470 359535 : move32();
7471 :
7472 359535 : inAudio = mcInput->base.inputBuffer;
7473 :
7474 359535 : IF( NE_32( mcInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
7475 : {
7476 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" );
7477 : }
7478 359535 : mcInput->base.numNewSamplesPerChannel = 0;
7479 359535 : move32();
7480 359535 : v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
7481 359535 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 ); // reducing the Q by 1 compensating for the v_mult_fixed done
7482 359535 : move16();
7483 : /* set combined orientation subframe info to start info */
7484 359535 : ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
7485 :
7486 359535 : SWITCH( getAudioConfigType( outConfig ) )
7487 : {
7488 196617 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
7489 196617 : renderMcToMc( mcInput, outAudio );
7490 196617 : BREAK;
7491 75756 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
7492 75756 : renderMcToSba( mcInput, outAudio );
7493 75756 : BREAK;
7494 87012 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
7495 : SWITCH( outConfig )
7496 : {
7497 29004 : case IVAS_AUDIO_CONFIG_BINAURAL:
7498 29004 : error = renderMcToBinaural( mcInput, outConfig, outAudio );
7499 29004 : BREAK;
7500 58008 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
7501 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
7502 58008 : IF( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
7503 : {
7504 26008 : error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
7505 : }
7506 : ELSE
7507 : {
7508 32000 : error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
7509 : }
7510 58008 : BREAK;
7511 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
7512 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
7513 0 : error = renderMcToSplitBinaural( mcInput, outConfig, outAudio );
7514 0 : break;
7515 0 : default:
7516 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7517 : }
7518 87012 : BREAK;
7519 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
7520 150 : renderMcToMasa( mcInput, outAudio );
7521 150 : BREAK;
7522 0 : default:
7523 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7524 : }
7525 359535 : return error;
7526 : }
7527 :
7528 :
7529 1126140 : static ivas_error renderActiveInputsMc(
7530 : IVAS_REND_HANDLE hIvasRend,
7531 : IVAS_REND_AudioBuffer outAudio )
7532 : {
7533 : Word16 i;
7534 : input_mc *pCurrentInput;
7535 : ivas_error error;
7536 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMc ); i < RENDERER_MAX_MC_INPUTS; ( ++i, ++pCurrentInput ) )
7537 : {
7538 1126140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
7539 : {
7540 : /* Skip inactive inputs */
7541 766605 : CONTINUE;
7542 : }
7543 :
7544 359535 : *outAudio.pq_fact = outAudio.q_factor;
7545 359535 : move16();
7546 359535 : IF( NE_32( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
7547 : {
7548 0 : return error;
7549 : }
7550 : }
7551 :
7552 1126140 : return IVAS_ERR_OK;
7553 : }
7554 :
7555 :
7556 115801 : static void renderSbaToMc(
7557 : const input_sba *sbaInput,
7558 : IVAS_REND_AudioBuffer outAudio )
7559 : {
7560 : Word16 i;
7561 : IVAS_REND_AudioBuffer inAudio;
7562 :
7563 115801 : push_wmops( "renderSbaToMc" );
7564 115801 : inAudio = sbaInput->base.inputBuffer;
7565 :
7566 1225294 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7567 : {
7568 1109493 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
7569 : }
7570 :
7571 115801 : pop_wmops();
7572 115801 : return;
7573 : }
7574 :
7575 :
7576 45768 : static void renderSbaToSba(
7577 : const input_sba *sbaInput,
7578 : IVAS_REND_AudioBuffer outAudio )
7579 : {
7580 : Word16 i;
7581 : IVAS_REND_AudioBuffer inAudio;
7582 :
7583 45768 : push_wmops( "renderSbaToSba" );
7584 45768 : inAudio = sbaInput->base.inputBuffer;
7585 :
7586 483942 : FOR( i = 0; i < inAudio.config.numChannels; ++i )
7587 : {
7588 438174 : renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
7589 : }
7590 :
7591 45768 : pop_wmops();
7592 45768 : return;
7593 : }
7594 :
7595 :
7596 0 : static ivas_error renderSbaToMultiBinaural(
7597 : input_sba *sbaInput,
7598 : const AUDIO_CONFIG outConfig,
7599 : #ifdef FIX_1843_IO_QFACTOR_INIT
7600 : Word32 out[][L_FRAME48k],
7601 : const Word16 *pq_fact )
7602 : #else
7603 : Word32 out[][L_FRAME48k] )
7604 : #endif
7605 : {
7606 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7607 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7608 : Word16 sf;
7609 : Word16 i, j, pos_idx;
7610 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
7611 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
7612 : ivas_error error;
7613 : IVAS_REND_AudioBuffer tmpRotBuffer;
7614 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
7615 :
7616 0 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7617 : {
7618 0 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7619 0 : move32();
7620 : }
7621 0 : push_wmops( "renderSbaToMultiBinaural" );
7622 0 : pMultiBinPoseData = &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData;
7623 0 : move32();
7624 :
7625 0 : pCombinedOrientationDataLocal = *sbaInput->base.ctx.pCombinedOrientationData;
7626 0 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
7627 0 : move32();
7628 0 : move32();
7629 :
7630 0 : IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
7631 : {
7632 0 : FOR( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
7633 : {
7634 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[0], &combinedOrientationDataLocal.Quaternions[sf] );
7635 0 : FOR( i = 0; i < 3; i++ )
7636 : {
7637 0 : FOR( j = 0; j < 3; j++ )
7638 : {
7639 0 : combinedOrientationDataLocal.Rmat_fx[sf][i][j] = combinedOrientationDataLocal.Rmat_fx[0][i][j];
7640 0 : move32();
7641 : }
7642 : }
7643 : }
7644 : }
7645 :
7646 0 : tmpRotBuffer = sbaInput->base.inputBuffer;
7647 0 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7648 :
7649 0 : FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
7650 : {
7651 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
7652 : Word16 q_fact_orig;
7653 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7654 : {
7655 0 : Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[i], &Quaternions_orig[i] );
7656 :
7657 0 : Quaternions_abs.w_fx = L_negate( 12582912 ); // Q22
7658 0 : q_fact_orig = combinedOrientationDataLocal.Quaternions[i].q_fact;
7659 0 : modify_Quat_q_fx( &combinedOrientationDataLocal.Quaternions[i], &combinedOrientationDataLocal.Quaternions[i], Q22 );
7660 : /*euler*/
7661 0 : Quat2EulerDegree_fx( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z_fx, &Quaternions_abs.y_fx, &Quaternions_abs.x_fx );
7662 0 : Quaternions_abs.x_fx = L_add( Quaternions_abs.x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
7663 0 : Quaternions_abs.y_fx = L_add( Quaternions_abs.y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
7664 0 : Quaternions_abs.z_fx = L_add( Quaternions_abs.z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
7665 :
7666 0 : Euler2Quat_fx( deg2rad_fx( Quaternions_abs.x_fx ), deg2rad_fx( Quaternions_abs.y_fx ), deg2rad_fx( Quaternions_abs.z_fx ), &Quaternions_abs );
7667 :
7668 0 : modify_Quat_q_fx( &Quaternions_abs, &Quaternions_abs, q_fact_orig );
7669 :
7670 0 : Copy_Quat_fx( &Quaternions_abs, &combinedOrientationDataLocal.Quaternions[i] );
7671 0 : QuatToRotMat_fx( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat_fx[i] );
7672 0 : modify_Rmat_q_fx( combinedOrientationDataLocal.Rmat_fx[i], combinedOrientationDataLocal.Rmat_fx[i], sub( shl( q_fact_orig, 1 ), 32 ), Q30 );
7673 : }
7674 :
7675 : /* copy input for in-place rotation */
7676 0 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7677 :
7678 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7679 :
7680 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 )
7681 : {
7682 0 : return error;
7683 : }
7684 :
7685 0 : copyBufferTo2dArray_fx( tmpRotBuffer, tmpCrendBuffer );
7686 :
7687 0 : assert( sbaInput->crendWrapper->hCrend[0]->hReverb == NULL );
7688 :
7689 : #ifdef FIX_1843_IO_QFACTOR_INIT
7690 0 : *sbaInput->crendWrapper->p_io_qfactor = *pq_fact;
7691 : #endif
7692 : /* call CREND */
7693 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 ) )
7694 : {
7695 0 : return error;
7696 : }
7697 :
7698 0 : FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7699 : {
7700 0 : Copy_Quat_fx( &Quaternions_orig[i], &combinedOrientationDataLocal.Quaternions[i] );
7701 : }
7702 :
7703 : /* move to output */
7704 0 : FOR( i = 0; i < BINAURAL_CHANNELS; i++ )
7705 : {
7706 0 : Copy32( tmpCrendBuffer[i], out[pos_idx * BINAURAL_CHANNELS + i], tmpRotBuffer.config.numSamplesPerChannel );
7707 : }
7708 : }
7709 :
7710 0 : free( tmpRotBuffer.data_fx );
7711 :
7712 0 : pop_wmops();
7713 0 : return IVAS_ERR_OK;
7714 : }
7715 :
7716 :
7717 0 : static ivas_error renderSbaToMultiBinauralCldfb(
7718 : input_sba *sbaInput,
7719 : Word32 Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7720 : Word32 Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7721 : const Word16 low_res_pre_rend_rot,
7722 : const Word16 num_subframes,
7723 : const Word16 Q_in )
7724 : {
7725 : Word32 Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7726 : Word32 Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7727 :
7728 0 : copyBufferToCLDFBarray_fx( sbaInput->base.inputBuffer, Cldfb_RealBuffer, Cldfb_ImagBuffer );
7729 :
7730 0 : ivas_rend_CldfbMultiBinRendProcess( sbaInput->cldfbRendWrapper.hCldfbRend, sbaInput->base.ctx.pCombinedOrientationData, &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData,
7731 : Cldfb_RealBuffer, Cldfb_ImagBuffer, Cldfb_Out_Real, Cldfb_Out_Imag, low_res_pre_rend_rot, num_subframes, Q_in );
7732 :
7733 0 : return IVAS_ERR_OK;
7734 : }
7735 :
7736 :
7737 0 : static ivas_error renderSbaToSplitBinaural(
7738 : input_sba *sbaInput,
7739 : const AUDIO_CONFIG outConfig,
7740 : IVAS_REND_AudioBuffer outAudio )
7741 : {
7742 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7743 : ivas_error error;
7744 : Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7745 : Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7746 : Word16 low_res_pre_rend_rot;
7747 :
7748 0 : low_res_pre_rend_rot = 1;
7749 :
7750 0 : push_wmops( "renderSbaToSplitBinaural" );
7751 :
7752 0 : IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
7753 : {
7754 0 : if ( ( error = renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, low_res_pre_rend_rot,
7755 0 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ), *outAudio.pq_fact ) ) != IVAS_ERR_OK )
7756 : {
7757 0 : return error;
7758 : }
7759 :
7760 0 : accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7761 : }
7762 : else
7763 : {
7764 : #ifdef FIX_1843_IO_QFACTOR_INIT
7765 0 : IF( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer, outAudio.pq_fact ) ) != IVAS_ERR_OK )
7766 : #else
7767 : IF( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer ) ) != IVAS_ERR_OK )
7768 : #endif
7769 : {
7770 0 : return error;
7771 : }
7772 :
7773 0 : IF( sbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
7774 : {
7775 0 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
7776 0 : move16();
7777 : }
7778 :
7779 0 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
7780 : }
7781 :
7782 0 : pop_wmops();
7783 0 : return IVAS_ERR_OK;
7784 : }
7785 :
7786 :
7787 60024 : static ivas_error renderSbaToBinaural(
7788 : input_sba *sbaInput,
7789 : const AUDIO_CONFIG outConfig,
7790 : IVAS_REND_AudioBuffer outAudio )
7791 : {
7792 : ivas_error error;
7793 : IVAS_REND_AudioBuffer tmpRotBuffer;
7794 : Word16 i;
7795 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7796 : Word8 combinedOrientationEnabled;
7797 : Word16 subframe_idx;
7798 : Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7799 : Word32 *output_fx[MAX_OUTPUT_CHANNELS];
7800 :
7801 60024 : push_wmops( "renderSbaToBinaural" );
7802 :
7803 60024 : IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
7804 : {
7805 : Word32 Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7806 : Word32 Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7807 :
7808 0 : IF( ( error = renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 0,
7809 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ), *outAudio.pq_fact ) ) != IVAS_ERR_OK )
7810 : {
7811 0 : return error;
7812 : }
7813 :
7814 0 : accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7815 : }
7816 : ELSE
7817 : {
7818 1020408 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7819 : {
7820 960384 : output_fx[i] = output_buffer_fx[i];
7821 960384 : move32();
7822 : }
7823 :
7824 60024 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7825 60024 : combinedOrientationEnabled = 0;
7826 60024 : move16();
7827 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
7828 60024 : IF( *hCombinedOrientationData != NULL )
7829 : #else
7830 : IF( hCombinedOrientationData != NULL )
7831 : #endif
7832 : {
7833 30012 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7834 : {
7835 30012 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7836 : {
7837 30012 : combinedOrientationEnabled = 1;
7838 30012 : move16();
7839 30012 : BREAK;
7840 : }
7841 : }
7842 : }
7843 :
7844 : /* apply rotation */
7845 60024 : IF( combinedOrientationEnabled )
7846 : {
7847 30012 : tmpRotBuffer = sbaInput->base.inputBuffer;
7848 :
7849 30012 : tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
7850 :
7851 : /* copy input for in-place rotation */
7852 30012 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
7853 :
7854 30012 : IF( NE_16( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx[0], tmpRotBuffer ) ),
7855 : IVAS_ERR_OK ) )
7856 : {
7857 0 : return error;
7858 : }
7859 :
7860 30012 : copyBufferTo2dArray_fx( tmpRotBuffer, output_buffer_fx );
7861 30012 : free( tmpRotBuffer.data_fx );
7862 : }
7863 : ELSE
7864 : {
7865 30012 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, output_buffer_fx );
7866 : }
7867 :
7868 : CREND_HANDLE hCrend;
7869 60024 : hCrend = sbaInput->crendWrapper->hCrend[0];
7870 :
7871 : #ifdef FIX_1843_IO_QFACTOR_INIT
7872 60024 : *sbaInput->crendWrapper->p_io_qfactor = *outAudio.pq_fact;
7873 : #endif
7874 : /* call CREND */
7875 60024 : 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 ) )
7876 : {
7877 0 : return error;
7878 : }
7879 :
7880 60024 : IF( hCrend->hReverb != NULL )
7881 : {
7882 30012 : *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
7883 30012 : move16();
7884 : }
7885 :
7886 60024 : accumulate2dArrayToBuffer_fx( output_buffer_fx, &outAudio );
7887 : }
7888 :
7889 60024 : pop_wmops();
7890 60024 : return IVAS_ERR_OK;
7891 : }
7892 :
7893 :
7894 30012 : static ivas_error renderSbaToBinauralRoom(
7895 : input_sba *sbaInput,
7896 : const AUDIO_CONFIG outConfig,
7897 : IVAS_REND_AudioBuffer outAudio )
7898 : {
7899 : Word16 i;
7900 : Word16 tmp;
7901 : Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7902 : ivas_error error;
7903 : IVAS_REND_AudioBuffer tmpRotBuffer;
7904 : IVAS_REND_AudioBuffer tmpMcBuffer;
7905 : IVAS_REND_AudioBuffer *tmpBufPtr;
7906 : Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7907 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7908 : Word8 combinedOrientationEnabled;
7909 : Word16 subframe_idx;
7910 :
7911 30012 : tmpRotBuffer = outAudio; /* avoid compilation warning */
7912 30012 : push_wmops( "renderSbaToBinauralRoom" );
7913 : Word16 nchan_out;
7914 : CREND_HANDLE hCrend;
7915 30012 : hCrend = sbaInput->crendWrapper->hCrend[0];
7916 :
7917 30012 : IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ), IVAS_ERR_OK ) )
7918 : {
7919 0 : return error;
7920 : }
7921 :
7922 510204 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7923 : {
7924 480192 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7925 : }
7926 :
7927 30012 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7928 30012 : combinedOrientationEnabled = 0;
7929 30012 : move16();
7930 : #ifdef FIX_1135_EXT_RENDERER_HANDLES
7931 30012 : IF( *hCombinedOrientationData != NULL )
7932 : #else
7933 : IF( hCombinedOrientationData != NULL )
7934 : #endif
7935 : {
7936 15006 : FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7937 : {
7938 15006 : IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7939 : {
7940 15006 : combinedOrientationEnabled = 1;
7941 15006 : move16();
7942 15006 : BREAK;
7943 : }
7944 : }
7945 : }
7946 :
7947 : /* apply rotation */
7948 30012 : IF( combinedOrientationEnabled )
7949 : {
7950 15006 : tmpRotBuffer = sbaInput->base.inputBuffer;
7951 15006 : tmpRotBuffer.data_fx = malloc( imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) * sizeof( Word32 ) );
7952 :
7953 : /* copy input for in-place rotation */
7954 15006 : Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
7955 :
7956 15006 : IF( NE_32( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx[0], tmpRotBuffer ) ),
7957 : IVAS_ERR_OK ) )
7958 : {
7959 0 : return error;
7960 : }
7961 : }
7962 :
7963 : /* intermediate rendering to 7_1_4 */
7964 30012 : tmpMcBuffer = sbaInput->base.inputBuffer;
7965 :
7966 30012 : IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
7967 : {
7968 0 : return error;
7969 : }
7970 :
7971 30012 : tmpMcBuffer.config.numChannels = tmp;
7972 30012 : move16();
7973 30012 : tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) );
7974 30012 : set32_fx( tmpMcBuffer.data_fx, 0, i_mult( tmpMcBuffer.config.numChannels, tmpMcBuffer.config.numSamplesPerChannel ) );
7975 :
7976 30012 : IF( combinedOrientationEnabled )
7977 : {
7978 15006 : tmpBufPtr = &tmpRotBuffer;
7979 : }
7980 : ELSE
7981 : {
7982 15006 : tmpBufPtr = &sbaInput->base.inputBuffer;
7983 : }
7984 320128 : FOR( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
7985 : {
7986 290116 : renderBufferChannel_fx( *tmpBufPtr, i, sbaInput->hoaDecMtx_fx[i], tmpMcBuffer );
7987 : }
7988 30012 : copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
7989 :
7990 : #ifdef FIX_1843_IO_QFACTOR_INIT
7991 30012 : *sbaInput->crendWrapper->p_io_qfactor = *outAudio.pq_fact;
7992 : #endif
7993 : /* call CREND */
7994 30012 : 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 ) )
7995 : {
7996 0 : return error;
7997 : }
7998 :
7999 30012 : IF( hCrend->hReverb != NULL )
8000 : {
8001 0 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 2 );
8002 0 : move16();
8003 : }
8004 :
8005 30012 : accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
8006 :
8007 30012 : IF( combinedOrientationEnabled )
8008 : {
8009 15006 : free( tmpRotBuffer.data_fx );
8010 : }
8011 30012 : free( tmpMcBuffer.data_fx );
8012 :
8013 30012 : pop_wmops();
8014 30012 : return IVAS_ERR_OK;
8015 : }
8016 :
8017 :
8018 150 : static void renderSbaToMasa(
8019 : input_sba *sbaInput,
8020 : IVAS_REND_AudioBuffer outAudio )
8021 : {
8022 : Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8023 :
8024 150 : push_wmops( "renderMcToMasa" );
8025 150 : copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, tmpRendBuffer );
8026 150 : ivas_dirac_ana_fx( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, *outAudio.pq_fact );
8027 150 : accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
8028 :
8029 150 : pop_wmops();
8030 150 : return;
8031 : }
8032 :
8033 :
8034 251755 : static ivas_error renderInputSba(
8035 : input_sba *sbaInput,
8036 : const AUDIO_CONFIG outConfig,
8037 : IVAS_REND_AudioBuffer outAudio )
8038 : {
8039 : ivas_error error;
8040 : IVAS_REND_AudioBuffer inAudio;
8041 : Word16 cldfb2tdShift;
8042 251755 : error = IVAS_ERR_OK;
8043 251755 : move32();
8044 251755 : inAudio = sbaInput->base.inputBuffer;
8045 :
8046 251755 : cldfb2tdShift = outAudio.config.is_cldfb ? 1 : 0;
8047 251755 : IF( NE_32( L_shl( sbaInput->base.numNewSamplesPerChannel, cldfb2tdShift ), outAudio.config.numSamplesPerChannel ) &&
8048 : NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8049 : {
8050 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" );
8051 : }
8052 251755 : sbaInput->base.numNewSamplesPerChannel = 0;
8053 251755 : move32();
8054 251755 : *outAudio.pq_fact = outAudio.q_factor;
8055 251755 : move16();
8056 : /* Apply input gain to new audio */
8057 251755 : v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
8058 251755 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
8059 251755 : move16();
8060 :
8061 : /* set combined orientation subframe info to start info */
8062 251755 : ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
8063 :
8064 251755 : SWITCH( getAudioConfigType( outConfig ) )
8065 : {
8066 115801 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
8067 115801 : renderSbaToMc( sbaInput, outAudio );
8068 115801 : BREAK;
8069 45768 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
8070 45768 : renderSbaToSba( sbaInput, outAudio );
8071 45768 : BREAK;
8072 90036 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
8073 : SWITCH( outConfig )
8074 : {
8075 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
8076 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
8077 0 : error = renderSbaToSplitBinaural( sbaInput, outConfig, outAudio );
8078 0 : break;
8079 : #ifdef FIX_1129_EXT_REND_OUTPUT_HIGH
8080 60024 : case IVAS_AUDIO_CONFIG_BINAURAL:
8081 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
8082 60024 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
8083 60024 : break;
8084 30012 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
8085 : #else
8086 : case IVAS_AUDIO_CONFIG_BINAURAL:
8087 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
8088 : BREAK;
8089 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
8090 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
8091 : #endif
8092 30012 : error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
8093 30012 : BREAK;
8094 0 : default:
8095 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
8096 : }
8097 90036 : BREAK;
8098 150 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
8099 150 : renderSbaToMasa( sbaInput, outAudio );
8100 150 : BREAK;
8101 0 : default:
8102 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
8103 : }
8104 :
8105 251755 : return error;
8106 : }
8107 :
8108 :
8109 1126140 : static ivas_error renderActiveInputsSba(
8110 : IVAS_REND_HANDLE hIvasRend,
8111 : IVAS_REND_AudioBuffer outAudio )
8112 : {
8113 : Word16 i;
8114 : input_sba *pCurrentInput;
8115 : ivas_error error;
8116 :
8117 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsSba ); i < RENDERER_MAX_SBA_INPUTS; ( ++i, ++pCurrentInput ) )
8118 : {
8119 1126140 : IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8120 : {
8121 : /* Skip inactive inputs */
8122 874385 : CONTINUE;
8123 : }
8124 251755 : *outAudio.pq_fact = outAudio.q_factor;
8125 251755 : move16();
8126 251755 : IF( NE_32( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
8127 : {
8128 0 : return error;
8129 : }
8130 : }
8131 :
8132 1126140 : return IVAS_ERR_OK;
8133 : }
8134 :
8135 :
8136 17250 : static void copyMasaMetadataToDiracRenderer_fx(
8137 : MASA_METADATA_FRAME *meta,
8138 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
8139 : const Word16 maxBin )
8140 : {
8141 : Word16 band, sf, bin;
8142 : Word16 meta_write_index;
8143 :
8144 17250 : hSpatParamRendCom->numParametricDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
8145 17250 : hSpatParamRendCom->numSimultaneousDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
8146 17250 : move16();
8147 17250 : move16();
8148 :
8149 86250 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
8150 : {
8151 69000 : meta_write_index = add( hSpatParamRendCom->dirac_bs_md_write_idx, sf ) % hSpatParamRendCom->dirac_md_buffer_length;
8152 :
8153 1725000 : FOR( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
8154 : {
8155 5796000 : FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
8156 : {
8157 4140000 : hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8158 4140000 : move16();
8159 4140000 : hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8160 4140000 : move16();
8161 4140000 : hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band];
8162 4140000 : move32();
8163 4140000 : hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( ONE_IN_Q30, meta->directional_meta[0].energy_ratio_fx[sf][band] );
8164 4140000 : move32();
8165 4140000 : hSpatParamRendCom->spreadCoherence_fx[meta_write_index][bin] = meta->directional_meta[0].spread_coherence_fx[sf][band];
8166 4140000 : move16();
8167 4140000 : hSpatParamRendCom->surroundingCoherence_fx[meta_write_index][bin] = meta->common_meta.surround_coherence_fx[sf][band];
8168 4140000 : move16();
8169 :
8170 4140000 : IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) )
8171 : {
8172 2160000 : hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8173 2160000 : move16();
8174 2160000 : hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
8175 2160000 : move16();
8176 2160000 : hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band];
8177 2160000 : move32();
8178 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] );
8179 2160000 : move32();
8180 2160000 : hSpatParamRendCom->spreadCoherence2_fx[meta_write_index][bin] = meta->directional_meta[1].spread_coherence_fx[sf][band];
8181 2160000 : move16();
8182 : }
8183 : }
8184 : }
8185 : }
8186 :
8187 17250 : hSpatParamRendCom->dirac_bs_md_write_idx = add( hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
8188 17250 : move16();
8189 :
8190 17250 : return;
8191 : }
8192 :
8193 :
8194 150 : static void renderMasaToMasa(
8195 : input_masa *masaInput,
8196 : IVAS_REND_AudioBuffer outAudio )
8197 : {
8198 : Word16 sf, band, dir, numDirs;
8199 : Word32 ratioSum_fx; /* Q30 */
8200 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
8201 : MASA_METADATA_FRAME *inMeta;
8202 : Word32 tmpBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8203 : Word16 ts, i, j, l_ts;
8204 : Word32 Chan_RealBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
8205 : Word32 Chan_ImagBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
8206 : Word16 band_m_idx, block_m_idx;
8207 : Word16 mrange[2];
8208 : Word16 brange[2];
8209 : Word16 numAnalysisChannels;
8210 150 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_fx );
8211 150 : Word16 q_cldfb = *outAudio.pq_fact;
8212 150 : Word16 q_cldfb_out = *outAudio.pq_fact;
8213 150 : Word16 scale_factor = 31;
8214 : Word16 scale_fac_arr[MASA_MAX_TRANSPORT_CHANNELS];
8215 150 : move16();
8216 150 : move16();
8217 150 : move16();
8218 : /* Calculate energy */
8219 : // l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
8220 150 : l_ts = shr( masaInput->base.inputBuffer.config.numSamplesPerChannel, 4 );
8221 150 : numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
8222 150 : move16();
8223 : /* do processing over all CLDFB time slots */
8224 750 : FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
8225 : {
8226 600 : mrange[0] = DirAC_block_grouping[block_m_idx];
8227 600 : mrange[1] = DirAC_block_grouping[block_m_idx + 1];
8228 600 : move16();
8229 600 : move16();
8230 :
8231 600 : set_zero_fx( masaInput->hMasaPrerend->energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
8232 600 : set16_fx( masaInput->hMasaPrerend->energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
8233 :
8234 3000 : FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
8235 : {
8236 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
8237 : {
8238 4800 : scale_factor = 31;
8239 4800 : move16();
8240 4800 : masaInput->hMasaPrerend->cldfbAnaEnc[i]->Q_cldfb_state = q_cldfb;
8241 4800 : q_cldfb_out = q_cldfb;
8242 4800 : move16();
8243 4800 : move16();
8244 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 );
8245 4800 : scale_factor = s_min( scale_factor, s_min( getScaleFactor32( Chan_RealBuffer_fx[i], l_ts ), getScaleFactor32( Chan_ImagBuffer_fx[i], l_ts ) ) );
8246 4800 : scale_factor = sub( scale_factor, 1 );
8247 4800 : scale_sig32( Chan_RealBuffer_fx[i], l_ts, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
8248 4800 : scale_sig32( Chan_ImagBuffer_fx[i], l_ts, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
8249 4800 : scale_fac_arr[i] = scale_factor;
8250 4800 : move16();
8251 : }
8252 :
8253 2400 : scale_factor = MAX_16;
8254 2400 : move16();
8255 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
8256 : {
8257 4800 : scale_factor = s_min( scale_factor, scale_fac_arr[i] );
8258 : }
8259 :
8260 7200 : FOR( i = 0; i < numAnalysisChannels; i++ )
8261 : {
8262 4800 : IF( NE_16( scale_factor, scale_fac_arr[i] ) )
8263 : {
8264 48861 : FOR( j = 0; j < l_ts; j++ )
8265 : {
8266 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) */
8267 48060 : move32();
8268 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) */
8269 48060 : move32();
8270 : }
8271 : }
8272 : }
8273 :
8274 2400 : Word16 q_add = sub( 31, add( scale_factor, q_cldfb_out ) );
8275 : /* Compute channel energy for metadata processing */
8276 60000 : FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
8277 : {
8278 57600 : brange[0] = MASA_band_grouping_24[band_m_idx];
8279 57600 : move16();
8280 57600 : brange[1] = MASA_band_grouping_24[band_m_idx + 1];
8281 57600 : move16();
8282 201600 : FOR( j = brange[0]; j < brange[1]; j++ )
8283 : {
8284 432000 : FOR( i = 0; i < numAnalysisChannels; i++ )
8285 : {
8286 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 */
8287 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] );
8288 288000 : move32();
8289 : }
8290 : }
8291 : }
8292 : }
8293 : }
8294 :
8295 : /* Copy audio channels if mismatch in number of transports */
8296 150 : test();
8297 150 : test();
8298 150 : IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 1 ) && EQ_16( outAudio.config.numChannels, 2 ) )
8299 : {
8300 0 : Copy32( tmpBuffer_fx[0], tmpBuffer_fx[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
8301 : }
8302 150 : ELSE IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 2 ) && EQ_16( outAudio.config.numChannels, 1 ) )
8303 : {
8304 : // v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
8305 0 : v_add_fixed_no_hdrm( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
8306 : }
8307 :
8308 : /* Copy metadata */
8309 150 : outMeta = masaInput->hMasaPrerend->hMasaOut;
8310 150 : inMeta = &masaInput->masaMetadata;
8311 150 : numDirs = add( inMeta->descriptive_meta.numberOfDirections, 1 );
8312 :
8313 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
8314 : {
8315 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
8316 : {
8317 : /* Remainder is always set to zero and energy removal is compensated in following steps
8318 : * to other ratios. */
8319 : // inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
8320 14400 : inMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0;
8321 14400 : move32();
8322 14400 : ratioSum_fx = 0;
8323 14400 : move32();
8324 43200 : FOR( dir = 0; dir < numDirs; dir++ )
8325 : {
8326 28800 : ratioSum_fx = L_add( ratioSum_fx, inMeta->directional_meta[dir].energy_ratio_fx[sf][band] );
8327 : }
8328 14400 : ratioSum_fx = L_add( ratioSum_fx, inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
8329 :
8330 14400 : IF( ratioSum_fx == 0 )
8331 : {
8332 0 : FOR( dir = 0; dir < numDirs; dir++ )
8333 : {
8334 0 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0;
8335 0 : move32();
8336 : }
8337 0 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30;
8338 0 : move32();
8339 : }
8340 14400 : ELSE IF( NE_32( ratioSum_fx, ONE_IN_Q30 ) )
8341 : {
8342 14400 : Word16 tmp_e = 0;
8343 14400 : move16();
8344 14400 : Word32 tmp = 0;
8345 14400 : move32();
8346 43200 : FOR( dir = 0; dir < numDirs; dir++ )
8347 : {
8348 28800 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
8349 28800 : inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
8350 28800 : move32();
8351 : }
8352 14400 : tmp_e = 0;
8353 14400 : move16();
8354 14400 : tmp = 0;
8355 14400 : move32();
8356 14400 : tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
8357 14400 : inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
8358 14400 : move32();
8359 : }
8360 : }
8361 : }
8362 :
8363 750 : FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
8364 : {
8365 15000 : FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
8366 : {
8367 14400 : outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
8368 14400 : move16();
8369 43200 : FOR( dir = 0; dir < numDirs; dir++ )
8370 : {
8371 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 );
8372 28800 : outMeta->directToTotalRatio[dir][sf][band] = (UWord8) L_shr( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], Q22 );
8373 28800 : outMeta->diffuseToTotalRatio[sf][band] = (UWord8) sub( outMeta->diffuseToTotalRatio[sf][band], outMeta->directToTotalRatio[dir][sf][band] );
8374 28800 : outMeta->spreadCoherence[dir][sf][band] = (UWord8) shr( inMeta->directional_meta[dir].spread_coherence_fx[sf][band], Q7 );
8375 :
8376 28800 : move16();
8377 28800 : move16();
8378 28800 : move16();
8379 28800 : move16();
8380 : }
8381 14400 : outMeta->surroundCoherence[sf][band] = (UWord8) shr( inMeta->common_meta.surround_coherence_fx[sf][band], Q7 );
8382 14400 : move16();
8383 : }
8384 : }
8385 :
8386 150 : copy_masa_descriptive_meta_fx( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
8387 :
8388 150 : accumulate2dArrayToBuffer_fx( tmpBuffer_fx, &outAudio );
8389 :
8390 150 : return;
8391 : }
8392 :
8393 18150 : static ivas_error renderInputMasa(
8394 : input_masa *masaInput,
8395 : const AUDIO_CONFIG outConfig,
8396 : IVAS_REND_AudioBuffer outAudio )
8397 : {
8398 : IVAS_REND_AudioBuffer inAudio;
8399 : Word16 ch;
8400 : Word16 maxBin;
8401 : Word32 *tmpBuffer_fx[MAX_OUTPUT_CHANNELS];
8402 : Word32 tmpBuffer_buff_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
8403 : Word16 cldfb2tdShift;
8404 : Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8405 : Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8406 :
8407 18150 : IF( !masaInput->metadataHasBeenFed )
8408 : {
8409 0 : return IVAS_ERR_MISSING_METADATA;
8410 : }
8411 :
8412 18150 : inAudio = masaInput->base.inputBuffer;
8413 :
8414 18150 : cldfb2tdShift = outAudio.config.is_cldfb ? 1 : 0;
8415 18150 : IF( ( NE_32( L_shl( masaInput->base.numNewSamplesPerChannel, cldfb2tdShift ), outAudio.config.numSamplesPerChannel ) ) &&
8416 : NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8417 : {
8418 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" );
8419 : }
8420 18150 : masaInput->base.numNewSamplesPerChannel = 0;
8421 18150 : move32();
8422 :
8423 18150 : *outAudio.pq_fact = outAudio.q_factor;
8424 18150 : move16();
8425 : /* Apply input gain to new audio */
8426 18150 : v_multc_fixed( inAudio.data_fx, masaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
8427 18150 : *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
8428 18150 : move16();
8429 :
8430 18150 : maxBin = extract_l( Mpy_32_32( *masaInput->base.ctx.pOutSampleRate, INV_CLDFB_BANDWIDTH_Q31 ) ); /* Q0 */
8431 :
8432 : /* set combined orientation subframe info to start info */
8433 18150 : ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
8434 :
8435 18150 : IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8436 : {
8437 : /* MASA prerendering path for MASA -> MASA */
8438 150 : renderMasaToMasa( masaInput, outAudio );
8439 : }
8440 : ELSE
8441 : {
8442 : /* MASA external renderer -> other formats */
8443 : Word16 num_subframes, exp;
8444 306000 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
8445 : {
8446 288000 : tmpBuffer_fx[ch] = tmpBuffer_buff_fx[ch];
8447 : }
8448 18000 : copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_buff_fx );
8449 :
8450 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 );
8451 18000 : num_subframes = shr( num_subframes, sub( 15, exp ) ); /* Q0 */
8452 :
8453 18000 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) )
8454 0 : {
8455 : /* split rendering. use the combined of the first subframe in all subframes */
8456 : Word16 sf, i, j;
8457 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
8458 0 : pCombinedOrientationData = *masaInput->base.ctx.pCombinedOrientationData;
8459 0 : FOR( sf = 1; sf < pCombinedOrientationData->num_subframes; sf++ )
8460 : {
8461 0 : Copy_Quat_fx( &pCombinedOrientationData->Quaternions[0], &pCombinedOrientationData->Quaternions[sf] );
8462 0 : FOR( i = 0; i < 3; i++ )
8463 : {
8464 0 : FOR( j = 0; j < 3; j++ )
8465 : {
8466 0 : pCombinedOrientationData->Rmat_fx[sf][i][j] = pCombinedOrientationData->Rmat_fx[0][i][j];
8467 0 : move32();
8468 : }
8469 : }
8470 : }
8471 :
8472 0 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
8473 0 : Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8474 0 : Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8475 : // scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
8476 :
8477 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 );
8478 :
8479 0 : accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
8480 :
8481 0 : *outAudio.pq_fact = Q6;
8482 0 : move16();
8483 : }
8484 : ELSE
8485 : {
8486 : /* non-split path */
8487 18000 : SWITCH( masaInput->hMasaExtRend->renderer_type )
8488 : {
8489 12750 : case RENDERER_DIRAC:
8490 :
8491 12750 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
8492 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 1 );
8493 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
8494 : {
8495 110250 : masaInput->hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state = Q11;
8496 110250 : move16();
8497 : }
8498 216750 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
8499 : {
8500 204000 : Scale_sig32( tmpBuffer_buff_fx[ch], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8501 : }
8502 :
8503 12750 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8504 :
8505 12750 : ivas_masa_ext_dirac_render_fx( masaInput->hMasaExtRend, tmpBuffer_fx, num_subframes );
8506 :
8507 12750 : *outAudio.pq_fact = Q11;
8508 12750 : move16();
8509 :
8510 123000 : FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
8511 : {
8512 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 */
8513 110250 : masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
8514 110250 : move16();
8515 : }
8516 :
8517 12750 : intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 0 );
8518 12750 : BREAK;
8519 4500 : case RENDERER_STEREO_PARAMETRIC:
8520 : case RENDERER_BINAURAL_PARAMETRIC:
8521 : case RENDERER_BINAURAL_PARAMETRIC_ROOM:
8522 :
8523 4500 : copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
8524 :
8525 4500 : Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8526 4500 : Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
8527 :
8528 4500 : scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
8529 :
8530 4500 : ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes, NULL, NULL, NULL );
8531 4500 : *outAudio.pq_fact = Q11;
8532 4500 : move16();
8533 4500 : BREAK;
8534 750 : case RENDERER_DISABLE:
8535 750 : BREAK; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
8536 0 : default:
8537 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
8538 : }
8539 18000 : accumulate2dArrayToBuffer_fx( tmpBuffer_buff_fx, &outAudio );
8540 : }
8541 : }
8542 :
8543 18150 : return IVAS_ERR_OK;
8544 : }
8545 :
8546 :
8547 1126140 : static ivas_error renderActiveInputsMasa(
8548 : IVAS_REND_HANDLE hIvasRend,
8549 : IVAS_REND_AudioBuffer outAudio )
8550 : {
8551 : Word16 i;
8552 : input_masa *pCurrentInput;
8553 : ivas_error error;
8554 :
8555 2252280 : FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMasa ); i < RENDERER_MAX_MASA_INPUTS; ( ++i, ++pCurrentInput ) )
8556 : {
8557 1126140 : IF( EQ_16( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8558 : {
8559 : /* Skip inactive inputs */
8560 1107990 : CONTINUE;
8561 : }
8562 :
8563 18150 : *outAudio.pq_fact = outAudio.q_factor;
8564 18150 : move16();
8565 :
8566 18150 : IF( NE_32( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
8567 : {
8568 0 : return error;
8569 : }
8570 : }
8571 :
8572 1126140 : return IVAS_ERR_OK;
8573 : }
8574 :
8575 :
8576 : /*---------------------------------------------------------------------*
8577 : * IVAS_REND_GetMasaMetadata( )
8578 : *
8579 : * Get metadata of the estimated MASA frame
8580 : *---------------------------------------------------------------------*/
8581 :
8582 0 : ivas_error IVAS_REND_GetMasaMetadata(
8583 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8584 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to analyzed MASA metadata */
8585 : const IVAS_REND_AudioConfigType inputType /* i : Input type */
8586 : )
8587 : {
8588 0 : IF( hIvasRend == NULL )
8589 : {
8590 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8591 : }
8592 :
8593 : /* Get the metadata handle */
8594 0 : IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
8595 : {
8596 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
8597 : }
8598 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
8599 : {
8600 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
8601 : }
8602 0 : ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
8603 : {
8604 0 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
8605 : }
8606 : ELSE
8607 : {
8608 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
8609 : }
8610 :
8611 0 : return IVAS_ERR_OK;
8612 : }
8613 :
8614 :
8615 : /*---------------------------------------------------------------------*
8616 : * IVAS_REND_MergeMasaMetadata( )
8617 : *
8618 : * Merge MASA metadata from two formats
8619 : *---------------------------------------------------------------------*/
8620 :
8621 450 : ivas_error IVAS_REND_MergeMasaMetadata(
8622 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8623 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to merged metadata */
8624 : const IVAS_REND_AudioConfigType inputType1, /* i : Input type 1 */
8625 : const IVAS_REND_AudioConfigType inputType2 /* i : Input type 2 */
8626 : )
8627 : {
8628 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
8629 : Word32( *inEne1_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8630 : Word32( *inEne2_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8631 : Word16( *inEne1_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8632 : Word16( *inEne2_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
8633 :
8634 450 : IF( hIvasRend == NULL )
8635 : {
8636 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8637 : }
8638 :
8639 : /* Input1 metadata and energy */
8640 450 : IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
8641 : {
8642 :
8643 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
8644 0 : inEne1_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
8645 0 : inEne1_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
8646 : }
8647 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
8648 : {
8649 :
8650 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
8651 0 : inEne1_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
8652 0 : inEne1_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
8653 : }
8654 450 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
8655 : {
8656 :
8657 450 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
8658 450 : inEne1_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
8659 450 : inEne1_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
8660 : }
8661 0 : ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8662 : {
8663 :
8664 0 : *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
8665 0 : inEne1_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
8666 0 : inEne1_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
8667 : }
8668 : ELSE
8669 : {
8670 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
8671 : }
8672 :
8673 : /* Input2 metadata and energy */
8674 450 : IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
8675 : {
8676 150 : inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
8677 150 : inEne2_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
8678 150 : inEne2_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
8679 : }
8680 300 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
8681 : {
8682 150 : inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
8683 150 : inEne2_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
8684 150 : inEne2_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
8685 : }
8686 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
8687 : {
8688 0 : inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
8689 0 : inEne2_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
8690 0 : inEne2_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
8691 : }
8692 150 : ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8693 : {
8694 :
8695 150 : inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
8696 150 : inEne2_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
8697 150 : inEne2_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
8698 : }
8699 : ELSE
8700 : {
8701 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
8702 : }
8703 :
8704 : /* Merge metadata */
8705 450 : ivas_prerend_merge_masa_metadata_fx( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1_fx, *inEne1_e, inMeta2, inputType2, *inEne2_fx, *inEne2_e );
8706 :
8707 :
8708 450 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
8709 : {
8710 0 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 0u;
8711 0 : move16();
8712 : }
8713 : ELSE
8714 : {
8715 450 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 1u;
8716 450 : move16();
8717 : }
8718 :
8719 450 : return IVAS_ERR_OK;
8720 : }
8721 :
8722 :
8723 : /*---------------------------------------------------------------------*
8724 : * IVAS_REND_SetTotalNumberOfObjects( )
8725 : *
8726 : * Set the total number of objects to the first object data
8727 : *---------------------------------------------------------------------*/
8728 :
8729 182 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
8730 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8731 : const UWord16 total_num_objects /* i : total number of objects */
8732 : )
8733 : {
8734 182 : IF( hIvasRend == NULL )
8735 : {
8736 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8737 : }
8738 :
8739 182 : hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
8740 182 : move16();
8741 :
8742 182 : return IVAS_ERR_OK;
8743 : }
8744 :
8745 :
8746 : /*---------------------------------------------------------------------*
8747 : * IVAS_REND_SetIsmMetadataDelay( )
8748 : *
8749 : * Set the Metadata Delay in ms in order to sync with audio delay
8750 : *---------------------------------------------------------------------*/
8751 :
8752 182 : ivas_error IVAS_REND_SetIsmMetadataDelay(
8753 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8754 : const Word32 sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */
8755 : )
8756 : {
8757 : Word16 i;
8758 :
8759 182 : IF( hIvasRend == NULL )
8760 : {
8761 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8762 : }
8763 910 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8764 : {
8765 728 : hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay;
8766 728 : move32();
8767 : }
8768 :
8769 182 : return IVAS_ERR_OK;
8770 : }
8771 :
8772 :
8773 : /*-------------------------------------------------------------------*
8774 : * getSamplesInternal()
8775 : *
8776 : *
8777 : *-------------------------------------------------------------------*/
8778 :
8779 1126140 : static ivas_error getSamplesInternal(
8780 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
8781 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
8782 : IVAS_REND_BitstreamBuffer *hBits /* i/o: buffer for input/output bitstream. Needed in split rendering */
8783 : )
8784 : {
8785 : ivas_error error;
8786 : Word16 numOutChannels;
8787 : Word16 cldfb2tdSampleShift;
8788 : IVAS_REND_AudioBuffer outAudioOrig;
8789 :
8790 : /* Validate function arguments */
8791 1126140 : test();
8792 1126140 : IF( hIvasRend == NULL || outAudio.data_fx == NULL )
8793 : {
8794 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8795 : }
8796 :
8797 1126140 : test();
8798 1126140 : cldfb2tdSampleShift = ( outAudio.config.is_cldfb ) ? 1 : 0;
8799 :
8800 1126140 : IF( outAudio.config.numSamplesPerChannel <= 0 || ( MAX_BUFFER_LENGTH_PER_CHANNEL < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
8801 : ( ( shl( MAX_BUFFER_LENGTH_PER_CHANNEL, cldfb2tdSampleShift ) ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
8802 : {
8803 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
8804 : }
8805 :
8806 1126140 : test();
8807 1126140 : IF( LE_16( outAudio.config.numChannels, 0 ) || LT_16( MAX_OUTPUT_CHANNELS, outAudio.config.numChannels ) )
8808 : {
8809 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
8810 : }
8811 :
8812 1126140 : test();
8813 1126140 : test();
8814 1126140 : test();
8815 1126140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
8816 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) &&
8817 : NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) &&
8818 : NE_32( L_shr( L_mult0( outAudio.config.numSamplesPerChannel, 1000 ), cldfb2tdSampleShift ),
8819 : imult3216( hIvasRend->sampleRateOut, i_mult( hIvasRend->num_subframes, BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ) )
8820 : {
8821 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
8822 : }
8823 :
8824 : /* Check that there is allowed configuration for MASA format output */
8825 1126140 : IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
8826 : {
8827 : Word16 i;
8828 150 : Word16 numMasaInputs = 0;
8829 150 : move16();
8830 150 : Word16 numOtherInputs = 0;
8831 150 : move16();
8832 :
8833 300 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
8834 : {
8835 : // numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8836 :
8837 150 : IF( EQ_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8838 : {
8839 0 : numMasaInputs = add( numMasaInputs, 0 );
8840 : }
8841 : ELSE
8842 : {
8843 150 : numMasaInputs = add( numMasaInputs, 1 );
8844 : }
8845 : }
8846 :
8847 300 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
8848 : {
8849 : // numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8850 :
8851 150 : IF( EQ_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8852 : {
8853 0 : numOtherInputs = add( numOtherInputs, 0 );
8854 : }
8855 : ELSE
8856 : {
8857 150 : numOtherInputs = add( numOtherInputs, 1 );
8858 : }
8859 : }
8860 :
8861 300 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
8862 : {
8863 : // numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8864 :
8865 150 : IF( EQ_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8866 : {
8867 0 : numOtherInputs = add( numOtherInputs, 0 );
8868 : }
8869 : ELSE
8870 : {
8871 150 : numOtherInputs = add( numOtherInputs, 1 );
8872 : }
8873 : }
8874 :
8875 : /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
8876 : // numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8877 150 : IF( EQ_32( hIvasRend->inputsIsm[0].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8878 : {
8879 0 : numOtherInputs = add( numOtherInputs, 0 );
8880 : }
8881 : ELSE
8882 : {
8883 150 : numOtherInputs = add( numOtherInputs, 1 );
8884 : }
8885 :
8886 150 : test();
8887 150 : IF( numMasaInputs == 0 || numOtherInputs == 0 )
8888 : {
8889 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
8890 : }
8891 : }
8892 :
8893 1126140 : IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
8894 : {
8895 0 : return error;
8896 : }
8897 :
8898 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 ) )
8899 : {
8900 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
8901 : }
8902 :
8903 : /* Clear original output buffer */
8904 1126140 : set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) );
8905 :
8906 1126140 : outAudioOrig = outAudio;
8907 :
8908 : /* Use internal buffer if outputting split rendering bitstream */
8909 1126140 : test();
8910 1126140 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
8911 : EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8912 : {
8913 : Word16 num_poses_orig;
8914 0 : num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
8915 0 : move16();
8916 0 : outAudio.config = hIvasRend->splitRendEncBuffer.config;
8917 0 : outAudio.data_fx = hIvasRend->splitRendEncBuffer.data_fx;
8918 :
8919 0 : ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis );
8920 :
8921 0 : assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" );
8922 :
8923 : /* Clear output buffer for split rendering bitstream */
8924 0 : set32_fx( outAudio.data_fx, 0, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
8925 : }
8926 :
8927 1126140 : IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
8928 : {
8929 0 : return error;
8930 : }
8931 1126140 : IF( NE_32( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
8932 : {
8933 0 : return error;
8934 : }
8935 1126140 : IF( NE_32( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
8936 : {
8937 0 : return error;
8938 : }
8939 1126140 : IF( NE_32( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
8940 : {
8941 0 : return error;
8942 : }
8943 :
8944 1126140 : test();
8945 1126140 : IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
8946 : {
8947 : ISAR_SPLIT_REND_BITS_DATA bits;
8948 : Word16 cldfb_in_flag, i, j, k, ch, ro_md_flag;
8949 : Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8950 : Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8951 :
8952 0 : FOR( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; i++ )
8953 : {
8954 0 : FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ )
8955 : {
8956 0 : FOR( k = 0; k < CLDFB_NO_CHANNELS_MAX; k++ )
8957 : {
8958 0 : Cldfb_RealBuffer_Binaural[i][j][k] = 0;
8959 0 : Cldfb_ImagBuffer_Binaural[i][j][k] = 0;
8960 0 : move32();
8961 0 : move32();
8962 : }
8963 : }
8964 : }
8965 :
8966 : Word32 *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
8967 :
8968 0 : FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
8969 : {
8970 0 : tmpBinaural[ch] = tmpBinaural_buff[ch];
8971 0 : move32();
8972 : }
8973 :
8974 0 : IF( EQ_16( outAudio.config.is_cldfb, 1 ) )
8975 : {
8976 0 : cldfb_in_flag = 1;
8977 0 : move16();
8978 0 : copyBufferToCLDFBarray_fx( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
8979 : }
8980 : ELSE
8981 : {
8982 0 : cldfb_in_flag = 0;
8983 0 : move16();
8984 0 : copyBufferTo2dArray_fx( outAudio, tmpBinaural_buff );
8985 : }
8986 :
8987 : /* Encode split rendering bitstream */
8988 0 : convertBitsBufferToInternalBitsBuff( *hBits, &bits );
8989 :
8990 0 : ro_md_flag = 0;
8991 0 : move16();
8992 0 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8993 : {
8994 0 : IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
8995 : {
8996 0 : ro_md_flag = 1;
8997 0 : move16();
8998 0 : break;
8999 : }
9000 : }
9001 :
9002 0 : Word16 q1 = 31, q2 = 31, Q_buff;
9003 : Word16 Q_out[CLDFB_NO_COL_MAX];
9004 0 : Q_out[0] = 31;
9005 0 : Word16 num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
9006 :
9007 0 : for ( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ )
9008 : {
9009 0 : for ( j = 0; j < CLDFB_NO_COL_MAX; j++ )
9010 : {
9011 0 : q1 = s_min( q1, L_norm_arr( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) );
9012 0 : q2 = s_min( q2, L_norm_arr( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) );
9013 : }
9014 : }
9015 0 : Q_buff = s_min( q1, q2 );
9016 0 : for ( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ )
9017 : {
9018 0 : for ( j = 0; j < CLDFB_NO_COL_MAX; j++ )
9019 : {
9020 0 : scale_sig32( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff );
9021 0 : scale_sig32( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff );
9022 : }
9023 : }
9024 0 : Q_buff = Q_buff + *outAudio.pq_fact;
9025 :
9026 0 : IF( EQ_16( cldfb_in_flag, 0 ) )
9027 : {
9028 : /*TD input*/
9029 0 : num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
9030 :
9031 0 : FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
9032 : {
9033 0 : Q_out[0] = s_min( Q_out[0], L_norm_arr( tmpBinaural_buff[i], L_FRAME48k ) );
9034 : }
9035 :
9036 0 : FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
9037 : {
9038 0 : scale_sig32( tmpBinaural_buff[i], L_FRAME48k, Q_out[0] );
9039 : }
9040 :
9041 0 : Q_out[0] = Q_out[0] + *outAudio.pq_fact;
9042 : }
9043 :
9044 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,
9045 0 : hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms,
9046 0 : hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms,
9047 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 )
9048 : {
9049 0 : return error;
9050 : }
9051 :
9052 0 : Word16 pcm_out_flag = ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0;
9053 0 : IF( NE_16( pcm_out_flag, 0 ) )
9054 : {
9055 0 : FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
9056 : {
9057 0 : scale_sig32( tmpBinaural_buff[j], L_FRAME48k, sub( *outAudio.pq_fact, Q_out[j] ) ); // *outAudio.pq_fact
9058 : }
9059 : }
9060 :
9061 0 : convertInternalBitsBuffToBitsBuffer( hBits, bits );
9062 :
9063 : /* reset to outAudioOrig in case of PCM output */
9064 0 : outAudio.config = outAudioOrig.config;
9065 0 : outAudio.data_fx = outAudioOrig.data_fx;
9066 :
9067 0 : IF( NE_16( pcm_out_flag, 0 ) )
9068 : {
9069 0 : accumulate2dArrayToBuffer_fx( tmpBinaural_buff, &outAudio );
9070 : }
9071 : }
9072 :
9073 1126140 : if ( outAudio.config.is_cldfb == 0 )
9074 : {
9075 1126140 : Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact );
9076 : #ifndef DISABLE_LIMITER
9077 1126140 : limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact );
9078 : #endif
9079 : }
9080 :
9081 : /* update global cominbed orientation start index */
9082 1126140 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
9083 :
9084 1126140 : return IVAS_ERR_OK;
9085 : }
9086 :
9087 :
9088 : /*-------------------------------------------------------------------*
9089 : * IVAS_REND_GetSamples()
9090 : *
9091 : *
9092 : *-------------------------------------------------------------------*/
9093 :
9094 1126140 : ivas_error IVAS_REND_GetSamples(
9095 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
9096 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
9097 : )
9098 : {
9099 1126140 : return getSamplesInternal( hIvasRend, outAudio, NULL );
9100 : }
9101 :
9102 :
9103 : /*-------------------------------------------------------------------*
9104 : * IVAS_REND_GetSplitBinauralBitstream()
9105 : *
9106 : *
9107 : *-------------------------------------------------------------------*/
9108 :
9109 0 : ivas_error IVAS_REND_GetSplitBinauralBitstream(
9110 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
9111 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
9112 : IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */
9113 : )
9114 : {
9115 : Word16 cldfb_in_flag;
9116 :
9117 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
9118 0 : hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag;
9119 :
9120 0 : if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
9121 : {
9122 0 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
9123 : }
9124 : else
9125 : {
9126 0 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (Word16) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
9127 : }
9128 :
9129 0 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
9130 :
9131 : /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output
9132 : outAudio used for BINAURAL_SPLIT_PCM output */
9133 0 : return getSamplesInternal( hIvasRend, outAudio, hBits );
9134 : }
9135 :
9136 :
9137 : /*-------------------------------------------------------------------*
9138 : * IVAS_REND_GetSplitRendBitstreamHeader()
9139 : *
9140 : *
9141 : *-------------------------------------------------------------------*/
9142 :
9143 0 : ivas_error IVAS_REND_GetSplitRendBitstreamHeader(
9144 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9145 : ISAR_SPLIT_REND_CODEC *pCodec, /* o : pointer to codec setting */
9146 : ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o : pointer to pose correction mode */
9147 : Word16 *pCodec_frame_size_ms, /* o : pointer to codec frame size setting */
9148 : Word16 *pIsar_frame_size_ms /* o : pointer to ISAR frame size setting */
9149 : )
9150 : {
9151 0 : test();
9152 0 : IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
9153 : {
9154 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
9155 : }
9156 :
9157 0 : *pCodec = hIvasRend->hRendererConfig->split_rend_config.codec;
9158 0 : *pCodec_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms;
9159 0 : *pIsar_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms;
9160 0 : *poseCorrection = hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode;
9161 :
9162 0 : return IVAS_ERR_OK;
9163 : }
9164 :
9165 :
9166 : /*-------------------------------------------------------------------*
9167 : * IVAS_REND_Close()
9168 : *
9169 : *
9170 : *-------------------------------------------------------------------*/
9171 :
9172 666 : void IVAS_REND_Close(
9173 : IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
9174 : )
9175 : {
9176 : UWord16 i;
9177 : IVAS_REND_HANDLE hIvasRend;
9178 :
9179 : /* Validate function arguments */
9180 666 : test();
9181 666 : IF( phIvasRend == NULL || *phIvasRend == NULL )
9182 : {
9183 0 : return;
9184 : }
9185 666 : hIvasRend = *phIvasRend;
9186 :
9187 666 : IF( hIvasRend->efapOutWrapper.hEfap != NULL )
9188 : {
9189 471 : efap_free_data_fx( &hIvasRend->efapOutWrapper.hEfap );
9190 : }
9191 :
9192 : /* clear inputs */
9193 3330 : FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
9194 : {
9195 2664 : clearInputIsm( &hIvasRend->inputsIsm[i] );
9196 : }
9197 1332 : FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
9198 : {
9199 666 : clearInputMc( &hIvasRend->inputsMc[i] );
9200 : }
9201 1332 : FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
9202 : {
9203 666 : clearInputSba( &hIvasRend->inputsSba[i] );
9204 : }
9205 1332 : FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
9206 : {
9207 666 : clearInputMasa( &hIvasRend->inputsMasa[i] );
9208 : }
9209 :
9210 : /* clear Config. Renderer */
9211 666 : ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
9212 :
9213 666 : ivas_limiter_close_fx( &hIvasRend->hLimiter );
9214 :
9215 : /* Split binaural rendering */
9216 666 : IF( hIvasRend->splitRendWrapper != NULL )
9217 : {
9218 0 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
9219 0 : free( hIvasRend->splitRendWrapper );
9220 0 : hIvasRend->splitRendWrapper = NULL;
9221 : }
9222 :
9223 666 : closeHeadRotation( hIvasRend );
9224 :
9225 666 : ivas_external_orientation_close_fx( &hIvasRend->hExternalOrientationData );
9226 666 : ivas_combined_orientation_close_fx( &hIvasRend->hCombinedOrientationData );
9227 :
9228 : /* Fastconv HRTF memories */
9229 666 : ivas_binaural_hrtf_close( &hIvasRend->hHrtfs.hHrtfFastConv );
9230 :
9231 : /* Parametric binauralizer HRTF filters */
9232 666 : ivas_HRTF_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfTD ) );
9233 666 : ivas_HRTF_CRend_binary_close_fx( &( hIvasRend->hHrtfs.hSetOfHRTF ) );
9234 666 : ivas_HRTF_fastconv_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfFastConv ) );
9235 666 : ivas_HRTF_parambin_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfParambin ) );
9236 666 : ivas_HRTF_statistics_close( &( hIvasRend->hHrtfs.hHrtfStatistics ) );
9237 :
9238 666 : free( hIvasRend );
9239 666 : *phIvasRend = NULL;
9240 :
9241 666 : return;
9242 : }
9243 :
9244 : /*-------------------------------------------------------------------*
9245 : * IVAS_REND_openCldfb()
9246 : *
9247 : *
9248 : *-------------------------------------------------------------------*/
9249 :
9250 0 : ivas_error IVAS_REND_openCldfb(
9251 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
9252 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS],
9253 : const Word16 num_in_chs,
9254 : const Word16 num_out_chs,
9255 : const Word32 output_Fs )
9256 : {
9257 : Word16 n;
9258 : ivas_error error;
9259 :
9260 0 : FOR( n = 0; n < num_in_chs; n++ )
9261 : {
9262 0 : IF( ( error = openCldfb_ivas_fx( &( cldfbAna[n] ), CLDFB_ANALYSIS, output_Fs, CLDFB_PROTOTYPE_5_00MS, DEC ) ) != IVAS_ERR_OK )
9263 : {
9264 0 : return error;
9265 : }
9266 : }
9267 0 : FOR( ; n < IVAS_MAX_INPUT_CHANNELS; n++ )
9268 : {
9269 0 : cldfbAna[n] = NULL;
9270 : }
9271 :
9272 0 : FOR( n = 0; n < num_out_chs; n++ )
9273 : {
9274 0 : IF( ( error = openCldfb_ivas_fx( &( cldfbSyn[n] ), CLDFB_SYNTHESIS, output_Fs, CLDFB_PROTOTYPE_5_00MS, DEC ) ) != IVAS_ERR_OK )
9275 : {
9276 0 : return error;
9277 : }
9278 : }
9279 0 : FOR( ; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
9280 : {
9281 0 : cldfbSyn[n] = NULL;
9282 : }
9283 :
9284 0 : return IVAS_ERR_OK;
9285 : }
9286 :
9287 :
9288 : /*-------------------------------------------------------------------*
9289 : * IVAS_REND_closeCldfb()
9290 : *
9291 : *
9292 : *-------------------------------------------------------------------*/
9293 :
9294 0 : void IVAS_REND_closeCldfb(
9295 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
9296 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS] )
9297 : {
9298 : Word16 n;
9299 :
9300 0 : FOR( n = 0; n < IVAS_MAX_INPUT_CHANNELS; n++ )
9301 : {
9302 0 : IF( cldfbAna[n] != NULL )
9303 : {
9304 0 : deleteCldfb_ivas_fx( &( cldfbAna[n] ) );
9305 0 : cldfbAna[n] = NULL;
9306 : }
9307 : }
9308 :
9309 0 : FOR( n = 0; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
9310 : {
9311 0 : IF( cldfbSyn[n] != NULL )
9312 : {
9313 0 : deleteCldfb_ivas_fx( &( cldfbSyn[n] ) );
9314 0 : cldfbSyn[n] = NULL;
9315 : }
9316 : }
9317 :
9318 0 : return;
9319 : }
9320 :
9321 :
9322 : /*-------------------------------------------------------------------*
9323 : * IVAS_REND_cldfbSynthesis_wrapper()
9324 : *
9325 : *
9326 : *-------------------------------------------------------------------*/
9327 :
9328 0 : void IVAS_REND_cldfbAnalysis_ts_wrapper(
9329 : const Word32 *timeIn, /* i : time buffer */
9330 : Word32 realBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : real value buffer */
9331 : Word32 imagBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : imag value buffer */
9332 : const Word16 samplesToProcess, /* i : samples to process */
9333 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb, /* i : filterbank state */
9334 : Word16 Q_in,
9335 : Word16 *Q_out )
9336 : {
9337 :
9338 0 : Word16 Q_cldfb = Q_in;
9339 0 : assert( Q_in == h_cldfb->Q_cldfb_state );
9340 0 : cldfbAnalysis_ts_fx_fixed_q( timeIn, realBuffer, imagBuffer, samplesToProcess, h_cldfb, &Q_cldfb );
9341 :
9342 0 : *Q_out = sub( Q_in, 5 );
9343 :
9344 0 : return;
9345 : }
9346 :
9347 :
9348 : /*-------------------------------------------------------------------*
9349 : * IVAS_REND_cldfbSynthesis_wrapper()
9350 : *
9351 : *
9352 : *-------------------------------------------------------------------*/
9353 :
9354 0 : void IVAS_REND_cldfbSynthesis_wrapper(
9355 : Word32 **realBuffer, /* i : real values */
9356 : Word32 **imagBuffer, /* i : imag values */
9357 : Word32 *timeOut, /* o : output time domain samples */
9358 : const Word16 samplesToProcess, /* i : number of processed samples */
9359 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb, /* i : filter bank state */
9360 : Word16 Q_cldfb,
9361 : Word16 *Q_out )
9362 : {
9363 :
9364 0 : Scale_sig32( h_cldfb->cldfb_state_fx, h_cldfb->p_filter_length, sub( sub( Q_cldfb, 1 ), h_cldfb->Q_cldfb_state ) );
9365 0 : cldfbSynthesis_ivas_fx( realBuffer, imagBuffer, timeOut, samplesToProcess, 0, 0, h_cldfb ); // Q_cldfb - 1
9366 0 : *Q_out = sub( Q_cldfb, 1 );
9367 0 : move16();
9368 0 : h_cldfb->Q_cldfb_state = *Q_out;
9369 0 : move16();
9370 :
9371 0 : return;
9372 : }
9373 :
9374 :
9375 : /*---------------------------------------------------------------------*
9376 : * IVAS_REND_GetHrtfHandle( )
9377 : *
9378 : *
9379 : *---------------------------------------------------------------------*/
9380 :
9381 0 : ivas_error IVAS_REND_GetHrtfHandle(
9382 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9383 : IVAS_DEC_HRTF_HANDLE **hHrtfTD /* o : HRTF handle */
9384 : )
9385 : {
9386 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfTD == NULL )
9387 : {
9388 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
9389 : }
9390 :
9391 0 : *hHrtfTD = &hIvasRend->hHrtfs.hHrtfTD;
9392 :
9393 0 : return IVAS_ERR_OK;
9394 : }
9395 :
9396 :
9397 : /*---------------------------------------------------------------------*
9398 : * IVAS_REND_GetHrtfCRendHandle( )
9399 : *
9400 : *
9401 : *---------------------------------------------------------------------*/
9402 :
9403 0 : ivas_error IVAS_REND_GetHrtfCRendHandle(
9404 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9405 : IVAS_DEC_HRTF_CREND_HANDLE **hSetOfHRTF /* o : Set of HRTF handle */
9406 : )
9407 : {
9408 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hSetOfHRTF == NULL )
9409 : {
9410 0 : return IVAS_ERR_WRONG_PARAMS;
9411 : }
9412 :
9413 0 : *hSetOfHRTF = &hIvasRend->hHrtfs.hSetOfHRTF;
9414 :
9415 0 : return IVAS_ERR_OK;
9416 : }
9417 :
9418 :
9419 : /*---------------------------------------------------------------------*
9420 : * IVAS_REND_GetHrtfFastConvHandle( )
9421 : *
9422 : *
9423 : *---------------------------------------------------------------------*/
9424 :
9425 0 : ivas_error IVAS_REND_GetHrtfFastConvHandle(
9426 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9427 : IVAS_DEC_HRTF_FASTCONV_HANDLE **hHrtfFastConv /* o : FASTCONV HRTF handle */
9428 : )
9429 : {
9430 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfFastConv == NULL )
9431 : {
9432 0 : return IVAS_ERR_WRONG_PARAMS;
9433 : }
9434 :
9435 0 : *hHrtfFastConv = &hIvasRend->hHrtfs.hHrtfFastConv;
9436 :
9437 0 : return IVAS_ERR_OK;
9438 : }
9439 :
9440 :
9441 : /*---------------------------------------------------------------------*
9442 : * IVAS_REND_GetHrtfParamBinHandle( )
9443 : *
9444 : *
9445 : *---------------------------------------------------------------------*/
9446 :
9447 0 : ivas_error IVAS_REND_GetHrtfParamBinHandle(
9448 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9449 : IVAS_DEC_HRTF_PARAMBIN_HANDLE **hHrtfParambin /* o : Parametric binauralizer HRTF handle */
9450 : )
9451 : {
9452 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfParambin == NULL )
9453 : {
9454 0 : return IVAS_ERR_WRONG_PARAMS;
9455 : }
9456 :
9457 0 : *hHrtfParambin = &hIvasRend->hHrtfs.hHrtfParambin;
9458 :
9459 0 : return IVAS_ERR_OK;
9460 : }
9461 :
9462 :
9463 : /*---------------------------------------------------------------------*
9464 : * IVAS_REND_GetHrtfStatisticsHandle( )
9465 : *
9466 : *
9467 : *---------------------------------------------------------------------*/
9468 :
9469 0 : ivas_error IVAS_REND_GetHrtfStatisticsHandle(
9470 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
9471 : IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */
9472 : )
9473 : {
9474 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfStatistics == NULL )
9475 : {
9476 0 : return IVAS_ERR_WRONG_PARAMS;
9477 : }
9478 :
9479 0 : *hHrtfStatistics = &hIvasRend->hHrtfs.hHrtfStatistics;
9480 :
9481 0 : return IVAS_ERR_OK;
9482 : }
9483 :
9484 34 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
9485 : input_masa *inputMasa )
9486 : {
9487 : Word16 nchan_out_woLFE;
9488 : Word16 nchan_transport;
9489 : UWord16 i, j, k;
9490 : Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
9491 : Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
9492 : Word32 output_Fs;
9493 : ivas_error error;
9494 : DIRAC_REND_HANDLE hDirACRend;
9495 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
9496 :
9497 34 : error = IVAS_ERR_OK;
9498 34 : move32();
9499 :
9500 34 : hDirACRend = NULL;
9501 34 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
9502 34 : move32();
9503 :
9504 34 : hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
9505 :
9506 : /*-----------------------------------------------------------------*
9507 : * prepare library opening
9508 : *-----------------------------------------------------------------*/
9509 :
9510 34 : IF( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
9511 : {
9512 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
9513 : }
9514 :
9515 34 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
9516 : {
9517 18 : nchan_transport = 2;
9518 18 : move16();
9519 : }
9520 : ELSE
9521 : {
9522 16 : nchan_transport = 1;
9523 16 : move16();
9524 : }
9525 :
9526 : /*-----------------------------------------------------------------*
9527 : * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
9528 : *-----------------------------------------------------------------*/
9529 :
9530 34 : ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
9531 :
9532 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
9533 : {
9534 : /* Copy from ivas_ls_custom_setup */
9535 0 : hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
9536 0 : move16();
9537 0 : hDirACRend->hOutSetup.ls_azimuth_fx = inputMasa->base.ctx.pCustomLsOut->ls_azimuth_fx;
9538 0 : hDirACRend->hOutSetup.ls_elevation_fx = inputMasa->base.ctx.pCustomLsOut->ls_elevation_fx;
9539 :
9540 0 : hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
9541 0 : move16();
9542 0 : hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
9543 0 : move16();
9544 :
9545 0 : hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
9546 0 : move16();
9547 0 : hDirACRend->hOutSetup.is_planar_setup = (Word8) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
9548 0 : move16();
9549 : }
9550 :
9551 34 : nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
9552 34 : move16();
9553 :
9554 34 : test();
9555 34 : IF( hDirACRend->hOutSetup.ls_azimuth_fx != NULL && hDirACRend->hOutSetup.ls_elevation_fx != NULL )
9556 : {
9557 20 : Copy32( hDirACRend->hOutSetup.ls_azimuth_fx, ls_azimuth_fx, nchan_out_woLFE );
9558 20 : Copy32( hDirACRend->hOutSetup.ls_elevation_fx, ls_elevation_fx, nchan_out_woLFE );
9559 : }
9560 :
9561 34 : IF( EQ_16( hDirACRend->hOutSetup.ambisonics_order, -1 ) )
9562 : {
9563 22 : hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
9564 22 : move16();
9565 22 : test();
9566 22 : if ( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_STEREO ) )
9567 : {
9568 2 : hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
9569 2 : move16();
9570 : }
9571 : }
9572 12 : ELSE IF( GE_16( hDirACRend->hOutSetup.ambisonics_order, SBA_FOA_ORDER ) )
9573 : {
9574 12 : Copy32( ls_azimuth_4d4_fx, ls_azimuth_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
9575 12 : Copy32( ls_elevation_4d4_fx, ls_elevation_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
9576 : }
9577 :
9578 : /*-----------------------------------------------------------------*
9579 : * set input parameters
9580 : *-----------------------------------------------------------------*/
9581 :
9582 34 : test();
9583 34 : IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
9584 : {
9585 2 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
9586 2 : move32();
9587 2 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
9588 2 : move32();
9589 2 : nchan_out_woLFE = 1;
9590 2 : move16();
9591 : }
9592 32 : ELSE IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
9593 : {
9594 20 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
9595 20 : hDirACRend->panningConf = DIRAC_PANNING_VBAP;
9596 20 : move32();
9597 20 : move32();
9598 : }
9599 12 : ELSE IF( !hDirACRend->hOutSetup.is_loudspeaker_setup && GT_16( nchan_transport, 1 ) )
9600 : {
9601 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
9602 6 : move32();
9603 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
9604 6 : move32();
9605 : }
9606 : ELSE
9607 : {
9608 6 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
9609 6 : move32();
9610 6 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
9611 6 : move32();
9612 : }
9613 :
9614 34 : IF( ( hDirACRend->frequency_axis_fx = (Word16 *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( Word16 ) ) ) == NULL )
9615 : {
9616 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9617 : }
9618 34 : set16_fx( hDirACRend->frequency_axis_fx, 0, hSpatParamRendCom->num_freq_bands );
9619 34 : ivas_dirac_dec_get_frequency_axis_fx( hDirACRend->frequency_axis_fx, output_Fs, hSpatParamRendCom->num_freq_bands );
9620 :
9621 34 : test();
9622 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) && EQ_16( nchan_transport, 2 ) )
9623 : {
9624 8 : IF( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
9625 : {
9626 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9627 : }
9628 8 : ivas_masa_init_stereotype_detection_fx( hDirACRend->masa_stereo_type_detect );
9629 : }
9630 : ELSE
9631 : {
9632 26 : hDirACRend->masa_stereo_type_detect = NULL;
9633 : }
9634 :
9635 34 : hSpatParamRendCom->numIsmDirections = 0;
9636 34 : move16();
9637 :
9638 : /*-----------------------------------------------------------------*
9639 : * (re)configure sub-modules
9640 : *-----------------------------------------------------------------*/
9641 :
9642 : /* prototype signal computation */
9643 : /* allocate output setup related arrays */
9644 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
9645 : {
9646 : /* Directional and diffuses components in output LS format */
9647 20 : hDirACRend->num_outputs_diff = nchan_out_woLFE;
9648 20 : move16();
9649 20 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
9650 20 : move16();
9651 : }
9652 14 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9653 : {
9654 : /* Directional and diffuses components in SHD */
9655 : /* Diffuseness components up to 1st order */
9656 6 : hDirACRend->num_outputs_diff = imult1616( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ), ( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ) ) );
9657 6 : hDirACRend->num_outputs_dir = ivas_sba_get_nchan_fx( hDirACRend->hOutSetup.ambisonics_order, 0 );
9658 : }
9659 8 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
9660 : {
9661 6 : hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
9662 6 : move16();
9663 6 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
9664 6 : move16();
9665 : }
9666 2 : ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
9667 : {
9668 2 : hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
9669 2 : move16();
9670 2 : hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
9671 2 : move16();
9672 : }
9673 : ELSE
9674 : {
9675 0 : assert( 0 && "DirAC: not existing synthesis methods!" );
9676 : }
9677 :
9678 34 : IF( ( hDirACRend->proto_index_dir = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
9679 : {
9680 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9681 : }
9682 :
9683 34 : IF( ( hDirACRend->proto_index_diff = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_diff ) ) == NULL )
9684 : {
9685 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9686 : }
9687 :
9688 34 : set16_fx( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
9689 34 : set16_fx( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
9690 :
9691 34 : hDirACRend->sba_map_tc = sba_map_tc;
9692 :
9693 34 : IF( EQ_16( nchan_transport, 1 ) )
9694 : {
9695 16 : hDirACRend->num_protos_ambi = 1;
9696 16 : move16();
9697 16 : hDirACRend->num_protos_dir = 1;
9698 16 : move16();
9699 16 : hDirACRend->num_protos_diff = 1;
9700 16 : move16();
9701 : }
9702 18 : ELSE IF( EQ_16( nchan_transport, 2 ) )
9703 : {
9704 18 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9705 : {
9706 0 : hDirACRend->num_protos_ambi = 2;
9707 0 : move16();
9708 0 : hDirACRend->num_protos_diff = 1;
9709 0 : move16();
9710 0 : hDirACRend->num_protos_dir = 2;
9711 0 : move16();
9712 0 : hDirACRend->proto_index_dir[1] = 1;
9713 0 : move16();
9714 : }
9715 18 : ELSE IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
9716 : {
9717 : /* Following the foa rendering for code compatibility */
9718 2 : hDirACRend->num_protos_ambi = 2;
9719 2 : move16();
9720 2 : hDirACRend->num_protos_dir = 2;
9721 2 : move16();
9722 2 : hDirACRend->num_protos_diff = 3;
9723 2 : move16();
9724 2 : hDirACRend->proto_index_dir[0] = 0;
9725 2 : move16();
9726 2 : hDirACRend->proto_index_diff[0] = 0;
9727 2 : move16();
9728 : }
9729 : ELSE
9730 : {
9731 16 : hDirACRend->num_protos_ambi = 2;
9732 16 : move16();
9733 16 : hDirACRend->num_protos_diff = 3;
9734 16 : move16();
9735 :
9736 142 : FOR( k = 0; k < hDirACRend->num_outputs_diff; k++ )
9737 : {
9738 126 : IF( ls_azimuth_fx[k] > 0 )
9739 : {
9740 58 : hDirACRend->proto_index_diff[k] = 1;
9741 : }
9742 68 : ELSE IF( ls_azimuth_fx[k] < 0 )
9743 : {
9744 58 : hDirACRend->proto_index_diff[k] = 2;
9745 : }
9746 : ELSE
9747 : {
9748 10 : hDirACRend->proto_index_diff[k] = 0;
9749 : }
9750 126 : move16();
9751 : }
9752 :
9753 16 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
9754 : {
9755 10 : hDirACRend->num_protos_dir = 3;
9756 10 : move16();
9757 10 : Copy( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
9758 : }
9759 : ELSE
9760 : {
9761 6 : hDirACRend->num_protos_dir = 2;
9762 6 : move16();
9763 6 : hDirACRend->proto_index_dir[1] = 1;
9764 6 : move16();
9765 : }
9766 : }
9767 : }
9768 :
9769 : /* direct/diffuse responses */
9770 34 : IF( ( hDirACRend->diffuse_response_function_fx = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
9771 : {
9772 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9773 : }
9774 :
9775 34 : test();
9776 34 : test();
9777 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 ) )
9778 : {
9779 28 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
9780 28 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
9781 : }
9782 : ELSE
9783 : {
9784 6 : initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
9785 6 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
9786 : }
9787 :
9788 34 : hDirACRend->hoa_encoder_fx = NULL;
9789 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
9790 : {
9791 6 : IF( ( hDirACRend->hoa_encoder_fx = (Word32 *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( Word32 ) ) ) == NULL )
9792 : {
9793 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9794 : }
9795 :
9796 6 : set32_fx( hDirACRend->hoa_encoder_fx, 0, imult1616( nchan_out_woLFE, hDirACRend->num_outputs_diff ) );
9797 6 : compute_hoa_encoder_mtx_fx( ls_azimuth_fx, ls_elevation_fx, hDirACRend->hoa_encoder_fx, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
9798 : }
9799 :
9800 : /* VBAP */
9801 34 : inputMasa->hMasaExtRend->hVBAPdata = NULL;
9802 :
9803 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_VBAP ) )
9804 : {
9805 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 ) )
9806 : {
9807 0 : return error;
9808 : }
9809 : }
9810 :
9811 : /* HOA panning/dec */
9812 34 : hDirACRend->hoa_decoder = NULL;
9813 34 : IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) )
9814 : {
9815 14 : IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
9816 : {
9817 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 ) )
9818 : {
9819 0 : return error;
9820 : }
9821 :
9822 2 : hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
9823 : }
9824 : }
9825 :
9826 : /* decorrelation */
9827 34 : hDirACRend->proto_signal_decorr_on = 1;
9828 34 : move16();
9829 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
9830 : {
9831 2 : hDirACRend->proto_signal_decorr_on = 0;
9832 2 : move16();
9833 : }
9834 :
9835 34 : IF( hDirACRend->proto_signal_decorr_on )
9836 : {
9837 32 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDirACRend->h_freq_domain_decorr_ap_params ),
9838 : &( hDirACRend->h_freq_domain_decorr_ap_state ),
9839 : hSpatParamRendCom->num_freq_bands,
9840 : hDirACRend->num_outputs_diff,
9841 : hDirACRend->num_protos_diff,
9842 : hDirACRend->synthesisConf,
9843 : hDirACRend->frequency_axis_fx,
9844 : nchan_transport,
9845 : output_Fs ) ),
9846 : IVAS_ERR_OK ) )
9847 : {
9848 0 : return error;
9849 : }
9850 : }
9851 :
9852 : /* output synthesis */
9853 34 : IF( NE_32( ( ivas_dirac_dec_output_synthesis_open_fx( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ), IVAS_ERR_OK ) )
9854 : {
9855 0 : return error;
9856 : }
9857 34 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
9858 34 : move16();
9859 :
9860 34 : test();
9861 34 : if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9862 : {
9863 12 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
9864 12 : move16();
9865 : }
9866 :
9867 : /*-----------------------------------------------------------------*
9868 : * memory allocation
9869 : *-----------------------------------------------------------------*/
9870 :
9871 34 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
9872 : {
9873 6 : hDirACRend->proto_frame_f_fx = NULL;
9874 : }
9875 : ELSE
9876 : {
9877 28 : IF( ( hDirACRend->proto_frame_f_fx = (Word32 *) malloc( sizeof( Word32 ) * shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 ) ) ) == NULL )
9878 : {
9879 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
9880 : }
9881 28 : hDirACRend->proto_frame_f_len = shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 );
9882 28 : move16();
9883 : }
9884 :
9885 :
9886 34 : hDirACRend->buffer_energy_fx = NULL;
9887 136 : FOR( i = 0; i < DIRAC_NUM_DIMS; i++ )
9888 : {
9889 3366 : FOR( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
9890 : {
9891 3264 : hDirACRend->buffer_intensity_real_fx[i][j] = NULL;
9892 : }
9893 : }
9894 :
9895 : /* output synthesis */
9896 34 : ivas_dirac_dec_output_synthesis_init_fx( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
9897 :
9898 : /* Allocate stack memory */
9899 34 : IF( NE_32( ( error = ivas_dirac_alloc_mem_fx( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ), IVAS_ERR_OK ) )
9900 : {
9901 0 : return error;
9902 : }
9903 :
9904 34 : inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
9905 :
9906 34 : return error;
9907 : }
9908 :
9909 :
9910 12 : static ivas_error ivas_masa_ext_rend_parambin_init(
9911 : input_masa *inputMasa, /* i/o: MASA external renderer structure */
9912 : const RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration data handle */
9913 : HRTFS_STATISTICS_HANDLE hHrtfStatistics /* i : HRTF statistics */
9914 : )
9915 : {
9916 : DIRAC_DEC_BIN_HANDLE hDiracDecBin;
9917 : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
9918 : HRTFS_PARAMBIN_HANDLE *phHrtfParambin;
9919 : #else
9920 : HRTFS_PARAMBIN_HANDLE hHrtfParambin;
9921 : #endif
9922 : Word16 nBins;
9923 : Word32 output_Fs;
9924 : RENDERER_TYPE renderer_type;
9925 : Word16 j, k, bin;
9926 : Word32 binCenterFreq_fx;
9927 : Word16 tmpFloat_fx;
9928 : ivas_error error;
9929 : Word16 frequency_axis_fx[CLDFB_NO_CHANNELS_MAX];
9930 : #ifdef FIX_587_DEFAULT_REVERB
9931 : const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics;
9932 : #endif
9933 :
9934 : Word16 pos_idx, num_poses;
9935 : Word16 tmp;
9936 : Word16 tmp_e;
9937 : Word16 tmp2;
9938 :
9939 12 : error = IVAS_ERR_OK;
9940 12 : move32();
9941 :
9942 : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
9943 12 : phHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
9944 : #else
9945 : hHrtfParambin = *( inputMasa->hMasaExtRend->hHrtfParambin );
9946 : #endif
9947 : /* Set common variables and defaults */
9948 12 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
9949 12 : move32();
9950 12 : nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
9951 12 : move16();
9952 12 : renderer_type = inputMasa->hMasaExtRend->renderer_type;
9953 12 : move32();
9954 :
9955 12 : num_poses = 1;
9956 12 : move16();
9957 12 : if ( inputMasa->base.ctx.pSplitRendWrapper != NULL )
9958 : {
9959 0 : num_poses = inputMasa->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
9960 0 : move16();
9961 : }
9962 :
9963 24 : for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
9964 : {
9965 12 : hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin[pos_idx];
9966 :
9967 : /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
9968 12 : IF( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
9969 : {
9970 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
9971 : }
9972 :
9973 12 : hDiracDecBin->hTdDecorr = NULL;
9974 12 : hDiracDecBin->hReverb = NULL;
9975 12 : hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
9976 12 : hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
9977 12 : hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
9978 12 : hDiracDecBin->useTdDecorr = 0; /* Always use frequency domain decorrelator in external renderer */
9979 12 : move16();
9980 :
9981 36 : FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
9982 : {
9983 168 : FOR( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
9984 : {
9985 144 : set16_fx( hDiracDecBin->processMtxRe_fx[j][k], 0, nBins );
9986 144 : set16_fx( hDiracDecBin->processMtxIm_fx[j][k], 0, nBins );
9987 : }
9988 :
9989 72 : FOR( k = 0; k < BINAURAL_CHANNELS; k++ )
9990 : {
9991 48 : set16_fx( hDiracDecBin->processMtxDecRe_fx[j][k], 0, nBins );
9992 48 : set16_fx( hDiracDecBin->processMtxDecIm_fx[j][k], 0, nBins );
9993 : }
9994 24 : hDiracDecBin->q_processMtx = Q15;
9995 24 : hDiracDecBin->q_processMtxSCCR = Q15;
9996 24 : hDiracDecBin->q_processMtxPrev = Q15;
9997 24 : hDiracDecBin->q_processMtxPrevSCCR = Q15;
9998 24 : hDiracDecBin->q_processMtxDec = Q15;
9999 24 : hDiracDecBin->q_processMtxDecPrev = Q15;
10000 24 : move16();
10001 24 : move16();
10002 24 : move16();
10003 24 : move16();
10004 24 : move16();
10005 24 : move16();
10006 24 : set_zero_fx( hDiracDecBin->ChEnePrev_fx[j], nBins );
10007 24 : set_zero_fx( hDiracDecBin->ChEneOutPrev_fx[j], nBins );
10008 24 : set16_fx( hDiracDecBin->ChEnePrev_e[j], 0, nBins );
10009 24 : set16_fx( hDiracDecBin->ChEneOutPrev_e[j], 0, nBins );
10010 : }
10011 12 : set_zero_fx( hDiracDecBin->ChCrossRePrev_fx, nBins );
10012 12 : set_zero_fx( hDiracDecBin->ChCrossImPrev_fx, nBins );
10013 12 : set_zero_fx( hDiracDecBin->ChCrossReOutPrev_fx, nBins );
10014 12 : set_zero_fx( hDiracDecBin->ChCrossImOutPrev_fx, nBins );
10015 12 : set16_fx( hDiracDecBin->ChCrossRePrev_e, 0, nBins );
10016 12 : set16_fx( hDiracDecBin->ChCrossImPrev_e, 0, nBins );
10017 12 : set16_fx( hDiracDecBin->ChCrossReOutPrev_e, 0, nBins );
10018 12 : set16_fx( hDiracDecBin->ChCrossImOutPrev_e, 0, nBins );
10019 12 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
10020 12 : move16();
10021 :
10022 732 : FOR( bin = 0; bin < nBins; bin++ )
10023 : {
10024 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*/
10025 : /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
10026 720 : tmp = BASOP_Util_Divide3232_Scale( binCenterFreq_fx, L_shl( 2700, Q15 ), &tmp_e );
10027 720 : IF( tmp_e < 0 )
10028 : {
10029 36 : tmp = shl( tmp, tmp_e ); /*q15*/
10030 36 : tmp_e = 0;
10031 36 : move16();
10032 : }
10033 720 : tmpFloat_fx = s_max( 0, sub( shl_sat( 1, sub( 15, tmp_e ) ), tmp ) ) /*max( 0.0f, 1.0f - binCenterFreq / 2700.0f )*/; /*Q30*/
10034 720 : tmp2 = extract_l( Mult_32_32( binCenterFreq_fx, 1952258 /*=2^31*180/(550)/360*/ ) % 32767 ); //*binCenterFreq_fx * EVS_PI / 550.0f*/
10035 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 );*/
10036 720 : hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( hDiracDecBin->diffuseFieldCoherence_fx[bin], 1 ); /* Q31 */
10037 720 : move32();
10038 720 : move32();
10039 : }
10040 :
10041 : /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
10042 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceX_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
10043 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceY_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
10044 12 : set_zero_fx( hDiracDecBin->diffuseFieldCoherenceZ_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
10045 :
10046 12 : IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC ) ) /* Indication of binaural rendering without room effect */
10047 : {
10048 8 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
10049 8 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
10050 8 : move16();
10051 8 : hDiracDecBin->hReverb = NULL;
10052 : }
10053 4 : ELSE IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) /* Indication of binaural rendering with room effect */
10054 : {
10055 : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
10056 : #ifdef NONBE_FIX_981_PARAMBIN_DEFAULT_EARLY_PART
10057 0 : IF( EQ_32( *inputMasa->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
10058 : {
10059 0 : Copy32( ( *phHrtfParambin )->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
10060 : #ifdef FIX_587_DEFAULT_REVERB
10061 0 : pRoomAcoustics = NULL;
10062 : #endif
10063 : }
10064 : ELSE
10065 : {
10066 0 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28, CLDFB_NO_CHANNELS_MAX );
10067 : #ifdef FIX_587_DEFAULT_REVERB
10068 0 : pRoomAcoustics = &( hRendCfg->roomAcoustics );
10069 : #endif
10070 : }
10071 : #else
10072 : Copy32( ( *phHrtfParambin )->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
10073 : #endif
10074 : #else
10075 : Copy32( hHrtfParambin->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
10076 : #endif
10077 0 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
10078 0 : move16();
10079 :
10080 0 : IF( hDiracDecBin->hReverb == NULL && pos_idx == 0 ) /* open reverb only for the main direction */
10081 : {
10082 : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
10083 : #ifdef FIX_587_DEFAULT_REVERB
10084 : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
10085 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 ) )
10086 : #else
10087 : 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 ) )
10088 : #endif
10089 : #else
10090 : 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 ) )
10091 : #endif
10092 : #else
10093 : 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 ) )
10094 : #endif
10095 : {
10096 0 : return error;
10097 : }
10098 : }
10099 : }
10100 4 : ELSE IF( EQ_16( renderer_type, RENDERER_STEREO_PARAMETRIC ) )
10101 : {
10102 4 : set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
10103 4 : hDiracDecBin->q_earlyPartEneCorrection = Q28;
10104 4 : move16();
10105 4 : hDiracDecBin->hReverb = NULL;
10106 4 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
10107 4 : move16();
10108 : }
10109 : ELSE /* Not valid renderer type for this renderer */
10110 : {
10111 0 : assert( false );
10112 : }
10113 :
10114 12 : IF( pos_idx == 0 ) /* open decorrelator only for the main direction */
10115 : {
10116 : /* Always open frequency domain decorrelator */
10117 12 : ivas_dirac_dec_get_frequency_axis_fx( frequency_axis_fx, output_Fs, nBins );
10118 :
10119 12 : IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
10120 : &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
10121 : nBins,
10122 : BINAURAL_CHANNELS,
10123 : BINAURAL_CHANNELS,
10124 : DIRAC_SYNTHESIS_PSD_LS,
10125 : frequency_axis_fx,
10126 : BINAURAL_CHANNELS,
10127 : output_Fs ) ),
10128 : IVAS_ERR_OK ) )
10129 : {
10130 0 : return error;
10131 : }
10132 : }
10133 :
10134 : /* External renderer uses constant regularization factor */
10135 12 : hDiracDecBin->reqularizationFactor_fx = 6554; /* 0.4f in Q14 */
10136 12 : move16();
10137 :
10138 : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
10139 12 : hDiracDecBin->phHrtfParambin = phHrtfParambin;
10140 : #endif
10141 :
10142 12 : inputMasa->hMasaExtRend->hDiracDecBin[pos_idx] = hDiracDecBin;
10143 : }
10144 :
10145 12 : return error;
10146 : }
10147 :
10148 :
10149 48 : static ivas_error initMasaExtRenderer(
10150 : input_masa *inputMasa,
10151 : const AUDIO_CONFIG outConfig,
10152 : const RENDER_CONFIG_DATA *hRendCfg,
10153 : hrtf_handles *hrtfs )
10154 : {
10155 : Word16 i;
10156 : ivas_error error;
10157 : MASA_EXT_REND_HANDLE hMasaExtRend;
10158 :
10159 48 : error = IVAS_ERR_OK;
10160 48 : move32();
10161 :
10162 48 : IF( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
10163 : {
10164 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
10165 : }
10166 :
10167 48 : inputMasa->hMasaExtRend = hMasaExtRend;
10168 :
10169 : /* Default init */
10170 48 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
10171 48 : move32();
10172 48 : hMasaExtRend->hDirACRend = NULL;
10173 48 : hMasaExtRend->hSpatParamRendCom = NULL;
10174 432 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
10175 : {
10176 384 : hMasaExtRend->hDiracDecBin[i] = NULL;
10177 : }
10178 48 : hMasaExtRend->hReverb = NULL;
10179 48 : hMasaExtRend->hHrtfParambin = &hrtfs->hHrtfParambin;
10180 48 : hMasaExtRend->hVBAPdata = NULL;
10181 48 : hMasaExtRend->hoa_dec_mtx = NULL;
10182 :
10183 48 : IF( NE_32( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ), IVAS_ERR_OK ) )
10184 : {
10185 0 : return error;
10186 : }
10187 :
10188 48 : IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
10189 : {
10190 0 : hMasaExtRend->nchan_output = add( inputMasa->base.ctx.pCustomLsOut->num_spk, inputMasa->base.ctx.pCustomLsOut->num_lfe );
10191 0 : move16();
10192 : }
10193 48 : ELSE IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ), IVAS_ERR_OK ) )
10194 : {
10195 0 : return error;
10196 : }
10197 :
10198 48 : SWITCH( outConfig )
10199 : {
10200 4 : case IVAS_AUDIO_CONFIG_MONO:
10201 4 : IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
10202 : {
10203 2 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
10204 2 : move32();
10205 : }
10206 : ELSE
10207 : {
10208 : /* 1TC MASA to mono does not need rendering. */
10209 2 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
10210 2 : move32();
10211 : }
10212 4 : BREAK;
10213 :
10214 4 : case IVAS_AUDIO_CONFIG_STEREO:
10215 4 : hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
10216 4 : move32();
10217 4 : BREAK;
10218 :
10219 32 : case IVAS_AUDIO_CONFIG_5_1:
10220 : case IVAS_AUDIO_CONFIG_7_1:
10221 : case IVAS_AUDIO_CONFIG_5_1_2:
10222 : case IVAS_AUDIO_CONFIG_5_1_4:
10223 : case IVAS_AUDIO_CONFIG_7_1_4:
10224 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
10225 : case IVAS_AUDIO_CONFIG_FOA:
10226 : case IVAS_AUDIO_CONFIG_HOA2:
10227 : case IVAS_AUDIO_CONFIG_HOA3:
10228 32 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
10229 32 : move32();
10230 32 : BREAK;
10231 :
10232 8 : case IVAS_AUDIO_CONFIG_BINAURAL:
10233 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
10234 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
10235 8 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
10236 8 : move32();
10237 8 : BREAK;
10238 :
10239 0 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
10240 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
10241 0 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
10242 0 : move32();
10243 0 : BREAK;
10244 :
10245 0 : default:
10246 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
10247 : }
10248 :
10249 48 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
10250 : {
10251 : Word16 subframe;
10252 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 ) )
10253 : {
10254 0 : return error;
10255 : }
10256 : /* Simple population of the metadata index map as no adaptation is present */
10257 46 : set16_fx( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
10258 230 : FOR( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
10259 : {
10260 184 : hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
10261 184 : move16();
10262 : }
10263 46 : hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
10264 46 : move16();
10265 : }
10266 :
10267 48 : IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_DIRAC ) )
10268 : {
10269 34 : IF( NE_32( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ), IVAS_ERR_OK ) )
10270 : {
10271 0 : return error;
10272 : }
10273 : }
10274 :
10275 48 : test();
10276 48 : test();
10277 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 ) )
10278 : {
10279 12 : IF( NE_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
10280 : {
10281 8 : IF( NE_32( ( error = ivas_dirac_dec_binaural_copy_hrtfs_fx( inputMasa->hMasaExtRend->hHrtfParambin ) ), IVAS_ERR_OK ) )
10282 : {
10283 0 : return error;
10284 : }
10285 : }
10286 12 : if ( NE_32( ( error = ivas_masa_ext_rend_parambin_init( inputMasa, hRendCfg, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
10287 : {
10288 0 : return error;
10289 : }
10290 : }
10291 :
10292 : /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
10293 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
10294 : {
10295 96 : hMasaExtRend->cldfbAnaRend[i] = NULL;
10296 : }
10297 :
10298 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
10299 : {
10300 768 : hMasaExtRend->cldfbSynRend[i] = NULL;
10301 : }
10302 :
10303 48 : IF( NE_32( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
10304 : {
10305 116 : FOR( i = 0; i < hMasaExtRend->nchan_input; i++ )
10306 : {
10307 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 ) )
10308 : {
10309 0 : return error;
10310 : }
10311 : }
10312 :
10313 364 : FOR( i = 0; i < hMasaExtRend->nchan_output; i++ )
10314 : {
10315 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 ) )
10316 : {
10317 0 : return error;
10318 : }
10319 : }
10320 : }
10321 :
10322 48 : inputMasa->hMasaExtRend = hMasaExtRend;
10323 :
10324 48 : return IVAS_ERR_OK;
10325 : }
10326 :
10327 :
10328 666 : static void freeMasaExtRenderer(
10329 : MASA_EXT_REND_HANDLE *hMasaExtRendOut )
10330 : {
10331 : MASA_EXT_REND_HANDLE hMasaExtRend;
10332 : Word16 i;
10333 :
10334 666 : test();
10335 666 : IF( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
10336 : {
10337 618 : return;
10338 : }
10339 :
10340 48 : hMasaExtRend = *hMasaExtRendOut;
10341 :
10342 48 : IF( hMasaExtRend->hDirACRend != NULL )
10343 : {
10344 34 : ivas_dirac_rend_close_fx( &hMasaExtRend->hDirACRend );
10345 : }
10346 :
10347 48 : IF( hMasaExtRend->hSpatParamRendCom != NULL )
10348 : {
10349 46 : ivas_spat_hSpatParamRendCom_close_fx( &hMasaExtRend->hSpatParamRendCom );
10350 : }
10351 :
10352 432 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
10353 : {
10354 384 : if ( hMasaExtRend->hDiracDecBin[i] != NULL )
10355 : {
10356 12 : ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin[i] );
10357 : }
10358 : }
10359 :
10360 48 : IF( hMasaExtRend->hReverb != NULL )
10361 : {
10362 0 : ivas_binaural_reverb_close_fx( &hMasaExtRend->hReverb );
10363 : }
10364 :
10365 48 : IF( hMasaExtRend->hHrtfParambin != NULL )
10366 : {
10367 48 : ivas_HRTF_parambin_binary_close_fx( hMasaExtRend->hHrtfParambin );
10368 : }
10369 :
10370 48 : IF( hMasaExtRend->hVBAPdata != NULL )
10371 : {
10372 20 : vbap_free_data_fx( &hMasaExtRend->hVBAPdata );
10373 : }
10374 :
10375 48 : IF( hMasaExtRend->hoa_dec_mtx != NULL )
10376 : {
10377 2 : free( hMasaExtRend->hoa_dec_mtx );
10378 : }
10379 :
10380 144 : FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
10381 : {
10382 96 : IF( hMasaExtRend->cldfbAnaRend[i] != NULL )
10383 : {
10384 70 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbAnaRend[i] );
10385 : }
10386 : }
10387 :
10388 816 : FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
10389 : {
10390 768 : IF( hMasaExtRend->cldfbSynRend[i] != NULL )
10391 : {
10392 318 : deleteCldfb_ivas_fx( &hMasaExtRend->cldfbSynRend[i] );
10393 : }
10394 : }
10395 :
10396 48 : free( hMasaExtRend );
10397 48 : *hMasaExtRendOut = NULL;
10398 :
10399 48 : return;
10400 : }
10401 :
10402 25500 : static void intermidiate_ext_dirac_render(
10403 : MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure */
10404 : Word16 to_fix )
10405 : {
10406 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
10407 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
10408 : DIRAC_DEC_STACK_MEM DirAC_mem;
10409 : Word16 ch;
10410 : DIRAC_REND_HANDLE hDirACRend;
10411 : Word16 subframe_idx;
10412 : Word16 slot_idx;
10413 : Word16 nchan_transport;
10414 : Word16 tmp;
10415 :
10416 25500 : hDirACRend = hMasaExtRend->hDirACRend;
10417 25500 : hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
10418 25500 : nchan_transport = hMasaExtRend->nchan_input;
10419 : DIRAC_OUTPUT_SYNTHESIS_STATE *h_dirac_output_synthesis_state;
10420 :
10421 25500 : h_dirac_output_synthesis_state = &( hDirACRend->h_output_synthesis_psd_state );
10422 :
10423 25500 : subframe_idx = hSpatParamRendCom->subframes_rendered;
10424 25500 : move16();
10425 :
10426 25500 : DirAC_mem = hDirACRend->stack_mem;
10427 :
10428 25500 : IF( to_fix )
10429 : {
10430 12750 : DirAC_mem.reference_power_smooth_q[0] = DirAC_mem.reference_power_q[0] = Q31;
10431 12750 : DirAC_mem.reference_power_smooth_q[1] = DirAC_mem.reference_power_q[1] = Q31;
10432 12750 : move16();
10433 12750 : move16();
10434 12750 : move16();
10435 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
10436 : {
10437 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 */
10438 30736 : hDirACRend->h_output_synthesis_psd_state.direct_responses_q = Q30;
10439 30736 : move16();
10440 : }
10441 :
10442 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx )
10443 : {
10444 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 );
10445 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) */
10446 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 );
10447 12750 : move16();
10448 : }
10449 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx )
10450 : {
10451 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 );
10452 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) */
10453 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 );
10454 12750 : move16();
10455 : }
10456 :
10457 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx )
10458 : {
10459 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 ) );
10460 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) */
10461 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 );
10462 10500 : move16();
10463 : }
10464 :
10465 12750 : Word16 num_channels_dir = hDirACRend->num_outputs_dir;
10466 12750 : move16();
10467 :
10468 12750 : IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
10469 : {
10470 7500 : num_channels_dir = hDirACRend->hOutSetup.nchan_out_woLFE;
10471 7500 : move16();
10472 : }
10473 :
10474 12750 : IF( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx )
10475 : {
10476 12750 : tmp = L_norm_arr( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, imult1616( num_channels_dir, hSpatParamRendCom->num_freq_bands ) );
10477 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) */
10478 12750 : h_dirac_output_synthesis_state->q_cy_auto_diff_smooth = add( h_dirac_output_synthesis_state->q_cy_auto_diff_smooth, tmp );
10479 12750 : move16();
10480 : }
10481 :
10482 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx )
10483 : {
10484 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 );
10485 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) */
10486 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 );
10487 12750 : move16();
10488 : }
10489 :
10490 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 */
10491 12750 : hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q = Q26;
10492 12750 : move16();
10493 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 */
10494 12750 : hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q = Q26;
10495 12750 : move16();
10496 12750 : IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx )
10497 : {
10498 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 ) );
10499 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) */
10500 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 );
10501 10500 : move16();
10502 : }
10503 :
10504 12750 : IF( EQ_16( hDirACRend->proto_signal_decorr_on, 1 ) )
10505 : {
10506 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 );
10507 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) */
10508 12000 : hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer = add( hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer, tmp );
10509 12000 : move16();
10510 : }
10511 :
10512 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len > 0 )
10513 : {
10514 : Word16 shift, norm1, norm2;
10515 : Word32 tmp1, tmp2;
10516 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 );
10517 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 );
10518 :
10519 12000 : IF( tmp1 == 0 )
10520 : {
10521 32 : norm1 = 31;
10522 32 : move16();
10523 : }
10524 : ELSE
10525 : {
10526 11968 : norm1 = norm_l( tmp1 );
10527 : }
10528 :
10529 12000 : IF( tmp2 == 0 )
10530 : {
10531 32 : norm2 = 31;
10532 32 : move16();
10533 : }
10534 : ELSE
10535 : {
10536 11968 : norm2 = norm_l( tmp2 );
10537 : }
10538 :
10539 12000 : shift = s_min( norm1, norm2 );
10540 :
10541 12000 : Word16 hr_exp = sub( 31, shift );
10542 :
10543 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) */
10544 12000 : hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q = sub( 31, hr_exp );
10545 12000 : move16();
10546 : }
10547 :
10548 43486 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
10549 : {
10550 : /* CLDFB Analysis*/
10551 77744 : FOR( ch = 0; ch < nchan_transport; ch++ )
10552 : {
10553 47008 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
10554 47008 : move16();
10555 : }
10556 : }
10557 12750 : hDirACRend->proto_frame_dec_f_q = sub( 31, hDirACRend->proto_frame_dec_f_q );
10558 12750 : move16();
10559 :
10560 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx )
10561 : {
10562 10500 : tmp = 0;
10563 10500 : move16();
10564 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 ) )
10565 : {
10566 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 ) ) );
10567 : }
10568 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 ) )
10569 : {
10570 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) */
10571 : }
10572 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 );
10573 10500 : move16();
10574 10500 : tmp = 0;
10575 10500 : move16();
10576 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 ) )
10577 : {
10578 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 ) ) ) );
10579 : }
10580 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 ) )
10581 : {
10582 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) */
10583 : }
10584 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 );
10585 10500 : move16();
10586 10500 : tmp = 0;
10587 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 ) )
10588 : {
10589 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 ) ) );
10590 : }
10591 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 ) )
10592 : {
10593 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) */
10594 : }
10595 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] );
10596 10500 : move16();
10597 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 ) )
10598 : {
10599 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 ) ) ) );
10600 : }
10601 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 ) )
10602 : {
10603 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) */
10604 : }
10605 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] );
10606 10500 : move16();
10607 : }
10608 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx != NULL )
10609 : {
10610 :
10611 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 );
10612 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) */
10613 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 );
10614 10500 : move16();
10615 : }
10616 :
10617 12750 : IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx != NULL )
10618 : {
10619 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 );
10620 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) */
10621 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 );
10622 9750 : move16();
10623 : }
10624 : }
10625 : ELSE
10626 : {
10627 43350 : FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[hSpatParamRendCom->subframes_rendered]; slot_idx++ )
10628 : {
10629 : /* CLDFB Analysis*/
10630 77400 : FOR( ch = 0; ch < nchan_transport; ch++ )
10631 : {
10632 46800 : scale_sig32( hMasaExtRend->cldfbAnaRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbAnaRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state ) ); /* Q11 */
10633 46800 : hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
10634 46800 : move16();
10635 : }
10636 : }
10637 :
10638 123000 : FOR( ch = 0; ch < hDirACRend->hOutSetup.nchan_out_woLFE + hDirACRend->hOutSetup.num_lfe; ch++ )
10639 : {
10640 110250 : scale_sig32( hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbSynRend[0]->Q_cldfb_state ) ); /* Q11 */
10641 110250 : hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
10642 110250 : move16();
10643 : }
10644 : }
10645 :
10646 25500 : return;
10647 : }
10648 :
10649 :
10650 666 : static ivas_error printConfigInfo_rend(
10651 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
10652 : )
10653 : {
10654 : ivas_error error;
10655 : Word8 config_str[50];
10656 :
10657 : /*-----------------------------------------------------------------*
10658 : * Print output audio configuration
10659 : *-----------------------------------------------------------------*/
10660 :
10661 666 : IF( NE_32( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ), IVAS_ERR_OK ) )
10662 : {
10663 0 : return error;
10664 : }
10665 :
10666 666 : fprintf( stdout, "Output configuration: %s\n", config_str );
10667 :
10668 : /*-----------------------------------------------------------------*
10669 : * Print renderer configurations
10670 : *-----------------------------------------------------------------*/
10671 :
10672 666 : fprintf( stdout, "Output sampling rate: %d Hz\n", hIvasRend->sampleRateOut );
10673 :
10674 666 : if ( hIvasRend->headRotData.headRotEnabled )
10675 : {
10676 94 : fprintf( stdout, "Head-tracking: ON\n" );
10677 : }
10678 :
10679 666 : test();
10680 666 : test();
10681 666 : test();
10682 666 : test();
10683 666 : IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) ||
10684 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) ||
10685 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ||
10686 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
10687 : EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
10688 : {
10689 188 : fprintf( stdout, "Render framesize: %dms\n", i_mult( hIvasRend->num_subframes, 5 ) );
10690 : }
10691 :
10692 666 : return IVAS_ERR_OK;
10693 : }
10694 :
10695 :
10696 : /*---------------------------------------------------------------------*
10697 : * IVAS_REND_PrintInputConfig()
10698 : *
10699 : *
10700 : *---------------------------------------------------------------------*/
10701 :
10702 729 : void IVAS_REND_PrintInputConfig(
10703 : const IVAS_AUDIO_CONFIG inputConfig /* i : input audio configuration */
10704 : )
10705 : {
10706 : Word8 config_str[50];
10707 :
10708 729 : get_channel_config( inputConfig, &config_str[0] );
10709 729 : fprintf( stdout, "Input configuration: %s\n", config_str );
10710 :
10711 729 : return;
10712 : }
10713 :
10714 :
10715 : /*---------------------------------------------------------------------*
10716 : * IVAS_REND_PrintConfig()
10717 : *
10718 : *
10719 : *---------------------------------------------------------------------*/
10720 :
10721 666 : ivas_error IVAS_REND_PrintConfig(
10722 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
10723 : )
10724 : {
10725 666 : if ( hIvasRend == NULL )
10726 : {
10727 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
10728 : }
10729 :
10730 666 : return printConfigInfo_rend( hIvasRend );
10731 : }
10732 :
10733 :
10734 : /*---------------------------------------------------------------------*
10735 : * IVAS_REND_PrintDisclaimer()
10736 : *
10737 : * Print IVAS disclaimer to console
10738 : *---------------------------------------------------------------------*/
10739 :
10740 666 : void IVAS_REND_PrintDisclaimer( void )
10741 : {
10742 666 : print_disclaimer( stderr );
10743 :
10744 666 : return;
10745 : }
|