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 "options.h"
34 : #include "lib_rend.h"
35 : #include "prot.h"
36 : #include "ivas_prot.h"
37 : #include "ivas_prot_rend.h"
38 : #include "isar_prot.h"
39 : #include "lib_isar_pre_rend.h"
40 : #include "ivas_cnst.h"
41 : #include "ivas_rom_com.h"
42 : #include "ivas_rom_rend.h"
43 : #include <assert.h>
44 : #include <math.h>
45 : #include <stdbool.h>
46 : #include "wmc_auto.h"
47 : #include <stdint.h>
48 :
49 :
50 : /*-------------------------------------------------------------------*
51 : * Local constants
52 : *-------------------------------------------------------------------*/
53 :
54 : /* Maximum buffer length (total) in samples. */
55 : #define MAX_BUFFER_LENGTH ( L_FRAME_MAX * MAX_INPUT_CHANNELS )
56 : #define MAX_BIN_DELAY_SAMPLES 150 /* Maximum supported rendering latency for binaural IRs */
57 :
58 : /*-------------------------------------------------------------------*
59 : * Local types
60 : *-------------------------------------------------------------------*/
61 :
62 : typedef float pan_vector[MAX_OUTPUT_CHANNELS];
63 : typedef float pan_matrix[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
64 : typedef float rotation_gains[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
65 : typedef float rotation_matrix[3][3];
66 :
67 : /* EFAP wrapper to simplify writing panning gains to a vector that includes LFE channels */
68 : typedef struct
69 : {
70 : EFAP_HANDLE hEfap;
71 : AUDIO_CONFIG speakerConfig;
72 : const LSSETUP_CUSTOM_STRUCT *pCustomLsSetup; /* Pointer to main custom LS struct from renderer handle - doesn't need freeing */
73 : } EFAP_WRAPPER;
74 :
75 : /* Lightweight helper struct that gathers all information required for rendering
76 : * any config to any other config. Used to simplify signatures of rendering functions.
77 : *
78 : * This struct should store ONLY CONST POINTERS to data existing elsewhere.
79 : * Storing pointers instead of data itself ensures that no additional updates
80 : * are required when any of these are changed in the renderer. Making the pointers
81 : * const ensures that this data is only read, but not modified by the rendering functions. */
82 : typedef struct
83 : {
84 : const int32_t *pOutSampleRate;
85 : const int32_t *pMaxGlobalDelayNs;
86 : const AUDIO_CONFIG *pOutConfig;
87 : const LSSETUP_CUSTOM_STRUCT *pCustomLsOut;
88 : const EFAP_WRAPPER *pEfapOutWrapper;
89 : const IVAS_REND_HeadRotData *pHeadRotData;
90 : const RENDER_CONFIG_HANDLE *hhRendererConfig;
91 : const int16_t *pSplitRendBFI;
92 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
93 : const COMBINED_ORIENTATION_HANDLE *pCombinedOrientationData;
94 : const IVAS_DefaultReverbSize *pSelectedRoomReverbSize;
95 : } rendering_context;
96 :
97 : /* Common base for input structs */
98 : typedef struct
99 : {
100 : AUDIO_CONFIG inConfig;
101 : IVAS_REND_InputId id;
102 : IVAS_REND_AudioBuffer inputBuffer;
103 : TD_RINGBUF_HANDLE delayBuffer;
104 : float gain; /* Linear, not in dB */
105 : rendering_context ctx;
106 : int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */
107 : int16_t delayNumSamples;
108 : } input_base;
109 :
110 : typedef struct
111 : {
112 : input_base base;
113 : IVAS_ISM_METADATA currentPos;
114 : IVAS_ISM_METADATA previousPos;
115 : TDREND_WRAPPER tdRendWrapper;
116 : CREND_WRAPPER_HANDLE crendWrapper;
117 : REVERB_HANDLE hReverb;
118 : rotation_matrix rot_mat_prev;
119 : pan_vector prev_pan_gains;
120 : int8_t firstFrameRendered;
121 : TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */
122 : float *bufferData;
123 : int16_t nonDiegeticPan;
124 : float nonDiegeticPanGain;
125 : OMASA_ANA_HANDLE hOMasa;
126 : uint16_t total_num_objects;
127 : int16_t object_id;
128 : int16_t ism_metadata_delay_ms;
129 : } input_ism;
130 :
131 : typedef struct
132 : {
133 : int16_t numLfeChannels;
134 : bool pan_lfe;
135 : float lfeInputGain;
136 : float lfeOutputAzimuth;
137 : float lfeOutputElevation;
138 : IVAS_REND_LfePanMtx lfePanMtx;
139 : } lfe_routing;
140 :
141 : typedef struct
142 : {
143 : input_base base;
144 :
145 : /* Full panning matrix. 1st index is input channel, 2nd index is output channel.
146 : All LFE channels should be included, both for inputs and outputs */
147 : pan_matrix panGains;
148 :
149 : LSSETUP_CUSTOM_STRUCT customLsInput;
150 : EFAP_WRAPPER efapInWrapper;
151 : TDREND_WRAPPER tdRendWrapper;
152 : CREND_WRAPPER_HANDLE crendWrapper;
153 : TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */
154 : REVERB_HANDLE hReverb;
155 : rotation_gains rot_gains_prev[MAX_HEAD_ROT_POSES];
156 : int16_t nonDiegeticPan;
157 : float nonDiegeticPanGain;
158 : lfe_routing lfeRouting;
159 : float *bufferData;
160 : int16_t binauralDelaySmp;
161 : float *lfeDelayBuffer;
162 : MCMASA_ANA_HANDLE hMcMasa;
163 : } input_mc;
164 :
165 : typedef struct
166 : {
167 : input_base base;
168 : pan_matrix hoaDecMtx;
169 : CLDFB_REND_WRAPPER cldfbRendWrapper;
170 : CREND_WRAPPER_HANDLE crendWrapper;
171 : rotation_gains rot_gains_prev[MAX_HEAD_ROT_POSES];
172 : float *bufferData;
173 : DIRAC_ANA_HANDLE hDirAC;
174 : } input_sba;
175 :
176 : typedef struct
177 : {
178 : input_base base;
179 : MASA_METADATA_FRAME masaMetadata;
180 : bool metadataHasBeenFed;
181 : float *bufferData;
182 : MASA_EXT_REND_HANDLE hMasaExtRend;
183 : MASA_PREREND_HANDLE hMasaPrerend;
184 : } input_masa;
185 :
186 : typedef struct hrtf_handles
187 : {
188 : IVAS_DEC_HRTF_CREND_HANDLE hHrtfCrend;
189 : IVAS_DEC_HRTF_FASTCONV_HANDLE hHrtfFastConv;
190 : IVAS_DEC_HRTF_PARAMBIN_HANDLE hHrtfParambin;
191 : IVAS_DEC_HRTF_TD_HANDLE hHrtfTD;
192 : IVAS_DEC_HRTF_STATISTICS_HANDLE hHrtfStatistics;
193 : } hrtf_handles;
194 :
195 : struct IVAS_REND
196 : {
197 : int32_t sampleRateOut;
198 : int32_t maxGlobalDelayNs;
199 :
200 : IVAS_LIMITER_HANDLE hLimiter;
201 : #ifdef DEBUGGING
202 : int32_t numClipping; /* Counter of clipped output samples */
203 : #endif
204 :
205 : input_ism inputsIsm[RENDERER_MAX_ISM_INPUTS];
206 : input_mc inputsMc[RENDERER_MAX_MC_INPUTS];
207 : input_sba inputsSba[RENDERER_MAX_SBA_INPUTS];
208 : input_masa inputsMasa[RENDERER_MAX_MASA_INPUTS];
209 :
210 : AUDIO_CONFIG inputConfig;
211 : AUDIO_CONFIG outputConfig;
212 : EFAP_WRAPPER efapOutWrapper;
213 : IVAS_LSSETUP_CUSTOM_STRUCT customLsOut;
214 :
215 : int16_t splitRendBFI;
216 : SPLIT_REND_WRAPPER *splitRendWrapper;
217 : IVAS_REND_AudioBuffer splitRendEncBuffer;
218 :
219 : IVAS_REND_HeadRotData headRotData;
220 :
221 : EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData;
222 : COMBINED_ORIENTATION_HANDLE hCombinedOrientationData;
223 :
224 : int8_t rendererConfigEnabled;
225 : RENDER_CONFIG_DATA *hRendererConfig; /* Renderer config pointer */
226 : IVAS_DefaultReverbSize selectedRoomReverbSize;
227 :
228 : int16_t num_subframes;
229 : hrtf_handles hHrtfs;
230 : };
231 :
232 :
233 : /*-------------------------------------------------------------------*
234 : * Local function prototypes
235 : *-------------------------------------------------------------------*/
236 :
237 : static ivas_error initMasaExtRenderer( input_masa *inputMasa, const AUDIO_CONFIG outConfig, const RENDER_CONFIG_DATA *hRendCfg, hrtf_handles *hHrtfs );
238 :
239 : static void freeMasaExtRenderer( MASA_EXT_REND_HANDLE *hMasaExtRendOut );
240 :
241 : static void renderSbaToMultiBinauralCldfb( input_sba *sbaInput, float Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], float Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], const int16_t low_res_pre_rend_rot, const int16_t num_subframes );
242 :
243 : static ivas_error renderSbaToMultiBinaural( input_sba *sbaInput, const AUDIO_CONFIG outConfig, float out[][L_FRAME48k] );
244 :
245 : /*-------------------------------------------------------------------*
246 : * Local functions
247 : *-------------------------------------------------------------------*/
248 :
249 25412 : static ivas_error allocateInputBaseBufferData(
250 : float **data,
251 : const int16_t data_size )
252 : {
253 25412 : *data = (float *) malloc( data_size * sizeof( float ) );
254 25412 : if ( *data == NULL )
255 : {
256 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for input base buffer data" );
257 : }
258 :
259 25412 : return IVAS_ERR_OK;
260 : }
261 :
262 72478 : static void freeInputBaseBufferData(
263 : float **data )
264 : {
265 72478 : if ( *data != NULL )
266 : {
267 25412 : free( *data );
268 25412 : *data = NULL;
269 : }
270 :
271 72478 : return;
272 : }
273 :
274 23401862 : static int16_t latencyNsToSamples(
275 : int32_t sampleRate,
276 : int32_t latency_ns )
277 : {
278 23401862 : return (int16_t) roundf( (float) ( latency_ns ) * ( sampleRate / 1000000000.f ) );
279 : }
280 :
281 2594 : static ivas_error allocateMcLfeDelayBuffer(
282 : float **lfeDelayBuffer,
283 : const int16_t data_size )
284 : {
285 2594 : *lfeDelayBuffer = (float *) malloc( data_size * sizeof( float ) );
286 2594 : if ( *lfeDelayBuffer == NULL )
287 : {
288 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" );
289 : }
290 :
291 2594 : return IVAS_ERR_OK;
292 : }
293 :
294 10354 : static void freeMcLfeDelayBuffer(
295 : float **lfeDelayBuffer )
296 : {
297 10354 : if ( *lfeDelayBuffer != NULL )
298 : {
299 2594 : free( *lfeDelayBuffer );
300 2594 : *lfeDelayBuffer = NULL;
301 : }
302 :
303 10354 : return;
304 : }
305 :
306 5344 : static IVAS_QUATERNION quaternionInit(
307 : void )
308 : {
309 : IVAS_QUATERNION q;
310 5344 : q.w = 1.0f;
311 5344 : q.x = q.y = q.z = 0.0f;
312 5344 : return q;
313 : }
314 :
315 3395870359 : static float *getSmplPtr(
316 : IVAS_REND_AudioBuffer buffer,
317 : const uint32_t chnlIdx,
318 : const uint32_t smplIdx )
319 : {
320 3395870359 : return buffer.data + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx;
321 : }
322 :
323 68852 : static void convertBitsBufferToInternalBitsBuff(
324 : const IVAS_REND_BitstreamBuffer outBits,
325 : ISAR_SPLIT_REND_BITS_HANDLE hBits )
326 : {
327 68852 : hBits->bits_buf = outBits.bits;
328 68852 : hBits->bits_read = outBits.config.bitsRead;
329 68852 : hBits->bits_written = outBits.config.bitsWritten;
330 68852 : hBits->buf_len = outBits.config.bufLenInBytes;
331 68852 : hBits->codec = outBits.config.codec;
332 68852 : hBits->pose_correction = outBits.config.poseCorrection;
333 68852 : hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
334 :
335 68852 : return;
336 : }
337 :
338 68852 : static void convertInternalBitsBuffToBitsBuffer(
339 : IVAS_REND_BitstreamBuffer *hOutBits,
340 : const ISAR_SPLIT_REND_BITS_DATA bits )
341 : {
342 68852 : hOutBits->bits = bits.bits_buf;
343 68852 : hOutBits->config.bitsRead = bits.bits_read;
344 68852 : hOutBits->config.bitsWritten = bits.bits_written;
345 68852 : hOutBits->config.bufLenInBytes = bits.buf_len;
346 68852 : hOutBits->config.codec = bits.codec;
347 68852 : hOutBits->config.poseCorrection = bits.pose_correction;
348 68852 : hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
349 :
350 68852 : return;
351 : }
352 :
353 16912 : static void copyBufferToCLDFBarray(
354 : const IVAS_REND_AudioBuffer buffer,
355 : float re[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
356 : float im[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] )
357 : {
358 : uint32_t smplIdx, slotIdx;
359 : uint32_t numCldfbSamples, num_bands;
360 : uint32_t chnlIdx;
361 : const float *readPtr;
362 :
363 16912 : assert( ( buffer.config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
364 16912 : readPtr = buffer.data;
365 16912 : numCldfbSamples = ( (uint32_t) buffer.config.numSamplesPerChannel ) >> 1;
366 16912 : num_bands = numCldfbSamples / CLDFB_NO_COL_MAX;
367 166384 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
368 : {
369 2541024 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
370 : {
371 145884672 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
372 : {
373 143493120 : re[chnlIdx][slotIdx][smplIdx] = *readPtr++;
374 : }
375 145884672 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
376 : {
377 143493120 : im[chnlIdx][slotIdx][smplIdx] = *readPtr++;
378 : }
379 : }
380 : }
381 :
382 16912 : return;
383 : }
384 :
385 33684 : static void accumulateCLDFBArrayToBuffer(
386 : float re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
387 : float im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
388 : const IVAS_REND_AudioBuffer *buffer )
389 : {
390 : uint32_t smplIdx, slotIdx;
391 : uint32_t numCldfbSamples, num_bands;
392 : uint32_t chnlIdx;
393 : float *writePtr;
394 :
395 33684 : assert( ( buffer->config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
396 33684 : writePtr = buffer->data;
397 33684 : numCldfbSamples = ( (uint32_t) buffer->config.numSamplesPerChannel ) >> 1;
398 33684 : num_bands = numCldfbSamples / CLDFB_NO_COL_MAX;
399 309468 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer->config.numChannels; ++chnlIdx )
400 : {
401 4688328 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
402 : {
403 269165184 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
404 : {
405 264752640 : *writePtr++ += re[chnlIdx][slotIdx][smplIdx];
406 : }
407 269165184 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
408 : {
409 264752640 : *writePtr++ += im[chnlIdx][slotIdx][smplIdx];
410 : }
411 : }
412 : }
413 :
414 33684 : return;
415 : }
416 :
417 11222146 : static void copyBufferTo2dArray(
418 : const IVAS_REND_AudioBuffer buffer,
419 : float array[][L_FRAME48k] )
420 : {
421 : uint32_t smplIdx;
422 : uint32_t chnlIdx;
423 : const float *readPtr;
424 :
425 11222146 : assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
426 11222146 : readPtr = buffer.data;
427 :
428 65981046 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
429 : {
430 15964707860 : for ( smplIdx = 0; smplIdx < (uint32_t) buffer.config.numSamplesPerChannel; ++smplIdx )
431 : {
432 15909948960 : array[chnlIdx][smplIdx] = *readPtr++;
433 : }
434 : }
435 :
436 11222146 : return;
437 : }
438 :
439 10743790 : static void accumulate2dArrayToBuffer(
440 : float array[][L_FRAME48k],
441 : const IVAS_REND_AudioBuffer *buffer )
442 : {
443 : int16_t smplIdx, chnlIdx;
444 : float *writePtr;
445 :
446 10743790 : writePtr = buffer->data;
447 35254402 : for ( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
448 : {
449 6975441492 : for ( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
450 : {
451 6950930880 : *writePtr++ += array[chnlIdx][smplIdx];
452 : }
453 : }
454 :
455 10743790 : return;
456 : }
457 :
458 : /*-------------------------------------------------------------------*
459 : * limitRendererOutput()
460 : *
461 : * In-place saturation control for multichannel buffers with adaptive release time
462 : *-------------------------------------------------------------------*/
463 :
464 : #ifndef DISABLE_LIMITER
465 : /*! r: number of clipped output samples */
466 8805555 : static int32_t limitRendererOutput(
467 : IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */
468 : float *output, /* i/o: I/O buffer */
469 : const int16_t output_frame, /* i : number of samples per channel in the buffer */
470 : const float threshold /* i : signal amplitude above which limiting starts to be applied */
471 : )
472 : {
473 : int16_t i;
474 : float **channels;
475 : int16_t num_channels;
476 8805555 : int32_t numClipping = 0;
477 :
478 : /* return early if given bad parameters */
479 8805555 : if ( hLimiter == NULL || output == NULL || output_frame <= 0 )
480 : {
481 0 : return 0;
482 : }
483 :
484 8805555 : channels = hLimiter->channel_ptrs;
485 8805555 : num_channels = hLimiter->num_channels;
486 :
487 54935435 : for ( i = 0; i < num_channels; ++i )
488 : {
489 46129880 : channels[i] = output + i * output_frame;
490 : }
491 :
492 8805555 : limiter_process( hLimiter, output_frame, threshold, 0, NULL );
493 :
494 : /* Apply clipping to buffer in case the limiter let through some samples > 1.0f */
495 13224371955 : for ( i = 0; i < output_frame * num_channels; ++i )
496 : {
497 : #ifdef DEBUGGING
498 : if ( output[i] < INT16_MIN || output[i] > INT16_MAX )
499 : {
500 : ++numClipping;
501 : }
502 : #endif
503 :
504 13215566400 : output[i] = min( max( INT16_MIN, output[i] ), INT16_MAX );
505 : }
506 :
507 8805555 : return numClipping;
508 : }
509 : #endif
510 :
511 : /*-------------------------------------------------------------------*
512 : * validateOutputAudioConfig()
513 : *
514 : *
515 : *-------------------------------------------------------------------*/
516 :
517 10354 : static ivas_error validateOutputAudioConfig(
518 : const AUDIO_CONFIG outConfig )
519 : {
520 10354 : switch ( outConfig )
521 : {
522 10354 : case IVAS_AUDIO_CONFIG_MONO:
523 : case IVAS_AUDIO_CONFIG_STEREO:
524 : case IVAS_AUDIO_CONFIG_5_1:
525 : case IVAS_AUDIO_CONFIG_7_1:
526 : case IVAS_AUDIO_CONFIG_5_1_2:
527 : case IVAS_AUDIO_CONFIG_5_1_4:
528 : case IVAS_AUDIO_CONFIG_7_1_4:
529 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
530 : case IVAS_AUDIO_CONFIG_FOA:
531 : case IVAS_AUDIO_CONFIG_HOA2:
532 : case IVAS_AUDIO_CONFIG_HOA3:
533 : case IVAS_AUDIO_CONFIG_BINAURAL:
534 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
535 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
536 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
537 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
538 : case IVAS_AUDIO_CONFIG_MASA1:
539 : case IVAS_AUDIO_CONFIG_MASA2:
540 10354 : return IVAS_ERR_OK;
541 0 : default:
542 0 : break;
543 : }
544 :
545 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
546 : }
547 :
548 :
549 : /*-------------------------------------------------------------------*
550 : * getAudioConfigType()
551 : *
552 : *
553 : *-------------------------------------------------------------------*/
554 :
555 92533109 : IVAS_REND_AudioConfigType getAudioConfigType(
556 : const AUDIO_CONFIG config )
557 : {
558 : IVAS_REND_AudioConfigType type;
559 :
560 92533109 : switch ( config )
561 : {
562 36119452 : case IVAS_AUDIO_CONFIG_MONO:
563 : case IVAS_AUDIO_CONFIG_STEREO:
564 : case IVAS_AUDIO_CONFIG_5_1:
565 : case IVAS_AUDIO_CONFIG_7_1:
566 : case IVAS_AUDIO_CONFIG_5_1_2:
567 : case IVAS_AUDIO_CONFIG_5_1_4:
568 : case IVAS_AUDIO_CONFIG_7_1_4:
569 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
570 36119452 : type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
571 36119452 : break;
572 16351069 : case IVAS_AUDIO_CONFIG_FOA:
573 : case IVAS_AUDIO_CONFIG_HOA2:
574 : case IVAS_AUDIO_CONFIG_HOA3:
575 16351069 : type = IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS;
576 16351069 : break;
577 5933134 : case IVAS_AUDIO_CONFIG_OBA:
578 5933134 : type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
579 5933134 : break;
580 33499362 : case IVAS_AUDIO_CONFIG_BINAURAL:
581 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
582 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
583 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
584 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
585 33499362 : type = IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL;
586 33499362 : break;
587 630092 : case IVAS_AUDIO_CONFIG_MASA1:
588 : case IVAS_AUDIO_CONFIG_MASA2:
589 630092 : type = IVAS_REND_AUDIO_CONFIG_TYPE_MASA;
590 630092 : break;
591 0 : default:
592 0 : type = IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
593 0 : break;
594 : }
595 :
596 92533109 : return type;
597 : }
598 :
599 :
600 : /*-------------------------------------------------------------------*
601 : * validateOutputSampleRate()
602 : *
603 : *
604 : *-------------------------------------------------------------------*/
605 :
606 10354 : static ivas_error validateOutputSampleRate(
607 : const int32_t sampleRate,
608 : const AUDIO_CONFIG outConfig )
609 : {
610 10354 : if ( getAudioConfigType( outConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
611 : {
612 : /* If no binaural rendering, any sampling rate is supported */
613 5814 : return IVAS_ERR_OK;
614 : }
615 4540 : else if ( ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && sampleRate != 48000 )
616 : {
617 0 : return IVAS_ERROR( IVAS_ERR_INVALID_SAMPLING_RATE, "Error: Only 48kHz output sampling rate is supported for split rendering." );
618 : }
619 : else
620 : {
621 : /* Otherwise rendering to binaural, support the same set as IVAS decoder */
622 4540 : switch ( sampleRate )
623 : {
624 4540 : case 16000:
625 : case 32000:
626 : case 48000:
627 4540 : return IVAS_ERR_OK;
628 : }
629 :
630 0 : return IVAS_ERR_INVALID_SAMPLING_RATE;
631 : }
632 : }
633 :
634 :
635 : /*-------------------------------------------------------------------*
636 : * getAudioConfigNumChannels()
637 : *
638 : *
639 : *-------------------------------------------------------------------*/
640 :
641 70115373 : ivas_error getAudioConfigNumChannels(
642 : const AUDIO_CONFIG config,
643 : int16_t *numChannels )
644 : {
645 70115373 : switch ( config )
646 : {
647 17702809 : case IVAS_AUDIO_CONFIG_MONO:
648 : case IVAS_AUDIO_CONFIG_OBA:
649 : case IVAS_AUDIO_CONFIG_MASA1:
650 17702809 : *numChannels = 1;
651 17702809 : break;
652 18097570 : case IVAS_AUDIO_CONFIG_STEREO:
653 : case IVAS_AUDIO_CONFIG_BINAURAL:
654 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
655 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
656 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
657 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
658 : case IVAS_AUDIO_CONFIG_MASA2:
659 18097570 : *numChannels = 2;
660 18097570 : break;
661 6183150 : case IVAS_AUDIO_CONFIG_FOA:
662 6183150 : *numChannels = 4;
663 6183150 : break;
664 1909816 : case IVAS_AUDIO_CONFIG_5_1:
665 1909816 : *numChannels = 6;
666 1909816 : break;
667 1686089 : case IVAS_AUDIO_CONFIG_7_1:
668 : case IVAS_AUDIO_CONFIG_5_1_2:
669 1686089 : *numChannels = 8;
670 1686089 : break;
671 5870902 : case IVAS_AUDIO_CONFIG_HOA2:
672 5870902 : *numChannels = 9;
673 5870902 : break;
674 890551 : case IVAS_AUDIO_CONFIG_5_1_4:
675 890551 : *numChannels = 10;
676 890551 : break;
677 11337643 : case IVAS_AUDIO_CONFIG_7_1_4:
678 11337643 : *numChannels = 12;
679 11337643 : break;
680 6436843 : case IVAS_AUDIO_CONFIG_HOA3:
681 6436843 : *numChannels = 16;
682 6436843 : break;
683 0 : default:
684 0 : return IVAS_ERR_NUM_CHANNELS_UNKNOWN;
685 : }
686 :
687 70115373 : return IVAS_ERR_OK;
688 : }
689 :
690 :
691 : /*-------------------------------------------------------------------*
692 : * Local functions
693 : *-------------------------------------------------------------------*/
694 :
695 11056 : static ivas_error initLimiter(
696 : IVAS_LIMITER_HANDLE *phLimiter,
697 : const int16_t numChannels,
698 : const int32_t sampleRate )
699 : {
700 : ivas_error error;
701 :
702 : /* If re-initializing with unchanged values, return early */
703 11056 : if ( *phLimiter != NULL && ( *phLimiter )->num_channels == numChannels && ( *phLimiter )->sampling_rate == sampleRate )
704 : {
705 0 : return IVAS_ERR_OK;
706 : }
707 :
708 : /* Support re-init: close if already allocated */
709 11056 : if ( *phLimiter != NULL )
710 : {
711 702 : ivas_limiter_close( phLimiter );
712 : }
713 :
714 11056 : if ( ( error = ivas_limiter_open( phLimiter, numChannels, sampleRate ) ) != IVAS_ERR_OK )
715 : {
716 0 : return error;
717 : }
718 :
719 11056 : return IVAS_ERR_OK;
720 : }
721 :
722 :
723 12948 : static LSSETUP_CUSTOM_STRUCT defaultCustomLs(
724 : void )
725 : {
726 : LSSETUP_CUSTOM_STRUCT ls;
727 :
728 : /* Set mono by default. This simplifies initialization,
729 : since output config is never in an undefined state. */
730 12948 : ls.is_planar_setup = 1;
731 12948 : ls.num_spk = 1;
732 12948 : set_zero( ls.ls_azimuth, MAX_OUTPUT_CHANNELS );
733 12948 : set_zero( ls.ls_elevation, MAX_OUTPUT_CHANNELS );
734 12948 : ls.num_lfe = 0;
735 12948 : set_s( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
736 12948 : ls.separate_ch_found = 0;
737 12948 : set_f( ls.separate_ch_gains, 0, MAX_OUTPUT_CHANNELS );
738 :
739 12948 : return ls;
740 : }
741 :
742 :
743 74940 : static ivas_error getSpeakerAzimuths(
744 : AUDIO_CONFIG config,
745 : const float **azimuths )
746 : {
747 74940 : switch ( config )
748 : {
749 618 : case IVAS_AUDIO_CONFIG_MONO:
750 618 : *azimuths = ls_azimuth_CICP1;
751 618 : break;
752 642 : case IVAS_AUDIO_CONFIG_STEREO:
753 642 : *azimuths = ls_azimuth_CICP2;
754 642 : break;
755 17070 : case IVAS_AUDIO_CONFIG_5_1:
756 17070 : *azimuths = ls_azimuth_CICP6;
757 17070 : break;
758 4232 : case IVAS_AUDIO_CONFIG_7_1:
759 4232 : *azimuths = ls_azimuth_CICP12;
760 4232 : break;
761 11520 : case IVAS_AUDIO_CONFIG_5_1_2:
762 11520 : *azimuths = ls_azimuth_CICP14;
763 11520 : break;
764 11556 : case IVAS_AUDIO_CONFIG_5_1_4:
765 11556 : *azimuths = ls_azimuth_CICP16;
766 11556 : break;
767 29302 : case IVAS_AUDIO_CONFIG_7_1_4:
768 29302 : *azimuths = ls_azimuth_CICP19;
769 29302 : break;
770 0 : default:
771 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
772 : }
773 :
774 74940 : return IVAS_ERR_OK;
775 : }
776 :
777 :
778 74940 : static ivas_error getSpeakerElevations(
779 : AUDIO_CONFIG config,
780 : const float **elevations )
781 : {
782 74940 : switch ( config )
783 : {
784 618 : case IVAS_AUDIO_CONFIG_MONO:
785 618 : *elevations = ls_elevation_CICP1;
786 618 : break;
787 642 : case IVAS_AUDIO_CONFIG_STEREO:
788 642 : *elevations = ls_elevation_CICP2;
789 642 : break;
790 17070 : case IVAS_AUDIO_CONFIG_5_1:
791 17070 : *elevations = ls_elevation_CICP6;
792 17070 : break;
793 4232 : case IVAS_AUDIO_CONFIG_7_1:
794 4232 : *elevations = ls_elevation_CICP12;
795 4232 : break;
796 11520 : case IVAS_AUDIO_CONFIG_5_1_2:
797 11520 : *elevations = ls_elevation_CICP14;
798 11520 : break;
799 11556 : case IVAS_AUDIO_CONFIG_5_1_4:
800 11556 : *elevations = ls_elevation_CICP16;
801 11556 : break;
802 29302 : case IVAS_AUDIO_CONFIG_7_1_4:
803 29302 : *elevations = ls_elevation_CICP19;
804 29302 : break;
805 0 : default:
806 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
807 : }
808 :
809 74940 : return IVAS_ERR_OK;
810 : }
811 :
812 :
813 3277086 : static ivas_error getAmbisonicsOrder(
814 : AUDIO_CONFIG config,
815 : int16_t *order )
816 : {
817 3277086 : switch ( config )
818 : {
819 1098242 : case IVAS_AUDIO_CONFIG_FOA:
820 1098242 : *order = 1;
821 1098242 : break;
822 1052918 : case IVAS_AUDIO_CONFIG_HOA2:
823 1052918 : *order = 2;
824 1052918 : break;
825 1125926 : case IVAS_AUDIO_CONFIG_HOA3:
826 1125926 : *order = 3;
827 1125926 : break;
828 0 : default:
829 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" );
830 : }
831 :
832 3277086 : return IVAS_ERR_OK;
833 : }
834 :
835 :
836 0 : static int16_t getNumLfeChannels(
837 : input_mc *inputMc )
838 : {
839 0 : switch ( inputMc->base.inConfig )
840 : {
841 0 : case IVAS_AUDIO_CONFIG_5_1:
842 : case IVAS_AUDIO_CONFIG_7_1:
843 : case IVAS_AUDIO_CONFIG_5_1_2:
844 : case IVAS_AUDIO_CONFIG_5_1_4:
845 : case IVAS_AUDIO_CONFIG_7_1_4:
846 0 : return 1;
847 0 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
848 0 : return inputMc->customLsInput.num_lfe;
849 0 : default:
850 0 : break;
851 : }
852 :
853 0 : return 0;
854 : }
855 :
856 7478 : static ivas_error getNumNonLfeChannelsInSpeakerLayout(
857 : AUDIO_CONFIG config,
858 : int16_t *numNonLfeChannels )
859 : {
860 7478 : switch ( config )
861 : {
862 618 : case IVAS_AUDIO_CONFIG_MONO:
863 618 : *numNonLfeChannels = 1;
864 618 : break;
865 642 : case IVAS_AUDIO_CONFIG_STEREO:
866 642 : *numNonLfeChannels = 2;
867 642 : break;
868 676 : case IVAS_AUDIO_CONFIG_5_1:
869 676 : *numNonLfeChannels = 5;
870 676 : break;
871 1176 : case IVAS_AUDIO_CONFIG_5_1_2:
872 : case IVAS_AUDIO_CONFIG_7_1:
873 1176 : *numNonLfeChannels = 7;
874 1176 : break;
875 624 : case IVAS_AUDIO_CONFIG_5_1_4:
876 624 : *numNonLfeChannels = 9;
877 624 : break;
878 3742 : case IVAS_AUDIO_CONFIG_7_1_4:
879 3742 : *numNonLfeChannels = 11;
880 3742 : break;
881 0 : default:
882 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
883 : }
884 :
885 7478 : return IVAS_ERR_OK;
886 : }
887 :
888 111946 : static ivas_error getMcConfigValues(
889 : AUDIO_CONFIG inConfig,
890 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs,
891 : const float **azimuth,
892 : const float **elevation,
893 : int16_t *lfe_idx,
894 : int16_t *is_planar )
895 : {
896 : int16_t i;
897 : ivas_error error;
898 :
899 111946 : *lfe_idx = -1;
900 111946 : *is_planar = 1;
901 111946 : switch ( inConfig )
902 : {
903 44484 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
904 44484 : *azimuth = (const float *) &pInCustomLs->ls_azimuth;
905 44484 : *elevation = (const float *) &pInCustomLs->ls_elevation;
906 44484 : if ( pInCustomLs->num_lfe > 0 )
907 : {
908 0 : *lfe_idx = pInCustomLs->lfe_idx[0];
909 : }
910 324468 : for ( i = 0; i < pInCustomLs->num_spk; i++ )
911 : {
912 324468 : if ( pInCustomLs->ls_elevation[i] != 0 )
913 : {
914 44484 : *is_planar = 0;
915 44484 : break;
916 : }
917 : }
918 44484 : break;
919 0 : case IVAS_AUDIO_CONFIG_MONO:
920 : case IVAS_AUDIO_CONFIG_STEREO:
921 0 : if ( ( error = getSpeakerAzimuths( inConfig, azimuth ) ) != IVAS_ERR_OK )
922 : {
923 0 : return error;
924 : }
925 0 : if ( ( error = getSpeakerElevations( inConfig, elevation ) ) != IVAS_ERR_OK )
926 : {
927 0 : return error;
928 : }
929 0 : break;
930 67462 : case IVAS_AUDIO_CONFIG_5_1:
931 : case IVAS_AUDIO_CONFIG_7_1:
932 : case IVAS_AUDIO_CONFIG_5_1_2:
933 : case IVAS_AUDIO_CONFIG_5_1_4:
934 : case IVAS_AUDIO_CONFIG_7_1_4:
935 67462 : if ( ( error = getSpeakerAzimuths( inConfig, azimuth ) ) != IVAS_ERR_OK )
936 : {
937 0 : return error;
938 : }
939 67462 : if ( ( error = getSpeakerElevations( inConfig, elevation ) ) != IVAS_ERR_OK )
940 : {
941 0 : return error;
942 : }
943 67462 : *lfe_idx = LFE_CHANNEL;
944 67462 : *is_planar = ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ? 1 : 0;
945 67462 : break;
946 0 : default:
947 0 : assert( !"Invalid speaker config" );
948 : return IVAS_ERR_WRONG_PARAMS;
949 : }
950 :
951 111946 : return IVAS_ERR_OK;
952 : }
953 :
954 :
955 12018 : static ivas_error initEfap(
956 : EFAP_WRAPPER *pEfapWrapper,
957 : AUDIO_CONFIG outConfig,
958 : const LSSETUP_CUSTOM_STRUCT *pCustomLsOut )
959 : {
960 : ivas_error error;
961 : const float *azimuths;
962 : const float *elevations;
963 : int16_t numNonLfeChannels;
964 :
965 12018 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
966 : {
967 3120 : pEfapWrapper->speakerConfig = IVAS_AUDIO_CONFIG_7_1_4;
968 : }
969 : else
970 : {
971 8898 : pEfapWrapper->speakerConfig = outConfig;
972 : }
973 12018 : pEfapWrapper->pCustomLsSetup = pCustomLsOut;
974 :
975 : /* If re-initializing, free existing EFAP handle. */
976 12018 : if ( pEfapWrapper->hEfap != NULL )
977 : {
978 702 : efap_free_data( &pEfapWrapper->hEfap );
979 : }
980 :
981 : /* Only initialize EFAP handle if output config is channel-based */
982 12018 : if ( getAudioConfigType( pEfapWrapper->speakerConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
983 : {
984 3028 : pEfapWrapper->hEfap = NULL;
985 3028 : return IVAS_ERR_OK;
986 : }
987 :
988 8990 : if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
989 : {
990 2034 : if ( ( error = efap_init_data( &pEfapWrapper->hEfap, pCustomLsOut->ls_azimuth, pCustomLsOut->ls_elevation, pCustomLsOut->num_spk, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK )
991 : {
992 0 : return error;
993 : }
994 : }
995 : else
996 : {
997 6956 : if ( ( error = getSpeakerAzimuths( pEfapWrapper->speakerConfig, &azimuths ) ) != IVAS_ERR_OK )
998 : {
999 0 : return error;
1000 : }
1001 :
1002 6956 : if ( ( error = getSpeakerElevations( pEfapWrapper->speakerConfig, &elevations ) ) != IVAS_ERR_OK )
1003 : {
1004 0 : return error;
1005 : }
1006 :
1007 6956 : if ( ( error = getNumNonLfeChannelsInSpeakerLayout( pEfapWrapper->speakerConfig, &numNonLfeChannels ) ) != IVAS_ERR_OK )
1008 : {
1009 0 : return error;
1010 : }
1011 :
1012 6956 : if ( ( error = efap_init_data( &pEfapWrapper->hEfap, azimuths, elevations, numNonLfeChannels, EFAP_MODE_EFAP ) ) != IVAS_ERR_OK )
1013 : {
1014 0 : return error;
1015 : }
1016 : }
1017 :
1018 8990 : return IVAS_ERR_OK;
1019 : }
1020 :
1021 :
1022 2933694 : static ivas_error getEfapGains(
1023 : EFAP_WRAPPER efapWrapper,
1024 : const float azi,
1025 : const float ele,
1026 : pan_vector panGains )
1027 : {
1028 : pan_vector tmpPanGains; /* tmp pan gain buffer without LFE channels */
1029 : float *readPtr;
1030 : int16_t i;
1031 : int16_t lfeCount;
1032 : int16_t numChannels;
1033 : ivas_error error;
1034 :
1035 : /* EFAP returns an array of gains only for non-LFE speakers */
1036 2933694 : efap_determine_gains( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
1037 :
1038 : /* Now copy to buffer that includes LFE channels */
1039 2933694 : if ( efapWrapper.speakerConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
1040 : {
1041 192690 : numChannels = efapWrapper.pCustomLsSetup->num_spk + efapWrapper.pCustomLsSetup->num_lfe;
1042 192690 : readPtr = tmpPanGains;
1043 :
1044 2504778 : for ( i = 0, lfeCount = 0; i < numChannels; ++i )
1045 : {
1046 2312088 : if ( lfeCount < efapWrapper.pCustomLsSetup->num_lfe && i == efapWrapper.pCustomLsSetup->lfe_idx[lfeCount] )
1047 : {
1048 0 : panGains[i] = 0.0f;
1049 0 : ++lfeCount;
1050 : }
1051 : else
1052 : {
1053 2312088 : panGains[i] = *readPtr;
1054 2312088 : ++readPtr;
1055 : }
1056 : }
1057 : }
1058 : else
1059 : {
1060 2741004 : if ( ( error = getAudioConfigNumChannels( efapWrapper.speakerConfig, &numChannels ) ) != IVAS_ERR_OK )
1061 : {
1062 0 : return error;
1063 : }
1064 :
1065 2741004 : readPtr = tmpPanGains;
1066 :
1067 32166768 : for ( i = 0; i < numChannels; ++i )
1068 : {
1069 29425764 : if ( i == LFE_CHANNEL )
1070 : {
1071 2612328 : panGains[i] = 0.0f;
1072 : }
1073 : else
1074 : {
1075 26813436 : panGains[i] = *readPtr;
1076 26813436 : ++readPtr;
1077 : }
1078 : }
1079 : }
1080 :
1081 2933694 : return IVAS_ERR_OK;
1082 : }
1083 :
1084 :
1085 1966 : static ivas_error initHeadRotation(
1086 : IVAS_REND_HANDLE hIvasRend )
1087 : {
1088 : int16_t i, crossfade_len;
1089 : float tmp;
1090 : ivas_error error;
1091 :
1092 : /* Head rotation is enabled by default */
1093 1966 : hIvasRend->headRotData.headRotEnabled = 1;
1094 :
1095 : /* Initialize 5ms crossfade */
1096 1966 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
1097 1966 : tmp = 1.f / ( crossfade_len - 1 );
1098 473806 : for ( i = 0; i < crossfade_len; i++ )
1099 : {
1100 471840 : hIvasRend->headRotData.crossfade[i] = i * tmp;
1101 : }
1102 :
1103 : /* Initialize with unit quaternions */
1104 7310 : for ( i = 0; i < hIvasRend->num_subframes; ++i )
1105 : {
1106 5344 : hIvasRend->headRotData.headPositions[i] = quaternionInit();
1107 : }
1108 :
1109 1966 : hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
1110 :
1111 1966 : if ( ( hIvasRend->headRotData.hOrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ) ) == NULL )
1112 : {
1113 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Orientation tracking" );
1114 : }
1115 :
1116 1966 : if ( ( error = ivas_orient_trk_Init( hIvasRend->headRotData.hOrientationTracker ) ) != IVAS_ERR_OK )
1117 : {
1118 0 : return error;
1119 : }
1120 :
1121 1966 : return IVAS_ERR_OK;
1122 : }
1123 :
1124 10354 : static void closeHeadRotation(
1125 : IVAS_REND_HANDLE hIvasRend )
1126 : {
1127 10354 : if ( hIvasRend != NULL && hIvasRend->headRotData.headRotEnabled && hIvasRend->headRotData.hOrientationTracker != NULL )
1128 : {
1129 1966 : free( hIvasRend->headRotData.hOrientationTracker );
1130 : }
1131 :
1132 10354 : return;
1133 : }
1134 :
1135 :
1136 15940 : static void initRotMatrix(
1137 : rotation_matrix rot_mat )
1138 : {
1139 : int16_t i;
1140 :
1141 : /* Initialize rotation matrices */
1142 63760 : for ( i = 0; i < 3; i++ )
1143 : {
1144 47820 : set_zero( rot_mat[i], 3 );
1145 47820 : rot_mat[i][i] = 1.f;
1146 : }
1147 :
1148 15940 : return;
1149 : }
1150 :
1151 :
1152 53952 : static void initRotGains(
1153 : rotation_gains rot_gains )
1154 : {
1155 : int16_t i;
1156 :
1157 : /* Set gains to passthrough */
1158 917184 : for ( i = 0; i < MAX_INPUT_CHANNELS; i++ )
1159 : {
1160 863232 : set_zero( rot_gains[i], MAX_INPUT_CHANNELS );
1161 863232 : rot_gains[i][i] = 1.f;
1162 : }
1163 :
1164 53952 : return;
1165 : }
1166 :
1167 :
1168 170368 : static void initRendInputBase(
1169 : input_base *inputBase,
1170 : const AUDIO_CONFIG inConfig,
1171 : const IVAS_REND_InputId id,
1172 : const rendering_context rendCtx,
1173 : float *dataBuf,
1174 : const int16_t dataBufSize )
1175 : {
1176 170368 : inputBase->inConfig = inConfig;
1177 170368 : inputBase->id = id;
1178 170368 : inputBase->gain = 1.0f;
1179 170368 : inputBase->ctx = rendCtx;
1180 170368 : inputBase->numNewSamplesPerChannel = 0;
1181 170368 : inputBase->delayNumSamples = 0;
1182 170368 : inputBase->delayBuffer = NULL;
1183 :
1184 170368 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
1185 170368 : inputBase->inputBuffer.config.numChannels = 0;
1186 170368 : inputBase->inputBuffer.data = dataBuf;
1187 170368 : if ( inputBase->inputBuffer.data != NULL )
1188 : {
1189 25412 : set_zero( inputBase->inputBuffer.data, dataBufSize );
1190 : }
1191 :
1192 170368 : return;
1193 : }
1194 :
1195 :
1196 3231120 : static IVAS_ISM_METADATA defaultObjectPosition(
1197 : void )
1198 : {
1199 : IVAS_ISM_METADATA pos;
1200 :
1201 3231120 : pos.azimuth = 0.0f;
1202 3231120 : pos.elevation = 0.0f;
1203 3231120 : pos.radius = 1.0f;
1204 3231120 : pos.spread = 0.0f;
1205 3231120 : pos.gainFactor = 1.0f;
1206 3231120 : pos.yaw = 0.0f;
1207 3231120 : pos.pitch = 0.0f;
1208 3231120 : pos.non_diegetic_flag = 0;
1209 :
1210 3231120 : return pos;
1211 : }
1212 :
1213 :
1214 10138530 : static int8_t checkObjectPositionChanged(
1215 : IVAS_ISM_METADATA *currentPos,
1216 : IVAS_ISM_METADATA *previousPos )
1217 : {
1218 18754814 : return !( fabs( currentPos->azimuth - previousPos->azimuth ) < EPSILON &&
1219 8616284 : fabs( currentPos->elevation - previousPos->elevation ) < EPSILON );
1220 : }
1221 :
1222 :
1223 72478 : static rendering_context getRendCtx(
1224 : IVAS_REND_HANDLE hIvasRend )
1225 : {
1226 : rendering_context ctx;
1227 :
1228 : /* Note: when refactoring this, always take the ADDRESS of a member of the
1229 : * renderer struct, so that the context stores a POINTER to the member, even
1230 : * if the member is a pointer or handle itself. */
1231 72478 : ctx.pMaxGlobalDelayNs = &hIvasRend->maxGlobalDelayNs;
1232 72478 : ctx.pOutConfig = &hIvasRend->outputConfig;
1233 72478 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
1234 72478 : ctx.pCustomLsOut = &hIvasRend->customLsOut;
1235 72478 : ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
1236 72478 : ctx.pHeadRotData = &hIvasRend->headRotData;
1237 72478 : ctx.hhRendererConfig = &hIvasRend->hRendererConfig;
1238 72478 : ctx.pSplitRendBFI = &hIvasRend->splitRendBFI;
1239 72478 : ctx.pSplitRendWrapper = hIvasRend->splitRendWrapper;
1240 72478 : ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
1241 72478 : ctx.pSelectedRoomReverbSize = &hIvasRend->selectedRoomReverbSize;
1242 :
1243 72478 : return ctx;
1244 : }
1245 :
1246 :
1247 148272 : static TDREND_WRAPPER defaultTdRendWrapper(
1248 : void )
1249 : {
1250 : TDREND_WRAPPER w;
1251 :
1252 148272 : w.binaural_latency_ns = 0;
1253 148272 : w.hBinRendererTd = NULL;
1254 148272 : w.hHrtfTD = NULL;
1255 :
1256 148272 : return w;
1257 : }
1258 :
1259 :
1260 25412 : static bool isIoConfigPairSupported(
1261 : const AUDIO_CONFIG inConfig,
1262 : const AUDIO_CONFIG outConfig )
1263 : {
1264 : /* Rendering mono or stereo to binaural is not supported */
1265 25412 : if ( ( inConfig == IVAS_AUDIO_CONFIG_MONO || inConfig == IVAS_AUDIO_CONFIG_STEREO ) && getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
1266 : {
1267 0 : return false;
1268 : }
1269 :
1270 : /* If not returned so far, config pair is supported */
1271 25412 : return true;
1272 : }
1273 :
1274 :
1275 61078 : static int32_t getRendInputDelayIsm(
1276 : const input_ism *inputIsm,
1277 : bool splitPreRendCldfb )
1278 : {
1279 : int32_t latency_ns;
1280 61078 : latency_ns = 0;
1281 : (void) ( splitPreRendCldfb ); /* unused */
1282 :
1283 : /* set the rendering delay in InputBase */
1284 61078 : latency_ns = max( latency_ns,
1285 : inputIsm->tdRendWrapper.binaural_latency_ns );
1286 61078 : if ( inputIsm->crendWrapper != NULL )
1287 : {
1288 5580 : latency_ns = max( latency_ns,
1289 : inputIsm->crendWrapper->binaural_latency_ns );
1290 : }
1291 :
1292 61078 : return latency_ns;
1293 : }
1294 :
1295 :
1296 15940 : static void setRendInputDelayIsm(
1297 : void *input,
1298 : bool splitPreRendCldfb )
1299 : {
1300 : input_ism *inputIsm;
1301 15940 : inputIsm = (input_ism *) input;
1302 :
1303 15940 : inputIsm->base.delayNumSamples = latencyNsToSamples( *inputIsm->base.ctx.pOutSampleRate,
1304 : getRendInputDelayIsm( inputIsm, splitPreRendCldfb ) );
1305 15940 : }
1306 :
1307 :
1308 6018 : static int32_t getRendInputDelayMc(
1309 : const input_mc *inputMc,
1310 : bool splitPreRendCldfb )
1311 : {
1312 : int32_t latency_ns;
1313 6018 : latency_ns = 0;
1314 : (void) ( splitPreRendCldfb ); /* unused */
1315 :
1316 6018 : latency_ns = max( latency_ns,
1317 : inputMc->tdRendWrapper.binaural_latency_ns );
1318 6018 : if ( inputMc->crendWrapper != NULL )
1319 : {
1320 1418 : latency_ns = max( latency_ns,
1321 : inputMc->crendWrapper->binaural_latency_ns );
1322 : }
1323 :
1324 6018 : return latency_ns;
1325 : }
1326 :
1327 :
1328 2594 : static void setRendInputDelayMc(
1329 : void *input,
1330 : bool splitPreRendCldfb )
1331 : {
1332 : input_mc *inputMc;
1333 2594 : inputMc = (input_mc *) input;
1334 :
1335 2594 : inputMc->base.delayNumSamples = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate,
1336 : getRendInputDelayMc( inputMc, splitPreRendCldfb ) );
1337 2594 : }
1338 :
1339 :
1340 8514 : static int32_t getRendInputDelaySba(
1341 : const input_sba *inputSba,
1342 : bool splitPreRendCldfb )
1343 : {
1344 : int32_t latency_ns;
1345 8514 : latency_ns = 0;
1346 :
1347 8514 : if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
1348 : {
1349 24 : latency_ns = max( latency_ns,
1350 : inputSba->cldfbRendWrapper.binaural_latency_ns +
1351 : ( splitPreRendCldfb ? 0 : IVAS_FB_DEC_DELAY_NS ) );
1352 : }
1353 8514 : if ( inputSba->crendWrapper != NULL )
1354 : {
1355 4002 : latency_ns = max( latency_ns,
1356 : inputSba->crendWrapper->binaural_latency_ns );
1357 : }
1358 :
1359 8514 : return latency_ns;
1360 : }
1361 :
1362 :
1363 4150 : static void setRendInputDelaySba(
1364 : void *input,
1365 : bool splitPreRendCldfb )
1366 : {
1367 : input_sba *inputSba;
1368 4150 : inputSba = (input_sba *) input;
1369 :
1370 4150 : inputSba->base.delayNumSamples = latencyNsToSamples( *inputSba->base.ctx.pOutSampleRate,
1371 : getRendInputDelaySba( inputSba, splitPreRendCldfb ) );
1372 4150 : }
1373 :
1374 :
1375 5592 : static int32_t getRendInputDelayMasa(
1376 : const input_masa *inputMasa,
1377 : bool splitPreRendCldfb )
1378 : {
1379 : int32_t latency_ns;
1380 :
1381 5592 : latency_ns = 0;
1382 :
1383 11064 : if ( ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 && *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_MONO ) ||
1384 5472 : ( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
1385 : {
1386 384 : return 0; /* no delay */
1387 : }
1388 : else
1389 : {
1390 : /* no delay applied for split rendering */
1391 5208 : latency_ns = max( latency_ns,
1392 : (int32_t) ( ( splitPreRendCldfb ? 0 : (float) IVAS_FB_DEC_DELAY_NS + 0.5f ) ) );
1393 : }
1394 5208 : return latency_ns;
1395 : }
1396 :
1397 :
1398 2728 : static void setRendInputDelayMasa(
1399 : void *input,
1400 : bool splitPreRendCldfb )
1401 : {
1402 : input_masa *inputMasa;
1403 2728 : inputMasa = (input_masa *) input;
1404 :
1405 2728 : inputMasa->base.delayNumSamples = latencyNsToSamples( *inputMasa->base.ctx.pOutSampleRate,
1406 : getRendInputDelayMasa( inputMasa, splitPreRendCldfb ) );
1407 2728 : }
1408 :
1409 :
1410 25884 : static int32_t getMaxGlobalDelayNs( IVAS_REND_CONST_HANDLE hIvasRend )
1411 : {
1412 : int16_t i;
1413 : int32_t latency_ns;
1414 : int32_t max_latency_ns;
1415 : bool splitPreRendCldfb;
1416 :
1417 25884 : max_latency_ns = 0;
1418 : /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/
1419 25884 : if ( hIvasRend->hRendererConfig != NULL )
1420 : {
1421 11538 : splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD );
1422 : }
1423 : else
1424 : {
1425 14346 : splitPreRendCldfb = false;
1426 : }
1427 :
1428 : /* Compute the maximum delay across all inputs */
1429 129420 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
1430 : {
1431 103536 : if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1432 : {
1433 45138 : latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb );
1434 45138 : max_latency_ns = max( max_latency_ns, latency_ns );
1435 : }
1436 : }
1437 :
1438 51768 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
1439 : {
1440 25884 : if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1441 : {
1442 3424 : latency_ns = getRendInputDelayMc( &hIvasRend->inputsMc[i], splitPreRendCldfb );
1443 3424 : max_latency_ns = max( max_latency_ns, latency_ns );
1444 : }
1445 : }
1446 :
1447 51768 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
1448 : {
1449 25884 : if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1450 : {
1451 4364 : latency_ns = getRendInputDelaySba( &hIvasRend->inputsSba[i], splitPreRendCldfb );
1452 4364 : max_latency_ns = max( max_latency_ns, latency_ns );
1453 : }
1454 : }
1455 :
1456 51768 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
1457 : {
1458 25884 : if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1459 : {
1460 2864 : latency_ns = getRendInputDelayMasa( &hIvasRend->inputsMasa[i], splitPreRendCldfb );
1461 2864 : max_latency_ns = max( max_latency_ns, latency_ns );
1462 : }
1463 : }
1464 :
1465 25884 : return max_latency_ns;
1466 : }
1467 :
1468 :
1469 25412 : static void setMaxGlobalDelayNs( IVAS_REND_HANDLE hIvasRend )
1470 : {
1471 25412 : hIvasRend->maxGlobalDelayNs = getMaxGlobalDelayNs( (IVAS_REND_CONST_HANDLE) hIvasRend );
1472 25412 : }
1473 :
1474 22816121 : static ivas_error alignInputDelay(
1475 : input_base *inputBase,
1476 : const IVAS_REND_ReadOnlyAudioBuffer inputAudio,
1477 : const int32_t maxGlobalDelayNs,
1478 : const int32_t sampleRateOut,
1479 : const int16_t cldfb2tdSampleFact,
1480 : const bool flushInputs )
1481 : {
1482 : ivas_error error;
1483 : input_ism *inputIsm;
1484 : int16_t maxGlobalDelaySamples, numSamplesToPop, numSamplesToPush;
1485 : uint16_t ringBufferSize, preDelay;
1486 : int16_t i;
1487 : const float *p_read_channels[MAX_INPUT_CHANNELS];
1488 : float *p_write_channels[MAX_INPUT_CHANNELS];
1489 :
1490 22816121 : maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs );
1491 22816121 : maxGlobalDelaySamples *= cldfb2tdSampleFact;
1492 :
1493 : /* check if we need to open the delay buffer */
1494 22816121 : if ( inputBase->delayBuffer == NULL )
1495 : {
1496 : /* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */
1497 19469017 : ringBufferSize = maxGlobalDelaySamples + 2 * inputAudio.config.numSamplesPerChannel;
1498 :
1499 : /* pre delay for this input is maximum delay - input delay */
1500 19469017 : preDelay = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact;
1501 :
1502 19469017 : if ( preDelay > 0 )
1503 : {
1504 6604 : if ( ( error = ivas_TD_RINGBUF_Open( &inputBase->delayBuffer, ringBufferSize, inputAudio.config.numChannels ) ) != IVAS_ERR_OK )
1505 : {
1506 0 : return error;
1507 : }
1508 :
1509 : /* for the first frame we need to push zeros to align the input delay to the global delay
1510 : * and then push a frame of actual data */
1511 6604 : ivas_TD_RINGBUF_PushConstant( inputBase->delayBuffer, 0, preDelay );
1512 :
1513 : /* for ISM inputs, ensure the metadata sync delay is updated */
1514 6604 : if ( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
1515 : {
1516 4970 : inputIsm = (input_ism *) inputBase;
1517 4970 : inputIsm->ism_metadata_delay_ms = (int16_t) roundf( inputIsm->ism_metadata_delay_ms + maxGlobalDelayNs / 1e6f );
1518 : }
1519 : }
1520 : }
1521 :
1522 22816121 : if ( inputBase->delayBuffer != NULL )
1523 : {
1524 : /* push in the new input data and pop to retrieve a complete input frame
1525 : * if we are flushing the inputs, we don't push in any new data */
1526 3353708 : numSamplesToPush = flushInputs ? 0 : inputAudio.config.numSamplesPerChannel;
1527 3353708 : numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : inputAudio.config.numSamplesPerChannel;
1528 :
1529 19471568 : for ( i = 0; i < inputAudio.config.numChannels; ++i )
1530 : {
1531 16117860 : p_read_channels[i] = inputAudio.data + i * numSamplesToPush;
1532 : }
1533 3353708 : ivas_TD_RINGBUF_PushChannels( inputBase->delayBuffer, p_read_channels, (int16_t) numSamplesToPush );
1534 :
1535 19471568 : for ( i = 0; i < inputAudio.config.numChannels; ++i )
1536 : {
1537 16117860 : p_write_channels[i] = inputBase->inputBuffer.data + i * numSamplesToPop;
1538 : }
1539 3353708 : ivas_TD_RINGBUF_PopChannels( inputBase->delayBuffer, p_write_channels, (int16_t) numSamplesToPop );
1540 : }
1541 : else
1542 : {
1543 : /* delay buffer isn't open - we don't need it */
1544 19462413 : mvr2r( inputAudio.data,
1545 : inputBase->inputBuffer.data,
1546 19462413 : inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
1547 : }
1548 :
1549 22816121 : return IVAS_ERR_OK;
1550 : }
1551 :
1552 132 : static ivas_error initIsmMasaRendering(
1553 : input_ism *inputIsm,
1554 : const int32_t inSampleRate )
1555 : {
1556 : ivas_error error;
1557 :
1558 132 : if ( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1559 : {
1560 0 : ivas_td_binaural_close( &inputIsm->tdRendWrapper.hBinRendererTd );
1561 : }
1562 :
1563 132 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1564 :
1565 132 : ivas_reverb_close( &inputIsm->hReverb );
1566 :
1567 132 : if ( ( error = ivas_omasa_ana_open( &inputIsm->hOMasa, inSampleRate, inputIsm->total_num_objects ) ) != IVAS_ERR_OK )
1568 : {
1569 0 : return error;
1570 : }
1571 :
1572 132 : return IVAS_ERR_OK;
1573 : }
1574 :
1575 :
1576 15940 : static ivas_error setRendInputActiveIsm(
1577 : void *input,
1578 : const AUDIO_CONFIG inConfig,
1579 : const IVAS_REND_InputId id,
1580 : RENDER_CONFIG_DATA *hRendCfg,
1581 : hrtf_handles *hrtfs )
1582 : {
1583 : ivas_error error;
1584 : rendering_context rendCtx;
1585 : AUDIO_CONFIG outConfig;
1586 : input_ism *inputIsm;
1587 : int16_t i;
1588 :
1589 15940 : inputIsm = (input_ism *) input;
1590 15940 : rendCtx = inputIsm->base.ctx;
1591 15940 : outConfig = *rendCtx.pOutConfig;
1592 :
1593 15940 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
1594 : {
1595 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
1596 : }
1597 :
1598 15940 : if ( ( error = allocateInputBaseBufferData( &inputIsm->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
1599 : {
1600 0 : return error;
1601 : }
1602 15940 : initRendInputBase( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData, MAX_BUFFER_LENGTH );
1603 :
1604 15940 : inputIsm->firstFrameRendered = FALSE;
1605 :
1606 15940 : inputIsm->currentPos = defaultObjectPosition();
1607 15940 : inputIsm->previousPos = defaultObjectPosition();
1608 15940 : inputIsm->crendWrapper = NULL;
1609 15940 : inputIsm->hReverb = NULL;
1610 15940 : inputIsm->tdRendWrapper = defaultTdRendWrapper();
1611 15940 : initRotMatrix( inputIsm->rot_mat_prev );
1612 15940 : set_zero( inputIsm->prev_pan_gains, MAX_OUTPUT_CHANNELS );
1613 :
1614 127520 : for ( i = 0; i < (int16_t) ( sizeof( inputIsm->splitTdRendWrappers ) / sizeof( *inputIsm->splitTdRendWrappers ) ); ++i )
1615 : {
1616 111580 : inputIsm->splitTdRendWrappers[i] = defaultTdRendWrapper();
1617 111580 : inputIsm->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
1618 : }
1619 :
1620 15940 : inputIsm->hOMasa = NULL;
1621 :
1622 15940 : error = IVAS_ERR_OK;
1623 15940 : inputIsm->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
1624 :
1625 15940 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
1626 : {
1627 1938 : if ( ( error = ivas_td_binaural_open_ext( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, inputIsm->object_id ) ) != IVAS_ERR_OK )
1628 : {
1629 0 : return error;
1630 : }
1631 :
1632 : /* Open TD renderer wrappers */
1633 15504 : for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
1634 : {
1635 13566 : if ( ( error = ivas_td_binaural_open_ext( &inputIsm->splitTdRendWrappers[i], inConfig, hRendCfg, NULL, *inputIsm->base.ctx.pOutSampleRate, inputIsm->object_id ) ) != IVAS_ERR_OK )
1636 : {
1637 0 : return error;
1638 : }
1639 :
1640 : /* Assert same delay as main TD renderer */
1641 13566 : assert( inputIsm->splitTdRendWrappers[i].binaural_latency_ns == inputIsm->tdRendWrapper.binaural_latency_ns );
1642 : }
1643 : }
1644 14002 : else if ( outConfig == IVAS_AUDIO_CONFIG_MASA1 || outConfig == IVAS_AUDIO_CONFIG_MASA2 )
1645 : {
1646 132 : if ( ( error = initIsmMasaRendering( inputIsm, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
1647 : {
1648 0 : return error;
1649 : }
1650 : }
1651 : else
1652 : {
1653 13870 : if ( ( error = ivas_td_binaural_open_ext( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, inputIsm->object_id ) ) != IVAS_ERR_OK )
1654 : {
1655 0 : return error;
1656 : }
1657 :
1658 13870 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
1659 : {
1660 3620 : if ( ( error = ivas_reverb_open( &( inputIsm->hReverb ), hrtfs->hHrtfStatistics, hRendCfg, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
1661 : {
1662 0 : return error;
1663 : }
1664 : }
1665 10250 : else if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
1666 : {
1667 1460 : if ( ( error = ivas_rend_openCrend( &inputIsm->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics, *rendCtx.pOutSampleRate, 1, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ) != IVAS_ERR_OK )
1668 : {
1669 0 : return error;
1670 : }
1671 : }
1672 : }
1673 :
1674 15940 : return IVAS_ERR_OK;
1675 : }
1676 :
1677 :
1678 41416 : static void clearInputIsm(
1679 : input_ism *inputIsm )
1680 : {
1681 : rendering_context rendCtx;
1682 : int16_t i;
1683 :
1684 41416 : rendCtx = inputIsm->base.ctx;
1685 :
1686 41416 : freeInputBaseBufferData( &inputIsm->base.inputBuffer.data );
1687 41416 : ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer );
1688 :
1689 41416 : initRendInputBase( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
1690 :
1691 : /* Free input's internal handles */
1692 41416 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1693 :
1694 41416 : ivas_reverb_close( &inputIsm->hReverb );
1695 :
1696 41416 : if ( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1697 : {
1698 15808 : ivas_td_binaural_close( &inputIsm->tdRendWrapper.hBinRendererTd );
1699 : }
1700 :
1701 331328 : for ( i = 0; i < (int16_t) ( sizeof( inputIsm->splitTdRendWrappers ) / sizeof( *inputIsm->splitTdRendWrappers ) ); ++i )
1702 : {
1703 289912 : ivas_td_binaural_close( &inputIsm->splitTdRendWrappers[i].hBinRendererTd );
1704 : }
1705 :
1706 41416 : ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
1707 :
1708 41416 : return;
1709 : }
1710 :
1711 :
1712 492 : static void copyLsConversionMatrixToPanMatrix(
1713 : const LS_CONVERSION_MATRIX *lsConvMatrix,
1714 : pan_matrix panMatrix )
1715 : {
1716 : int16_t i;
1717 : int16_t inCh, outCh;
1718 : int16_t numNonZeroGains;
1719 : int16_t numColumns;
1720 :
1721 : /* Index 0 is special and describes the following values */
1722 492 : numNonZeroGains = lsConvMatrix[0].index;
1723 492 : numColumns = (int16_t) lsConvMatrix[0].value;
1724 :
1725 5084 : for ( i = 1; i < numNonZeroGains + 1; ++i )
1726 : {
1727 4592 : inCh = lsConvMatrix[i].index / numColumns;
1728 4592 : outCh = lsConvMatrix[i].index % numColumns;
1729 :
1730 4592 : panMatrix[inCh][outCh] = lsConvMatrix[i].value;
1731 : }
1732 :
1733 492 : return;
1734 : }
1735 :
1736 :
1737 14118 : static void setZeroPanMatrix(
1738 : pan_matrix panMatrix )
1739 : {
1740 : int16_t i;
1741 :
1742 240006 : for ( i = 0; i < MAX_INPUT_CHANNELS; ++i )
1743 : {
1744 225888 : set_zero( panMatrix[i], MAX_OUTPUT_CHANNELS );
1745 : }
1746 :
1747 14118 : return;
1748 : }
1749 :
1750 :
1751 : /* Note: this only sets non-zero elements, call setZeroPanMatrix() to init first. */
1752 1058 : static void fillIdentityPanMatrix(
1753 : pan_matrix panMatrix )
1754 : {
1755 : int16_t i;
1756 :
1757 17986 : for ( i = 0; i < min( MAX_INPUT_CHANNELS, MAX_OUTPUT_CHANNELS ); ++i )
1758 : {
1759 16928 : panMatrix[i][i] = 1.0f;
1760 : }
1761 :
1762 1058 : return;
1763 : }
1764 :
1765 :
1766 214 : static ivas_error initMcPanGainsWithIdentMatrix(
1767 : input_mc *inputMc )
1768 : {
1769 214 : fillIdentityPanMatrix( inputMc->panGains );
1770 :
1771 214 : return IVAS_ERR_OK;
1772 : }
1773 :
1774 :
1775 760 : static ivas_error initMcPanGainsWithConversionMapping(
1776 : input_mc *inputMc,
1777 : const AUDIO_CONFIG outConfig )
1778 : {
1779 : AUDIO_CONFIG ivasConfigIn, ivasConfigOut;
1780 : int16_t i;
1781 :
1782 760 : ivasConfigIn = inputMc->base.inConfig;
1783 760 : ivasConfigOut = outConfig;
1784 :
1785 : /* Find conversion mapping for current I/O config pair.
1786 : * Stay with default panning matrix if conversion_matrix is NULL */
1787 24460 : for ( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; ++i )
1788 : {
1789 24460 : if ( ls_conversion_mapping[i].input_config == ivasConfigIn && ls_conversion_mapping[i].output_config == ivasConfigOut )
1790 : {
1791 : /* Mapping found with valid matrix - copy */
1792 760 : if ( ls_conversion_mapping[i].conversion_matrix != NULL )
1793 : {
1794 492 : copyLsConversionMatrixToPanMatrix( ls_conversion_mapping[i].conversion_matrix, inputMc->panGains );
1795 : }
1796 : /* Mapping found with NULL matrix - use identity matrix */
1797 : else
1798 : {
1799 268 : fillIdentityPanMatrix( inputMc->panGains );
1800 : }
1801 :
1802 760 : return IVAS_ERR_OK;
1803 : }
1804 : }
1805 :
1806 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" );
1807 : }
1808 :
1809 :
1810 1080 : static ivas_error initMcPanGainsWithEfap(
1811 : input_mc *inputMc,
1812 : const AUDIO_CONFIG outConfig )
1813 : {
1814 : int16_t i;
1815 : int16_t numNonLfeInChannels;
1816 : int16_t inLfeChIdx, outChIdx;
1817 : const float *spkAzi, *spkEle;
1818 : ivas_error error;
1819 :
1820 1080 : if ( inputMc->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
1821 : {
1822 198 : if ( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK )
1823 : {
1824 0 : return error;
1825 : }
1826 :
1827 198 : if ( ( error = getSpeakerAzimuths( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK )
1828 : {
1829 0 : return error;
1830 : }
1831 :
1832 198 : if ( ( error = getSpeakerElevations( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK )
1833 : {
1834 0 : return error;
1835 : }
1836 :
1837 198 : inLfeChIdx = LFE_CHANNEL;
1838 : }
1839 : else
1840 : {
1841 882 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
1842 882 : spkAzi = inputMc->customLsInput.ls_azimuth;
1843 882 : spkEle = inputMc->customLsInput.ls_elevation;
1844 882 : inLfeChIdx = -1;
1845 882 : if ( inputMc->customLsInput.num_lfe > 0 )
1846 : {
1847 0 : inLfeChIdx = inputMc->customLsInput.lfe_idx[0];
1848 : }
1849 : }
1850 :
1851 7542 : for ( i = 0, outChIdx = 0; i < numNonLfeInChannels; ++i, ++outChIdx )
1852 : {
1853 6462 : if ( i == inLfeChIdx )
1854 : {
1855 90 : ++outChIdx;
1856 : }
1857 :
1858 6462 : if ( ( error = getEfapGains( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains[outChIdx] ) ) != IVAS_ERR_OK )
1859 : {
1860 0 : return error;
1861 : }
1862 : }
1863 :
1864 1080 : if ( outConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inLfeChIdx >= 0 )
1865 : {
1866 72 : inputMc->panGains[inLfeChIdx][LFE_CHANNEL] = 1;
1867 : }
1868 1008 : else if ( inputMc->base.ctx.pCustomLsOut->num_lfe > 0 && inLfeChIdx >= 0 )
1869 : {
1870 0 : inputMc->panGains[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = 1;
1871 : }
1872 :
1873 1080 : return IVAS_ERR_OK;
1874 : }
1875 :
1876 :
1877 29823922 : static ivas_error getRendInputNumChannels(
1878 : const void *rendInput,
1879 : int16_t *numInChannels )
1880 : {
1881 : /* Using a void pointer for this function to be reusable for any input type (input_ism, input_mc, input_sba).
1882 : Assumptions: - input_base is always the first member in the input struct */
1883 :
1884 : ivas_error error;
1885 : const input_base *pInputBase;
1886 : const input_mc *pInputMc;
1887 :
1888 29823922 : pInputBase = (const input_base *) rendInput;
1889 :
1890 29823922 : if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
1891 : {
1892 739140 : pInputMc = (const input_mc *) rendInput;
1893 739140 : *numInChannels = pInputMc->customLsInput.num_spk + pInputMc->customLsInput.num_lfe;
1894 : }
1895 : else
1896 : {
1897 29084782 : if ( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ) != IVAS_ERR_OK )
1898 : {
1899 0 : return error;
1900 : }
1901 : }
1902 :
1903 29823922 : return IVAS_ERR_OK;
1904 : }
1905 :
1906 :
1907 96 : static ivas_error initMcPanGainsWithMonoOut(
1908 : input_mc *inputMc )
1909 : {
1910 : int16_t i;
1911 : int16_t numInChannels;
1912 : int16_t readIdx;
1913 : int16_t writeIdx;
1914 : bool skipSideSpeakers;
1915 : ivas_error error;
1916 :
1917 96 : if ( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ) != IVAS_ERR_OK )
1918 : {
1919 0 : return error;
1920 : }
1921 :
1922 96 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
1923 : {
1924 0 : for ( i = 0; i < numInChannels; ++i )
1925 : {
1926 : /* It's OK to also set gain 1 for LFE input channels here.
1927 : * Correct LFE handling will be applied within updateMcPanGains() */
1928 0 : inputMc->panGains[i][0] = 1.f;
1929 : }
1930 : }
1931 96 : else if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_STEREO )
1932 : {
1933 : /* Special case for STEREO to MONO: Passive downmix (L+R)/2 */
1934 24 : inputMc->panGains[0][0] = 0.5;
1935 24 : inputMc->panGains[1][0] = 0.5;
1936 : }
1937 : else
1938 : {
1939 : /* ls_conversion_cicpX_stereo contains gains for side speakers.
1940 : * These should be skipped with 5.1+X inputs. */
1941 72 : skipSideSpeakers = false;
1942 72 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_2 || inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_4 )
1943 : {
1944 36 : skipSideSpeakers = true;
1945 : }
1946 720 : for ( readIdx = 0, writeIdx = 0; writeIdx < numInChannels; ++readIdx, ++writeIdx )
1947 : {
1948 648 : if ( skipSideSpeakers && readIdx == 4 )
1949 : {
1950 : /* Skip gains for side speakers in lookup table */
1951 36 : readIdx += 2;
1952 : }
1953 :
1954 648 : inputMc->panGains[writeIdx][0] = ls_conversion_cicpX_mono[readIdx][0];
1955 : }
1956 : }
1957 :
1958 96 : return IVAS_ERR_OK;
1959 : }
1960 :
1961 :
1962 72 : static ivas_error initMcPanGainsWithStereoLookup(
1963 : input_mc *inputMc )
1964 : {
1965 : int16_t readIdx;
1966 : int16_t writeIdx;
1967 : bool skipSideSpeakers;
1968 : int16_t numInChannels;
1969 : ivas_error error;
1970 :
1971 : /* Special case - MONO input.
1972 : * Use gains for center CICP speaker and return early. */
1973 72 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO )
1974 : {
1975 0 : inputMc->panGains[0][0] = ls_conversion_cicpX_stereo[2][0];
1976 0 : inputMc->panGains[0][1] = ls_conversion_cicpX_stereo[2][1];
1977 0 : return IVAS_ERR_OK;
1978 : }
1979 :
1980 : /* ls_conversion_cicpX_stereo contains gains for side speakers.
1981 : * These should be skipped with 5.1+X inputs. */
1982 72 : skipSideSpeakers = false;
1983 72 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_2 || inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_4 )
1984 : {
1985 36 : skipSideSpeakers = true;
1986 : }
1987 :
1988 72 : if ( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ) != IVAS_ERR_OK )
1989 : {
1990 0 : return error;
1991 : }
1992 :
1993 720 : for ( readIdx = 0, writeIdx = 0; writeIdx < numInChannels; ++readIdx, ++writeIdx )
1994 : {
1995 648 : if ( skipSideSpeakers && readIdx == 4 )
1996 : {
1997 : /* Skip gains for side speakers in lookup table */
1998 36 : readIdx += 2;
1999 : }
2000 :
2001 648 : inputMc->panGains[writeIdx][0] = ls_conversion_cicpX_stereo[readIdx][0];
2002 648 : inputMc->panGains[writeIdx][1] = ls_conversion_cicpX_stereo[readIdx][1];
2003 : }
2004 :
2005 72 : return IVAS_ERR_OK;
2006 : }
2007 :
2008 :
2009 : /* Returns 1 (true) if configs A and B are equal, otherwise returns 0 (false).
2010 : * If both configs are custom LS layouts, layout details are compared to determine equality. */
2011 2252 : static bool configsAreEqual(
2012 : const AUDIO_CONFIG configA,
2013 : const LSSETUP_CUSTOM_STRUCT customLsA,
2014 : const AUDIO_CONFIG configB,
2015 : const LSSETUP_CUSTOM_STRUCT customLsB )
2016 : {
2017 : int16_t i;
2018 :
2019 : /* Both input and output are custom LS - compare structs */
2020 2252 : if ( configA == IVAS_AUDIO_CONFIG_LS_CUSTOM && configB == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2021 : {
2022 108 : if ( customLsA.num_spk != customLsB.num_spk )
2023 : {
2024 90 : return false;
2025 : }
2026 :
2027 18 : if ( customLsA.num_lfe != customLsB.num_lfe )
2028 : {
2029 0 : return false;
2030 : }
2031 :
2032 18 : if ( customLsA.is_planar_setup != customLsB.is_planar_setup )
2033 : {
2034 0 : return false;
2035 : }
2036 :
2037 234 : for ( i = 0; i < customLsA.num_spk; ++i )
2038 : {
2039 : /* Compare to nearest degree (hence the int16_t cast) */
2040 216 : if ( (int16_t) customLsA.ls_azimuth[i] != (int16_t) customLsB.ls_azimuth[i] ||
2041 216 : (int16_t) customLsA.ls_elevation[i] != (int16_t) customLsB.ls_elevation[i] )
2042 : {
2043 0 : return false;
2044 : }
2045 : }
2046 18 : for ( i = 0; i < customLsA.num_lfe; ++i )
2047 : {
2048 0 : if ( customLsA.lfe_idx[i] != customLsB.lfe_idx[i] )
2049 : {
2050 0 : return false;
2051 : }
2052 : }
2053 :
2054 18 : return true;
2055 : }
2056 :
2057 : /* Otherwise it's enough to compare config enums */
2058 2144 : return configA == configB;
2059 : }
2060 :
2061 :
2062 2252 : static ivas_error updateLfePanGainsForMcOut(
2063 : input_mc *inputMc,
2064 : const AUDIO_CONFIG outConfig )
2065 : {
2066 : int16_t i, numLfeIn, numOutChannels;
2067 : ivas_error error;
2068 2252 : error = IVAS_ERR_OK;
2069 :
2070 : /* If panning is not required, simply return */
2071 2252 : if ( !inputMc->lfeRouting.pan_lfe )
2072 : {
2073 2252 : return error;
2074 : }
2075 :
2076 0 : numLfeIn = getNumLfeChannels( inputMc );
2077 :
2078 0 : if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2079 : {
2080 0 : numOutChannels = inputMc->base.ctx.pCustomLsOut->num_spk + inputMc->base.ctx.pCustomLsOut->num_lfe;
2081 : }
2082 : else
2083 : {
2084 0 : if ( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ) != IVAS_ERR_OK )
2085 : {
2086 0 : return error;
2087 : }
2088 : }
2089 :
2090 0 : for ( i = 0; i < numLfeIn; i++ )
2091 : {
2092 : /* panning gains */
2093 0 : if ( ( error = getEfapGains( *inputMc->base.ctx.pEfapOutWrapper, inputMc->lfeRouting.lfeOutputAzimuth, inputMc->lfeRouting.lfeOutputElevation, inputMc->lfeRouting.lfePanMtx[i] ) ) != IVAS_ERR_OK )
2094 : {
2095 0 : return error;
2096 : }
2097 :
2098 : /* linear input gain */
2099 0 : v_multc( inputMc->lfeRouting.lfePanMtx[i], inputMc->lfeRouting.lfeInputGain, inputMc->lfeRouting.lfePanMtx[i], numOutChannels );
2100 : }
2101 :
2102 0 : return error;
2103 : }
2104 :
2105 :
2106 540 : static ivas_error updateLfePanGainsForAmbiOut(
2107 : input_mc *inputMc,
2108 : const AUDIO_CONFIG outConfig )
2109 : {
2110 : int16_t i;
2111 : int16_t numLfeIn, outAmbiOrder;
2112 : ivas_error error;
2113 540 : error = IVAS_ERR_OK;
2114 :
2115 : /* If panning is not required, simply return */
2116 540 : if ( !inputMc->lfeRouting.pan_lfe )
2117 : {
2118 540 : return error;
2119 : }
2120 :
2121 0 : if ( ( error = getAmbisonicsOrder( outConfig, &outAmbiOrder ) ) != IVAS_ERR_OK )
2122 : {
2123 0 : return error;
2124 : }
2125 :
2126 0 : numLfeIn = getNumLfeChannels( inputMc );
2127 :
2128 0 : for ( i = 0; i < numLfeIn; i++ )
2129 : {
2130 : /* panning gains */
2131 0 : ivas_dirac_dec_get_response( (int16_t) inputMc->lfeRouting.lfeOutputAzimuth, (int16_t) inputMc->lfeRouting.lfeOutputElevation, inputMc->lfeRouting.lfePanMtx[i], outAmbiOrder );
2132 :
2133 : /* linear input gain */
2134 0 : v_multc( inputMc->lfeRouting.lfePanMtx[i], inputMc->lfeRouting.lfeInputGain, inputMc->lfeRouting.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
2135 : }
2136 :
2137 0 : return error;
2138 : }
2139 :
2140 :
2141 2252 : static ivas_error updateMcPanGainsForMcOut(
2142 : input_mc *inputMc,
2143 : const AUDIO_CONFIG outConfig )
2144 : {
2145 : ivas_error error;
2146 :
2147 : /* "if" conditions below realize the following mapping:
2148 :
2149 : If in == out, use identity matrix, otherwise follow the table:
2150 : +-----------+-------------+---------------+-----------+--------------------+
2151 : | in\out | MONO | STEREO | custom LS | other |
2152 : +-----------+-------------+---------------+-----------+--------------------+
2153 : | MONO | mono out | EFAP | EFAP | EFAP |
2154 : | custom LS | mono out | EFAP | EFAP | EFAP |
2155 : | other | mono lookup | stereo lookup | EFAP | conversion mapping |
2156 : +-----------+-------------+---------------+-----------+--------------------+
2157 : */
2158 :
2159 2252 : if ( configsAreEqual( inputMc->base.inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ) )
2160 : {
2161 214 : error = initMcPanGainsWithIdentMatrix( inputMc );
2162 : }
2163 2038 : else if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ||
2164 1822 : inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO ||
2165 1720 : inputMc->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2166 : {
2167 1110 : if ( ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO ) && ( inputMc->nonDiegeticPan ) )
2168 : {
2169 30 : inputMc->panGains[0][0] = ( inputMc->nonDiegeticPanGain + 1.f ) * 0.5f;
2170 30 : inputMc->panGains[0][1] = 1.f - inputMc->panGains[0][0];
2171 30 : error = IVAS_ERR_OK;
2172 : }
2173 : else
2174 : {
2175 1080 : error = initMcPanGainsWithEfap( inputMc, outConfig );
2176 : }
2177 : }
2178 928 : else if ( outConfig == IVAS_AUDIO_CONFIG_MONO )
2179 : {
2180 96 : error = initMcPanGainsWithMonoOut( inputMc );
2181 : }
2182 832 : else if ( outConfig == IVAS_AUDIO_CONFIG_STEREO )
2183 : {
2184 72 : error = initMcPanGainsWithStereoLookup( inputMc );
2185 : }
2186 : else /* default */
2187 : {
2188 760 : error = initMcPanGainsWithConversionMapping( inputMc, outConfig );
2189 : }
2190 :
2191 : /* check for errors from above block */
2192 2252 : if ( error != IVAS_ERR_OK )
2193 : {
2194 0 : return error;
2195 : }
2196 :
2197 : /* update LFE panning */
2198 2252 : error = updateLfePanGainsForMcOut( inputMc, outConfig );
2199 :
2200 2252 : return error;
2201 : }
2202 :
2203 :
2204 540 : static ivas_error updateMcPanGainsForAmbiOut(
2205 : input_mc *inputMc,
2206 : const AUDIO_CONFIG outConfig )
2207 : {
2208 : int16_t ch_in, ch_out, lfeIdx;
2209 : int16_t numNonLfeInChannels, outAmbiOrder;
2210 : const float *spkAzi, *spkEle;
2211 : ivas_error error;
2212 :
2213 540 : if ( ( error = getAmbisonicsOrder( outConfig, &outAmbiOrder ) ) != IVAS_ERR_OK )
2214 : {
2215 0 : return error;
2216 : }
2217 :
2218 540 : if ( inputMc->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
2219 : {
2220 324 : if ( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK )
2221 : {
2222 0 : return error;
2223 : }
2224 :
2225 324 : if ( ( error = getSpeakerAzimuths( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK )
2226 : {
2227 0 : return error;
2228 : }
2229 :
2230 324 : if ( ( error = getSpeakerElevations( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK )
2231 : {
2232 0 : return error;
2233 : }
2234 :
2235 2232 : for ( ch_in = 0, ch_out = 0; ch_in < numNonLfeInChannels; ++ch_in, ++ch_out )
2236 : {
2237 1908 : if ( ch_in == LFE_CHANNEL )
2238 : {
2239 216 : ++ch_out;
2240 : }
2241 1908 : ivas_dirac_dec_get_response( (int16_t) spkAzi[ch_in], (int16_t) spkEle[ch_in], inputMc->panGains[ch_out], outAmbiOrder );
2242 : }
2243 : }
2244 : else
2245 : {
2246 216 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
2247 216 : spkAzi = inputMc->customLsInput.ls_azimuth;
2248 216 : spkEle = inputMc->customLsInput.ls_elevation;
2249 :
2250 1620 : for ( ch_in = 0, ch_out = 0; ch_in < numNonLfeInChannels; ++ch_in, ++ch_out )
2251 : {
2252 1404 : for ( lfeIdx = 0; lfeIdx < inputMc->customLsInput.num_lfe; ++lfeIdx )
2253 : {
2254 0 : if ( inputMc->customLsInput.lfe_idx[lfeIdx] == ch_in )
2255 : {
2256 0 : ++ch_out;
2257 0 : break;
2258 : }
2259 : }
2260 :
2261 1404 : ivas_dirac_dec_get_response( (int16_t) spkAzi[ch_in], (int16_t) spkEle[ch_in], inputMc->panGains[ch_out], outAmbiOrder );
2262 : }
2263 : }
2264 :
2265 : /* update LFE panning */
2266 540 : if ( ( error = updateLfePanGainsForAmbiOut( inputMc, outConfig ) ) != IVAS_ERR_OK )
2267 : {
2268 0 : return error;
2269 : }
2270 :
2271 540 : return IVAS_ERR_OK;
2272 : }
2273 :
2274 :
2275 3224 : static ivas_error updateMcPanGains(
2276 : input_mc *inputMc,
2277 : const AUDIO_CONFIG outConfig )
2278 : {
2279 : int16_t i;
2280 : ivas_error error;
2281 :
2282 : /* Reset to all zeros - some functions below only write non-zero elements. */
2283 3224 : setZeroPanMatrix( inputMc->panGains );
2284 :
2285 3224 : error = IVAS_ERR_OK;
2286 3224 : switch ( getAudioConfigType( outConfig ) )
2287 : {
2288 1524 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2289 1524 : error = updateMcPanGainsForMcOut( inputMc, outConfig );
2290 1524 : break;
2291 540 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2292 540 : error = updateMcPanGainsForAmbiOut( inputMc, outConfig );
2293 540 : break;
2294 1124 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2295 : switch ( outConfig )
2296 : {
2297 396 : case IVAS_AUDIO_CONFIG_BINAURAL:
2298 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
2299 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
2300 396 : break; /* Do nothing */
2301 728 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2302 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2303 : /* Prepare rendering to intermediate format */
2304 728 : error = updateMcPanGainsForMcOut( inputMc, IVAS_AUDIO_CONFIG_7_1_4 );
2305 728 : break;
2306 0 : default:
2307 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2308 : }
2309 1124 : break;
2310 36 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2311 36 : break; /* Do nothing */
2312 0 : default:
2313 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2314 : }
2315 : /* Check error here to keep switch statement more compact */
2316 3224 : if ( error != IVAS_ERR_OK )
2317 : {
2318 0 : return error;
2319 : }
2320 :
2321 : /* Copy LFE routing to pan gains array */
2322 3224 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2323 : {
2324 1260 : for ( i = 0; i < inputMc->customLsInput.num_lfe; ++i )
2325 : {
2326 0 : mvr2r( inputMc->lfeRouting.lfePanMtx[i], inputMc->panGains[inputMc->customLsInput.lfe_idx[i]], RENDERER_MAX_OUTPUT_CHANNELS );
2327 : }
2328 : }
2329 : else
2330 : {
2331 : /* For code simplicity, always copy LFE gains. If config has no LFE, gains will be zero anyway. */
2332 1964 : mvr2r( inputMc->lfeRouting.lfePanMtx[0], inputMc->panGains[LFE_CHANNEL], RENDERER_MAX_OUTPUT_CHANNELS );
2333 : }
2334 :
2335 3224 : return IVAS_ERR_OK;
2336 : }
2337 :
2338 :
2339 559857 : static ivas_error initMcBinauralRendering(
2340 : input_mc *inputMc,
2341 : const AUDIO_CONFIG inConfig,
2342 : const AUDIO_CONFIG outConfig,
2343 : RENDER_CONFIG_DATA *hRendCfg,
2344 : IVAS_DEC_HRTF_CREND_HANDLE hMixconv,
2345 : HRTFS_STATISTICS_HANDLE hHrtfStatistics,
2346 : uint8_t reconfigureFlag )
2347 : {
2348 : ivas_error error;
2349 : int16_t i;
2350 : int32_t binauralDelayNs;
2351 : int32_t outSampleRate;
2352 : int8_t useTDRend;
2353 :
2354 : /* Allocate TD binaural renderer for custom loudspeaker layouts (regardless of headrotation)
2355 : or planar MC layouts with headrotation, CREND for the rest */
2356 559857 : useTDRend = FALSE;
2357 559857 : if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
2358 : {
2359 424996 : if ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
2360 : {
2361 58011 : useTDRend = TRUE;
2362 : }
2363 366985 : else if ( ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) &&
2364 213518 : ( inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2365 : {
2366 118028 : useTDRend = TRUE;
2367 : }
2368 : }
2369 :
2370 : /* if TD renderer was open and we need to use CREND, close it */
2371 559857 : if ( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) )
2372 : {
2373 1124 : ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
2374 : }
2375 :
2376 559857 : if ( !reconfigureFlag || !useTDRend )
2377 : {
2378 3072848 : for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2379 : {
2380 2688742 : if ( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
2381 : {
2382 0 : ivas_td_binaural_close( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
2383 : }
2384 : }
2385 : }
2386 :
2387 : /* if we need to use TD renderer and CREND was open, close it */
2388 559857 : if ( useTDRend )
2389 : {
2390 176039 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2391 : }
2392 :
2393 559857 : if ( !reconfigureFlag || ( !useTDRend && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB && inputMc->hReverb != NULL ) )
2394 : {
2395 1124 : ivas_reverb_close( &inputMc->hReverb );
2396 : }
2397 :
2398 559857 : if ( !reconfigureFlag || ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM && !inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2399 : {
2400 67850 : if ( inputMc->efapInWrapper.hEfap != NULL )
2401 : {
2402 216 : efap_free_data( &inputMc->efapInWrapper.hEfap );
2403 : }
2404 : }
2405 :
2406 559857 : outSampleRate = *inputMc->base.ctx.pOutSampleRate;
2407 :
2408 559857 : if ( useTDRend && inputMc->tdRendWrapper.hBinRendererTd == NULL )
2409 : {
2410 288 : if ( ( error = ivas_td_binaural_open_ext( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, 0 ) ) != IVAS_ERR_OK )
2411 : {
2412 0 : return error;
2413 : }
2414 :
2415 288 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
2416 : {
2417 : /* Open TD renderer wrappers */
2418 704 : for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2419 : {
2420 616 : if ( ( error = ivas_td_binaural_open_ext( &inputMc->splitTdRendWrappers[i], inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, 0 ) ) != IVAS_ERR_OK )
2421 : {
2422 0 : return error;
2423 : }
2424 :
2425 : /* Assert same delay as main TD renderer */
2426 616 : assert( inputMc->splitTdRendWrappers[i].binaural_latency_ns == inputMc->tdRendWrapper.binaural_latency_ns );
2427 : }
2428 : }
2429 :
2430 288 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB && inputMc->hReverb == NULL )
2431 : {
2432 28 : if ( ( error = ivas_reverb_open( &( inputMc->hReverb ), hHrtfStatistics, hRendCfg, outSampleRate ) ) != IVAS_ERR_OK )
2433 : {
2434 0 : return error;
2435 : }
2436 : }
2437 : }
2438 559569 : else if ( !useTDRend && inputMc->crendWrapper == NULL )
2439 : {
2440 : /* open CREND */
2441 1384 : if ( ( error = ivas_rend_openCrend( &inputMc->crendWrapper, ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) ? IVAS_AUDIO_CONFIG_7_1_4 : inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics,
2442 692 : outSampleRate, 1, ( ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) || ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ) ? inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ) != IVAS_ERR_OK )
2443 : {
2444 0 : return error;
2445 : }
2446 : }
2447 :
2448 : /* Initialise the EFAP handle for rotation on input layout */
2449 559857 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inputMc->base.ctx.pHeadRotData->headRotEnabled && inputMc->efapInWrapper.hEfap == NULL )
2450 : {
2451 332 : if ( ( error = initEfap( &inputMc->efapInWrapper, inConfig, NULL ) ) != IVAS_ERR_OK )
2452 : {
2453 0 : return error;
2454 : }
2455 : }
2456 :
2457 : /* determine binaural delay ( used for aligning LFE to output signal ) */
2458 559857 : binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, inputMc->tdRendWrapper.binaural_latency_ns );
2459 559857 : inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs );
2460 :
2461 559857 : if ( inputMc->binauralDelaySmp > MAX_BIN_DELAY_SAMPLES )
2462 : {
2463 0 : return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid delay for LFE binaural rendering!)" );
2464 : }
2465 :
2466 559857 : return IVAS_ERR_OK;
2467 : }
2468 :
2469 :
2470 36 : static ivas_error initMcMasaRendering(
2471 : input_mc *inputMc,
2472 : const AUDIO_CONFIG inConfig,
2473 : const int32_t inSampleRate )
2474 : {
2475 : ivas_error error;
2476 :
2477 36 : if ( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2478 : {
2479 0 : ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
2480 : }
2481 :
2482 36 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2483 :
2484 36 : ivas_reverb_close( &inputMc->hReverb );
2485 :
2486 36 : if ( inputMc->efapInWrapper.hEfap != NULL )
2487 : {
2488 0 : efap_free_data( &inputMc->efapInWrapper.hEfap );
2489 : }
2490 :
2491 36 : if ( ( error = ivas_mcmasa_ana_open( &inputMc->hMcMasa, inConfig, inSampleRate ) ) != IVAS_ERR_OK )
2492 : {
2493 0 : return error;
2494 : }
2495 :
2496 36 : return IVAS_ERR_OK;
2497 : }
2498 :
2499 :
2500 3224 : static lfe_routing defaultLfeRouting(
2501 : const AUDIO_CONFIG inConfig,
2502 : const LSSETUP_CUSTOM_STRUCT customLsIn,
2503 : const AUDIO_CONFIG outConfig,
2504 : const LSSETUP_CUSTOM_STRUCT customLsOut )
2505 : {
2506 : int16_t i;
2507 : lfe_routing routing;
2508 :
2509 : /* Set all output gains to zero, then route each input LFE consecutively to the next available output LFE. */
2510 :
2511 16120 : for ( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i )
2512 : {
2513 12896 : set_zero( routing.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
2514 : }
2515 :
2516 3224 : routing.pan_lfe = false;
2517 3224 : routing.lfeInputGain = 1.0f;
2518 :
2519 3224 : switch ( inConfig )
2520 : {
2521 1538 : case IVAS_AUDIO_CONFIG_5_1:
2522 : case IVAS_AUDIO_CONFIG_5_1_2:
2523 : case IVAS_AUDIO_CONFIG_5_1_4:
2524 : case IVAS_AUDIO_CONFIG_7_1:
2525 : case IVAS_AUDIO_CONFIG_7_1_4:
2526 1538 : routing.numLfeChannels = 1;
2527 1538 : break;
2528 1260 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2529 1260 : routing.numLfeChannels = customLsIn.num_lfe;
2530 1260 : break;
2531 426 : default:
2532 426 : routing.numLfeChannels = 0;
2533 : }
2534 :
2535 3224 : switch ( outConfig )
2536 : {
2537 900 : case IVAS_AUDIO_CONFIG_5_1:
2538 : case IVAS_AUDIO_CONFIG_5_1_2:
2539 : case IVAS_AUDIO_CONFIG_5_1_4:
2540 : case IVAS_AUDIO_CONFIG_7_1:
2541 : case IVAS_AUDIO_CONFIG_7_1_4:
2542 900 : routing.lfePanMtx[0][LFE_CHANNEL] = 1.0f;
2543 900 : break;
2544 234 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2545 234 : for ( i = 0; i < routing.numLfeChannels && i < customLsOut.num_lfe; ++i )
2546 : {
2547 0 : routing.lfePanMtx[i][customLsOut.lfe_idx[i]] = 1.0f;
2548 : }
2549 234 : break;
2550 2090 : default:
2551 : /* Do nothing */
2552 2090 : break;
2553 : }
2554 :
2555 3224 : return routing;
2556 : }
2557 :
2558 :
2559 2594 : static ivas_error setRendInputActiveMc(
2560 : void *input,
2561 : const AUDIO_CONFIG inConfig,
2562 : const IVAS_REND_InputId id,
2563 : RENDER_CONFIG_DATA *hRendCfg,
2564 : hrtf_handles *hrtfs )
2565 : {
2566 : int16_t i;
2567 : ivas_error error;
2568 : rendering_context rendCtx;
2569 : AUDIO_CONFIG outConfig;
2570 : input_mc *inputMc;
2571 : int16_t pos_idx;
2572 :
2573 2594 : inputMc = (input_mc *) input;
2574 2594 : rendCtx = inputMc->base.ctx;
2575 2594 : outConfig = *rendCtx.pOutConfig;
2576 :
2577 2594 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
2578 : {
2579 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2580 : }
2581 :
2582 2594 : if ( ( error = allocateMcLfeDelayBuffer( &inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES ) ) != IVAS_ERR_OK )
2583 : {
2584 0 : return error;
2585 : }
2586 :
2587 2594 : if ( ( error = allocateInputBaseBufferData( &inputMc->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
2588 : {
2589 0 : return error;
2590 : }
2591 2594 : initRendInputBase( &inputMc->base, inConfig, id, rendCtx, inputMc->bufferData, MAX_BUFFER_LENGTH );
2592 :
2593 2594 : setZeroPanMatrix( inputMc->panGains );
2594 2594 : inputMc->customLsInput = defaultCustomLs();
2595 2594 : inputMc->tdRendWrapper = defaultTdRendWrapper();
2596 :
2597 2594 : if ( hrtfs->hHrtfTD )
2598 : {
2599 0 : inputMc->tdRendWrapper.binaural_latency_ns = (int32_t) ( hrtfs->hHrtfTD->latency_s * 1000000000.f );
2600 : }
2601 2594 : inputMc->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
2602 2594 : inputMc->crendWrapper = NULL;
2603 2594 : inputMc->hReverb = NULL;
2604 2594 : inputMc->hMcMasa = NULL;
2605 :
2606 23346 : for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
2607 : {
2608 20752 : initRotGains( inputMc->rot_gains_prev[pos_idx] );
2609 : }
2610 2594 : inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut );
2611 2594 : set_zero( inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES );
2612 2594 : inputMc->binauralDelaySmp = 0;
2613 :
2614 20752 : for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i )
2615 : {
2616 18158 : inputMc->splitTdRendWrappers[i] = defaultTdRendWrapper();
2617 18158 : if ( hrtfs->hHrtfTD )
2618 : {
2619 0 : inputMc->splitTdRendWrappers[i].binaural_latency_ns = (int32_t) ( hrtfs->hHrtfTD->latency_s * 1000000000.f );
2620 : }
2621 18158 : inputMc->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
2622 : }
2623 :
2624 2594 : if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
2625 : {
2626 908 : if ( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics, FALSE ) ) != IVAS_ERR_OK )
2627 : {
2628 0 : return error;
2629 : }
2630 : }
2631 :
2632 2594 : if ( outConfig == IVAS_AUDIO_CONFIG_MASA1 || outConfig == IVAS_AUDIO_CONFIG_MASA2 )
2633 : {
2634 36 : if ( ( error = initMcMasaRendering( inputMc, inConfig, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2635 : {
2636 0 : return error;
2637 : }
2638 : }
2639 :
2640 2594 : if ( ( error = updateMcPanGains( inputMc, outConfig ) ) != IVAS_ERR_OK )
2641 : {
2642 0 : return error;
2643 : }
2644 :
2645 2594 : return IVAS_ERR_OK;
2646 : }
2647 :
2648 :
2649 10354 : static void clearInputMc(
2650 : input_mc *inputMc )
2651 : {
2652 : int16_t i;
2653 : rendering_context rendCtx;
2654 :
2655 10354 : rendCtx = inputMc->base.ctx;
2656 :
2657 10354 : freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer );
2658 10354 : freeInputBaseBufferData( &inputMc->bufferData );
2659 10354 : ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer );
2660 :
2661 10354 : initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2662 :
2663 : /* Free input's internal handles */
2664 10354 : if ( inputMc->efapInWrapper.hEfap != NULL )
2665 : {
2666 746 : efap_free_data( &inputMc->efapInWrapper.hEfap );
2667 : }
2668 :
2669 10354 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2670 :
2671 10354 : ivas_reverb_close( &inputMc->hReverb );
2672 :
2673 10354 : if ( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2674 : {
2675 216 : ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
2676 : }
2677 :
2678 82832 : for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i )
2679 : {
2680 72478 : if ( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
2681 : {
2682 616 : ivas_td_binaural_close( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
2683 : }
2684 : }
2685 :
2686 10354 : ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
2687 :
2688 10354 : return;
2689 : }
2690 :
2691 :
2692 2016 : static ivas_error initSbaPanGainsForMcOut(
2693 : input_sba *inputSba,
2694 : const AUDIO_CONFIG outConfig,
2695 : const LSSETUP_CUSTOM_STRUCT *outSetupCustom )
2696 : {
2697 : int16_t ambiOrderIn;
2698 : int16_t chInIdx, chOutIdx;
2699 : float *tmpDecMtx, *readPtr;
2700 : IVAS_OUTPUT_SETUP hOutSetup;
2701 : ivas_error error;
2702 :
2703 2016 : if ( ( error = getAmbisonicsOrder( inputSba->base.inConfig, &ambiOrderIn ) ) != IVAS_ERR_OK )
2704 : {
2705 0 : return error;
2706 : }
2707 :
2708 2016 : if ( getAudioConfigType( outConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
2709 : {
2710 0 : assert( !"Invalid configuration" );
2711 : return IVAS_ERR_WRONG_PARAMS;
2712 : }
2713 :
2714 2016 : switch ( outConfig )
2715 : {
2716 192 : case IVAS_AUDIO_CONFIG_MONO:
2717 192 : hOutSetup.ls_azimuth = ls_azimuth_CICP1;
2718 192 : hOutSetup.ls_elevation = ls_elevation_CICP1;
2719 192 : ivas_output_init( &hOutSetup, outConfig );
2720 192 : break;
2721 1554 : case IVAS_AUDIO_CONFIG_STEREO:
2722 : case IVAS_AUDIO_CONFIG_5_1:
2723 : case IVAS_AUDIO_CONFIG_7_1:
2724 : case IVAS_AUDIO_CONFIG_5_1_2:
2725 : case IVAS_AUDIO_CONFIG_5_1_4:
2726 : case IVAS_AUDIO_CONFIG_7_1_4:
2727 1554 : ivas_output_init( &hOutSetup, outConfig );
2728 1554 : break;
2729 270 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2730 270 : ivas_ls_custom_setup( &hOutSetup, outSetupCustom );
2731 270 : break;
2732 0 : default:
2733 0 : assert( !"Invalid speaker config" );
2734 : return IVAS_ERR_WRONG_PARAMS;
2735 : }
2736 :
2737 : /* obtain and copy over HOA decoding matrix */
2738 2016 : tmpDecMtx = NULL;
2739 2016 : if ( ( error = ivas_sba_get_hoa_dec_matrix( hOutSetup, &tmpDecMtx, ambiOrderIn ) ) != IVAS_ERR_OK )
2740 : {
2741 0 : return error;
2742 : }
2743 :
2744 2016 : readPtr = &tmpDecMtx[0];
2745 19104 : for ( chOutIdx = 0; chOutIdx < hOutSetup.nchan_out_woLFE + hOutSetup.num_lfe; ++chOutIdx )
2746 : {
2747 290496 : for ( chInIdx = 0; chInIdx < SBA_NHARM_HOA3; ++chInIdx )
2748 : {
2749 273408 : if ( hOutSetup.num_lfe > 0 && chOutIdx == hOutSetup.index_lfe[0] )
2750 : {
2751 21792 : continue; /* nothing to be rendered to LFE */
2752 : }
2753 251616 : inputSba->hoaDecMtx[chInIdx][chOutIdx] = *readPtr++;
2754 : }
2755 : }
2756 :
2757 2016 : free( tmpDecMtx );
2758 :
2759 2016 : return IVAS_ERR_OK;
2760 : }
2761 :
2762 :
2763 576 : static ivas_error initSbaPanGainsForSbaOut(
2764 : input_sba *inputSba,
2765 : const AUDIO_CONFIG outConfig )
2766 : {
2767 : ivas_error error;
2768 576 : error = IVAS_ERR_OK;
2769 :
2770 576 : if ( getAudioConfigType( outConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
2771 : {
2772 0 : assert( !"Invalid configuration" );
2773 : return IVAS_ERR_WRONG_PARAMS;
2774 : }
2775 :
2776 576 : fillIdentityPanMatrix( inputSba->hoaDecMtx );
2777 :
2778 576 : return error;
2779 : }
2780 :
2781 :
2782 4150 : static ivas_error updateSbaPanGains(
2783 : input_sba *inputSba,
2784 : const AUDIO_CONFIG outConfig,
2785 : RENDER_CONFIG_DATA *hRendCfg,
2786 : IVAS_DEC_HRTF_CREND_HANDLE hMixconv,
2787 : IVAS_DEC_HRTF_STATISTICS_HANDLE hHrtfStatistics )
2788 : {
2789 : ivas_error error;
2790 : AUDIO_CONFIG inConfig;
2791 : rendering_context rendCtx;
2792 :
2793 : /* Reset to all zeros - some functions below only write non-zero elements. */
2794 4150 : setZeroPanMatrix( inputSba->hoaDecMtx );
2795 :
2796 4150 : inConfig = inputSba->base.inConfig;
2797 4150 : rendCtx = inputSba->base.ctx;
2798 :
2799 4150 : switch ( getAudioConfigType( outConfig ) )
2800 : {
2801 1614 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2802 1614 : error = initSbaPanGainsForMcOut( inputSba, outConfig, inputSba->base.ctx.pCustomLsOut );
2803 1614 : break;
2804 576 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2805 576 : error = initSbaPanGainsForSbaOut( inputSba, outConfig );
2806 576 : break;
2807 1924 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2808 : switch ( outConfig )
2809 : {
2810 178 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
2811 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
2812 : {
2813 178 : if ( hRendCfg->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
2814 : {
2815 8 : assert( *rendCtx.pOutSampleRate == 48000 && "split binaural fast conv mode is currently supported with 48k sampling rate only" );
2816 8 : if ( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2817 : {
2818 0 : return error;
2819 : }
2820 : }
2821 : else
2822 : {
2823 170 : assert( ( *rendCtx.pOutSampleRate == 48000 ) && "split binaural crend mode is currently supported with 48k sampling rate only" );
2824 170 : if ( ( error = ivas_rend_openMultiBinCrend( &inputSba->crendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2825 : {
2826 0 : return error;
2827 : }
2828 : }
2829 178 : break;
2830 : }
2831 1344 : case IVAS_AUDIO_CONFIG_BINAURAL:
2832 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2833 1344 : if ( hRendCfg->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
2834 : {
2835 0 : if ( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2836 : {
2837 0 : return error;
2838 : }
2839 : }
2840 : else
2841 : {
2842 1344 : if ( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, 1, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ) != IVAS_ERR_OK )
2843 : {
2844 0 : return error;
2845 : }
2846 : }
2847 1344 : break;
2848 402 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2849 402 : if ( ( error = initSbaPanGainsForMcOut( inputSba, IVAS_AUDIO_CONFIG_7_1_4, NULL ) ) != IVAS_ERR_OK )
2850 : {
2851 0 : return error;
2852 : }
2853 :
2854 402 : if ( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, 1, rendCtx.pSplitRendWrapper != NULL ? rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses : 1 ) ) != IVAS_ERR_OK )
2855 : {
2856 0 : return error;
2857 : }
2858 402 : break;
2859 0 : default:
2860 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2861 : }
2862 1924 : break;
2863 36 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2864 36 : error = IVAS_ERR_OK;
2865 36 : break; /* Do nothing */
2866 0 : default:
2867 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2868 : }
2869 :
2870 : /* Check error here to keep switch statement more compact */
2871 4150 : if ( error != IVAS_ERR_OK )
2872 : {
2873 0 : return error;
2874 : }
2875 :
2876 4150 : return IVAS_ERR_OK;
2877 : }
2878 :
2879 :
2880 36 : static ivas_error initSbaMasaRendering(
2881 : input_sba *inputSba,
2882 : int32_t inSampleRate )
2883 : {
2884 : ivas_error error;
2885 :
2886 36 : ivas_rend_closeCrend( &inputSba->crendWrapper );
2887 :
2888 36 : if ( ( error = ivas_dirac_ana_open( &inputSba->hDirAC, inSampleRate ) ) != IVAS_ERR_OK )
2889 : {
2890 0 : return error;
2891 : }
2892 :
2893 36 : return IVAS_ERR_OK;
2894 : }
2895 :
2896 :
2897 4150 : static ivas_error setRendInputActiveSba(
2898 : void *input,
2899 : const AUDIO_CONFIG inConfig,
2900 : const IVAS_REND_InputId id,
2901 : RENDER_CONFIG_DATA *hRendCfg,
2902 : hrtf_handles *hrtfs )
2903 : {
2904 : ivas_error error;
2905 : rendering_context rendCtx;
2906 : AUDIO_CONFIG outConfig;
2907 : input_sba *inputSba;
2908 : int16_t pos_idx;
2909 :
2910 4150 : inputSba = (input_sba *) input;
2911 4150 : rendCtx = inputSba->base.ctx;
2912 4150 : outConfig = *rendCtx.pOutConfig;
2913 :
2914 4150 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
2915 : {
2916 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2917 : }
2918 :
2919 4150 : if ( ( error = allocateInputBaseBufferData( &inputSba->bufferData, MAX_CLDFB_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
2920 : {
2921 0 : return error;
2922 : }
2923 :
2924 4150 : initRendInputBase( &inputSba->base, inConfig, id, rendCtx, inputSba->bufferData, MAX_CLDFB_BUFFER_LENGTH );
2925 :
2926 4150 : setZeroPanMatrix( inputSba->hoaDecMtx );
2927 :
2928 4150 : inputSba->crendWrapper = NULL;
2929 37350 : for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
2930 : {
2931 33200 : initRotGains( inputSba->rot_gains_prev[pos_idx] );
2932 : }
2933 4150 : inputSba->cldfbRendWrapper.hHrtfFastConv = hrtfs->hHrtfFastConv;
2934 :
2935 4150 : if ( outConfig == IVAS_AUDIO_CONFIG_MASA1 || outConfig == IVAS_AUDIO_CONFIG_MASA2 )
2936 : {
2937 36 : if ( ( error = initSbaMasaRendering( inputSba, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2938 : {
2939 0 : return error;
2940 : }
2941 : }
2942 :
2943 4150 : if ( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics ) ) != IVAS_ERR_OK )
2944 : {
2945 0 : return error;
2946 : }
2947 :
2948 4150 : return IVAS_ERR_OK;
2949 : }
2950 :
2951 :
2952 10354 : static void clearInputSba(
2953 : input_sba *inputSba )
2954 : {
2955 : rendering_context rendCtx;
2956 :
2957 10354 : rendCtx = inputSba->base.ctx;
2958 :
2959 10354 : freeInputBaseBufferData( &inputSba->bufferData );
2960 10354 : ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer );
2961 :
2962 10354 : initRendInputBase( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2963 :
2964 : /* Free input's internal handles */
2965 10354 : ivas_rend_closeCrend( &inputSba->crendWrapper );
2966 :
2967 10354 : if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
2968 : {
2969 8 : ivas_rend_closeCldfbRend( &inputSba->cldfbRendWrapper );
2970 : }
2971 :
2972 10354 : ivas_dirac_ana_close( &( inputSba->hDirAC ) );
2973 :
2974 10354 : return;
2975 : }
2976 :
2977 :
2978 2728 : static ivas_error setRendInputActiveMasa(
2979 : void *input,
2980 : const AUDIO_CONFIG inConfig,
2981 : const IVAS_REND_InputId id,
2982 : RENDER_CONFIG_DATA *hRendCfg,
2983 : hrtf_handles *hrtfs )
2984 : {
2985 : ivas_error error;
2986 : rendering_context rendCtx;
2987 : AUDIO_CONFIG outConfig;
2988 : input_masa *inputMasa;
2989 : int16_t numInChannels;
2990 :
2991 2728 : inputMasa = (input_masa *) input;
2992 2728 : rendCtx = inputMasa->base.ctx;
2993 2728 : outConfig = *rendCtx.pOutConfig;
2994 :
2995 2728 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
2996 : {
2997 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2998 : }
2999 :
3000 2728 : if ( ( error = allocateInputBaseBufferData( &inputMasa->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
3001 : {
3002 0 : return error;
3003 : }
3004 2728 : initRendInputBase( &inputMasa->base, inConfig, id, rendCtx, inputMasa->bufferData, MAX_BUFFER_LENGTH );
3005 :
3006 2728 : if ( ( error = getAudioConfigNumChannels( inConfig, &numInChannels ) ) != IVAS_ERR_OK )
3007 : {
3008 0 : return error;
3009 : }
3010 :
3011 2728 : if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
3012 : {
3013 132 : inputMasa->metadataHasBeenFed = false;
3014 132 : if ( ( error = masaPrerendOpen( &inputMasa->hMasaPrerend, inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 ? 1 : 2, *( inputMasa->base.ctx.pOutSampleRate ) ) ) != IVAS_ERR_OK )
3015 : {
3016 0 : return error;
3017 : }
3018 : }
3019 : else
3020 : {
3021 2596 : if ( ( error = initMasaExtRenderer( inputMasa, outConfig, hRendCfg, hrtfs ) ) != IVAS_ERR_OK )
3022 : {
3023 0 : return error;
3024 : }
3025 2596 : inputMasa->metadataHasBeenFed = false;
3026 : }
3027 :
3028 2728 : return IVAS_ERR_OK;
3029 : }
3030 :
3031 :
3032 10354 : static void clearInputMasa(
3033 : input_masa *inputMasa )
3034 : {
3035 : rendering_context rendCtx;
3036 :
3037 10354 : rendCtx = inputMasa->base.ctx;
3038 :
3039 10354 : freeInputBaseBufferData( &inputMasa->bufferData );
3040 10354 : ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer );
3041 :
3042 10354 : masaPrerendClose( &inputMasa->hMasaPrerend );
3043 10354 : freeMasaExtRenderer( &inputMasa->hMasaExtRend );
3044 :
3045 10354 : initRendInputBase( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3046 :
3047 10354 : return;
3048 : }
3049 :
3050 :
3051 : /*-------------------------------------------------------------------------
3052 : * IVAS_REND_Open()
3053 : *
3054 : *
3055 : *------------------------------------------------------------------------*/
3056 :
3057 10354 : ivas_error IVAS_REND_Open(
3058 : IVAS_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */
3059 : const int32_t outputSampleRate, /* i : output sampling rate */
3060 : const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */
3061 : const bool asHrtfBinary, /* i : load hrtf binary file */
3062 : const int16_t nonDiegeticPan, /* i : non-diegetic object flag */
3063 : const float nonDiegeticPanGain, /* i : non-diegetic panning gain */
3064 : const int16_t Opt_Headrotation, /* i : indicates whether head-rotation is used */
3065 : const int16_t Opt_ExternalOrientation, /* i : indicates whether external orientations are used */
3066 : const int16_t num_subframes /* i : number of subframes */
3067 : )
3068 : {
3069 : int16_t i;
3070 : int16_t j;
3071 : IVAS_REND_HANDLE hIvasRend;
3072 : ivas_error error;
3073 : int16_t numOutChannels;
3074 :
3075 : /* Validate function arguments */
3076 10354 : if ( phIvasRend == NULL )
3077 : {
3078 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3079 : }
3080 :
3081 10354 : if ( ( error = validateOutputAudioConfig( outConfig ) ) != IVAS_ERR_OK )
3082 : {
3083 0 : return error;
3084 : }
3085 :
3086 10354 : if ( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ) != IVAS_ERR_OK )
3087 : {
3088 0 : return error;
3089 : }
3090 :
3091 10354 : *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
3092 10354 : if ( *phIvasRend == NULL )
3093 : {
3094 0 : return IVAS_ERR_FAILED_ALLOC;
3095 : }
3096 :
3097 10354 : hIvasRend = *phIvasRend;
3098 10354 : hIvasRend->sampleRateOut = outputSampleRate;
3099 10354 : hIvasRend->outputConfig = outConfig;
3100 10354 : hIvasRend->customLsOut = defaultCustomLs();
3101 10354 : hIvasRend->hLimiter = NULL;
3102 10354 : hIvasRend->efapOutWrapper.hEfap = NULL;
3103 10354 : hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
3104 10354 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_UNSET;
3105 : #ifdef DEBUGGING
3106 : hIvasRend->numClipping = 0;
3107 : #endif
3108 10354 : hIvasRend->num_subframes = num_subframes;
3109 :
3110 : /* Initialize limiter */
3111 10354 : if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
3112 : {
3113 0 : return error;
3114 : }
3115 :
3116 10354 : if ( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ) != IVAS_ERR_OK )
3117 : {
3118 0 : return error;
3119 : }
3120 :
3121 : /* Initialize headrotation data */
3122 10354 : hIvasRend->headRotData.headRotEnabled = 0;
3123 10354 : if ( Opt_Headrotation )
3124 : {
3125 1966 : if ( ( error = initHeadRotation( hIvasRend ) ) != IVAS_ERR_OK )
3126 : {
3127 0 : return error;
3128 : }
3129 : }
3130 :
3131 : /* Initialize external orientation data */
3132 10354 : hIvasRend->hExternalOrientationData = NULL;
3133 10354 : if ( Opt_ExternalOrientation )
3134 : {
3135 0 : if ( ( error = ivas_external_orientation_open( &( hIvasRend->hExternalOrientationData ), num_subframes ) ) != IVAS_ERR_OK )
3136 : {
3137 0 : return error;
3138 : }
3139 : }
3140 :
3141 : /* Initilize combined orientation data */
3142 10354 : hIvasRend->hCombinedOrientationData = NULL;
3143 10354 : if ( Opt_Headrotation || Opt_ExternalOrientation )
3144 : {
3145 1966 : if ( ( error = ivas_combined_orientation_open( &( hIvasRend->hCombinedOrientationData ), outputSampleRate, num_subframes ) ) != IVAS_ERR_OK )
3146 : {
3147 0 : return error;
3148 : }
3149 : }
3150 :
3151 : /* Initialize EFAP */
3152 10354 : if ( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ) != IVAS_ERR_OK )
3153 : {
3154 0 : return error;
3155 : }
3156 :
3157 : /* Initialize inputs */
3158 :
3159 10354 : hIvasRend->splitRendWrapper = NULL;
3160 10354 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
3161 : {
3162 472 : if ( ( hIvasRend->splitRendWrapper = (SPLIT_REND_WRAPPER *) malloc( sizeof( SPLIT_REND_WRAPPER ) ) ) == NULL )
3163 : {
3164 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS renderer handle" );
3165 : }
3166 :
3167 472 : isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
3168 : }
3169 10354 : hIvasRend->splitRendEncBuffer.data = NULL;
3170 10354 : hIvasRend->splitRendEncBuffer.config.is_cldfb = 0;
3171 10354 : hIvasRend->splitRendEncBuffer.config.numChannels = 0;
3172 10354 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0;
3173 :
3174 51770 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
3175 : {
3176 41416 : initRendInputBase( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3177 :
3178 41416 : hIvasRend->inputsIsm[i].crendWrapper = NULL;
3179 41416 : hIvasRend->inputsIsm[i].hReverb = NULL;
3180 41416 : hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
3181 331328 : for ( j = 0; j < (int16_t) ( sizeof( hIvasRend->inputsIsm[i].splitTdRendWrappers ) / sizeof( *hIvasRend->inputsIsm[i].splitTdRendWrappers ) ); ++j )
3182 : {
3183 289912 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3184 289912 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3185 : }
3186 41416 : hIvasRend->inputsIsm[i].bufferData = NULL;
3187 41416 : hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
3188 41416 : hIvasRend->inputsIsm[i].nonDiegeticPanGain = nonDiegeticPanGain;
3189 41416 : hIvasRend->inputsIsm[i].hOMasa = NULL;
3190 : }
3191 :
3192 20708 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3193 : {
3194 10354 : initRendInputBase( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3195 :
3196 10354 : hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
3197 10354 : hIvasRend->inputsMc[i].crendWrapper = NULL;
3198 10354 : hIvasRend->inputsMc[i].hReverb = NULL;
3199 10354 : hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
3200 10354 : hIvasRend->inputsMc[i].bufferData = NULL;
3201 10354 : hIvasRend->inputsMc[i].lfeDelayBuffer = NULL;
3202 10354 : hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
3203 10354 : hIvasRend->inputsMc[i].nonDiegeticPanGain = nonDiegeticPanGain;
3204 10354 : hIvasRend->inputsMc[i].hMcMasa = NULL;
3205 82832 : for ( j = 0; j < (int16_t) ( sizeof( hIvasRend->inputsMc[i].splitTdRendWrappers ) / sizeof( *hIvasRend->inputsMc[i].splitTdRendWrappers ) ); ++j )
3206 : {
3207 72478 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3208 72478 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3209 : }
3210 : }
3211 :
3212 20708 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3213 : {
3214 10354 : initRendInputBase( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3215 :
3216 10354 : hIvasRend->inputsSba[i].crendWrapper = NULL;
3217 10354 : hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend = NULL;
3218 10354 : hIvasRend->inputsSba[i].cldfbRendWrapper.hHrtfFastConv = NULL;
3219 10354 : hIvasRend->inputsSba[i].bufferData = NULL;
3220 10354 : hIvasRend->inputsSba[i].hDirAC = NULL;
3221 : }
3222 :
3223 20708 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3224 : {
3225 10354 : initRendInputBase( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3226 :
3227 10354 : hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
3228 10354 : hIvasRend->inputsMasa[i].bufferData = NULL;
3229 10354 : hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
3230 10354 : hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
3231 : }
3232 :
3233 :
3234 10354 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
3235 10354 : hIvasRend->hHrtfs.hHrtfParambin = NULL;
3236 10354 : hIvasRend->hHrtfs.hHrtfTD = NULL;
3237 10354 : hIvasRend->hHrtfs.hHrtfCrend = NULL;
3238 10354 : hIvasRend->hHrtfs.hHrtfStatistics = NULL;
3239 10354 : if ( asHrtfBinary )
3240 : {
3241 0 : if ( ( error = ivas_HRTF_binary_open( &( hIvasRend->hHrtfs.hHrtfTD ) ) ) != IVAS_ERR_OK )
3242 : {
3243 0 : return error;
3244 : }
3245 0 : if ( ( error = ivas_HRTF_CRend_binary_open( &( hIvasRend->hHrtfs.hHrtfCrend ) ) ) != IVAS_ERR_OK )
3246 : {
3247 0 : return error;
3248 : }
3249 0 : if ( ( error = ivas_HRTF_fastconv_binary_open( &( hIvasRend->hHrtfs.hHrtfFastConv ) ) ) != IVAS_ERR_OK )
3250 : {
3251 0 : return error;
3252 : }
3253 0 : if ( ( error = ivas_HRTF_parambin_binary_open( &( hIvasRend->hHrtfs.hHrtfParambin ) ) ) != IVAS_ERR_OK )
3254 : {
3255 0 : return error;
3256 : }
3257 0 : if ( ( error = ivas_HRTF_statistics_binary_open( &( hIvasRend->hHrtfs.hHrtfStatistics ) ) ) != IVAS_ERR_OK )
3258 : {
3259 0 : return error;
3260 : }
3261 : }
3262 :
3263 10354 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
3264 : {
3265 2172 : if ( ( error = ivas_HRTF_statistics_init( &( hIvasRend->hHrtfs.hHrtfStatistics ), hIvasRend->sampleRateOut ) ) != IVAS_ERR_OK )
3266 : {
3267 0 : return error;
3268 : }
3269 : }
3270 :
3271 10354 : return IVAS_ERR_OK;
3272 : }
3273 :
3274 :
3275 1332 : static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup(
3276 : const IVAS_CUSTOM_LS_DATA rendCustomLsLayout )
3277 : {
3278 : int16_t i;
3279 : LSSETUP_CUSTOM_STRUCT customLs;
3280 :
3281 : /* Copy layout description */
3282 1332 : customLs.num_spk = rendCustomLsLayout.num_spk;
3283 1332 : mvr2r( rendCustomLsLayout.azimuth, customLs.ls_azimuth, rendCustomLsLayout.num_spk );
3284 1332 : mvr2r( rendCustomLsLayout.elevation, customLs.ls_elevation, rendCustomLsLayout.num_spk );
3285 :
3286 1332 : customLs.is_planar_setup = 1;
3287 6660 : for ( i = 0; i < rendCustomLsLayout.num_spk; ++i )
3288 : {
3289 6660 : if ( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
3290 : {
3291 1332 : customLs.is_planar_setup = 0;
3292 1332 : break;
3293 : }
3294 : }
3295 :
3296 1332 : customLs.num_lfe = rendCustomLsLayout.num_lfe;
3297 1332 : mvs2s( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
3298 :
3299 1332 : return customLs;
3300 : }
3301 :
3302 :
3303 1332 : static ivas_error validateCustomLsLayout(
3304 : const IVAS_CUSTOM_LS_DATA layout )
3305 : {
3306 : int16_t i;
3307 :
3308 : /* Negative number of speakers or LFEs makes no sense */
3309 1332 : if ( layout.num_spk < 0 || layout.num_lfe < 0 )
3310 : {
3311 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3312 : }
3313 :
3314 : /* There must be at least one speaker or LFE in the layout */
3315 1332 : if ( layout.num_spk + layout.num_lfe <= 0 )
3316 : {
3317 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3318 : }
3319 :
3320 : /* LFE indices must be positive */
3321 1332 : for ( i = 0; i < layout.num_lfe; ++i )
3322 : {
3323 0 : if ( layout.lfe_idx[i] < 0 )
3324 : {
3325 0 : return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
3326 : }
3327 : }
3328 :
3329 1332 : return IVAS_ERR_OK;
3330 : }
3331 :
3332 :
3333 : /*-------------------------------------------------------------------*
3334 : * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
3335 : *
3336 : *
3337 : *-------------------------------------------------------------------*/
3338 :
3339 702 : ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
3340 : IVAS_REND_HANDLE hIvasRend,
3341 : const IVAS_CUSTOM_LS_DATA layout )
3342 : {
3343 : int16_t i, numOutChannels;
3344 : ivas_error error;
3345 : input_mc *inputMc;
3346 : input_sba *inputSba;
3347 :
3348 : /* Validate function arguments */
3349 702 : if ( hIvasRend == NULL )
3350 : {
3351 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3352 : }
3353 :
3354 702 : if ( hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
3355 : {
3356 : /* Specifying details of custom speaker layout only makes sense if output config is set to custom speaker layout */
3357 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
3358 : }
3359 :
3360 702 : if ( ( error = validateCustomLsLayout( layout ) ) != IVAS_ERR_OK )
3361 : {
3362 0 : return error;
3363 : }
3364 :
3365 702 : hIvasRend->customLsOut = makeCustomLsSetup( layout );
3366 :
3367 : /* Re-initialize limiter - number of output channels may have changed */
3368 702 : if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
3369 : {
3370 0 : return error;
3371 : }
3372 :
3373 702 : if ( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, hIvasRend->sampleRateOut ) ) != IVAS_ERR_OK )
3374 : {
3375 0 : return error;
3376 : }
3377 :
3378 : /* Re-initialize EFAP - output layout has changed or has been fully defined for the first time */
3379 702 : if ( ( error = initEfap( &hIvasRend->efapOutWrapper, hIvasRend->outputConfig, &hIvasRend->customLsOut ) ) != IVAS_ERR_OK )
3380 : {
3381 0 : return error;
3382 : }
3383 :
3384 : /* Re-initialize panning gains for each active MC input, This includes re-initializing
3385 : * LFE handling for the new output layout, which means custom LFE handling is overwritten,
3386 : * if previously set for any MC input. */
3387 1404 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3388 : {
3389 702 : inputMc = &hIvasRend->inputsMc[i];
3390 702 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
3391 : {
3392 : /* Input inactive, skip. */
3393 702 : continue;
3394 : }
3395 :
3396 0 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
3397 :
3398 0 : if ( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
3399 : {
3400 0 : return error;
3401 : }
3402 : }
3403 :
3404 : /* Re-initialize panning gains for each active SBA input */
3405 1404 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3406 : {
3407 702 : inputSba = &hIvasRend->inputsSba[i];
3408 :
3409 702 : if ( inputSba->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
3410 : {
3411 : /* Input inactive, skip. */
3412 702 : continue;
3413 : }
3414 :
3415 0 : if ( ( error = updateSbaPanGains( inputSba, hIvasRend->outputConfig, hIvasRend->hRendererConfig, NULL, NULL ) ) != IVAS_ERR_OK )
3416 : {
3417 0 : return error;
3418 : }
3419 : }
3420 :
3421 702 : return IVAS_ERR_OK;
3422 : }
3423 :
3424 :
3425 : /*-------------------------------------------------------------------*
3426 : * IVAS_REND_GetNumOutChannels()
3427 : *
3428 : *
3429 : *-------------------------------------------------------------------*/
3430 :
3431 8828213 : ivas_error IVAS_REND_GetNumOutChannels(
3432 : IVAS_REND_CONST_HANDLE hIvasRend,
3433 : int16_t *numOutChannels )
3434 : {
3435 : ivas_error error;
3436 :
3437 : /* Validate function arguments */
3438 8828213 : if ( hIvasRend == NULL || numOutChannels == NULL )
3439 : {
3440 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3441 : }
3442 :
3443 : /* Handle special cases where additional info is needed from the renderer, otherwise use getAudioConfigNumChannels() */
3444 8828213 : switch ( hIvasRend->outputConfig )
3445 : {
3446 276726 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3447 276726 : *numOutChannels = hIvasRend->customLsOut.num_spk + hIvasRend->customLsOut.num_lfe;
3448 276726 : break;
3449 8551487 : default:
3450 8551487 : if ( ( error = getAudioConfigNumChannels( hIvasRend->outputConfig, numOutChannels ) ) != IVAS_ERR_OK )
3451 : {
3452 0 : return error;
3453 : }
3454 8551487 : break;
3455 : }
3456 :
3457 8828213 : return IVAS_ERR_OK;
3458 : }
3459 :
3460 :
3461 25412 : static IVAS_REND_InputId makeInputId(
3462 : AUDIO_CONFIG config,
3463 : const int32_t inputIndex )
3464 : {
3465 : /* Put config type in second byte (from LSB), put index + 1 in first byte
3466 : *
3467 : * Index is incremented here so that a valid ID can never be 0. */
3468 25412 : return (IVAS_REND_InputId) ( ( ( (uint32_t) getAudioConfigType( config ) ) << 8 ) | ( inputIndex + 1 ) );
3469 : }
3470 :
3471 :
3472 39022311 : static ivas_error getInputById(
3473 : IVAS_REND_HANDLE hIvasRend,
3474 : IVAS_REND_InputId inputId,
3475 : void **ppInput )
3476 : {
3477 : int32_t inputIndex;
3478 : IVAS_REND_AudioConfigType configType;
3479 : input_base *pInputBase;
3480 :
3481 : /* Reverse makeInputId() */
3482 39022311 : inputIndex = ( inputId & 0xFF ) - 1;
3483 39022311 : configType = ( inputId & 0xFF00 ) >> 8;
3484 :
3485 : /* Validate values derived from input ID */
3486 39022311 : if ( inputIndex < 0 )
3487 : {
3488 0 : return IVAS_ERR_INVALID_INPUT_ID;
3489 : }
3490 39022311 : switch ( configType )
3491 : {
3492 31656128 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3493 31656128 : if ( inputIndex > RENDERER_MAX_ISM_INPUTS )
3494 : {
3495 0 : return IVAS_ERR_INVALID_INPUT_ID;
3496 : }
3497 31656128 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3498 31656128 : break;
3499 1376932 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3500 1376932 : if ( inputIndex > RENDERER_MAX_MC_INPUTS )
3501 : {
3502 0 : return IVAS_ERR_INVALID_INPUT_ID;
3503 : }
3504 1376932 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3505 1376932 : break;
3506 4774375 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3507 4774375 : if ( inputIndex > RENDERER_MAX_SBA_INPUTS )
3508 : {
3509 0 : return IVAS_ERR_INVALID_INPUT_ID;
3510 : }
3511 4774375 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3512 4774375 : break;
3513 1214876 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3514 1214876 : if ( inputIndex > RENDERER_MAX_MASA_INPUTS )
3515 : {
3516 0 : return IVAS_ERR_INVALID_INPUT_ID;
3517 : }
3518 1214876 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3519 1214876 : break;
3520 0 : default:
3521 0 : return IVAS_ERR_INVALID_INPUT_ID;
3522 : }
3523 :
3524 : /* Ensure input ID matches and that input is active */
3525 39022311 : if ( pInputBase->id != inputId || pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
3526 : {
3527 0 : return IVAS_ERR_INVALID_INPUT_ID;
3528 : }
3529 :
3530 : /* Validation done, set value via output parameter */
3531 39022311 : *ppInput = pInputBase;
3532 :
3533 39022311 : return IVAS_ERR_OK;
3534 : }
3535 :
3536 :
3537 7007633 : static ivas_error getConstInputById(
3538 : IVAS_REND_CONST_HANDLE hIvasRend,
3539 : const IVAS_REND_InputId inputId,
3540 : const void **ppInput )
3541 : {
3542 : int32_t inputIndex;
3543 : IVAS_REND_AudioConfigType configType;
3544 : const input_base *pInputBase;
3545 :
3546 : /* Reverse makeInputId() */
3547 7007633 : inputIndex = ( inputId & 0xFF ) - 1;
3548 7007633 : configType = ( inputId & 0xFF00 ) >> 8;
3549 :
3550 : /* Validate values derived from input ID */
3551 7007633 : if ( inputIndex < 0 )
3552 : {
3553 0 : return IVAS_ERR_INVALID_INPUT_ID;
3554 : }
3555 7007633 : switch ( configType )
3556 : {
3557 15940 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3558 15940 : if ( inputIndex > RENDERER_MAX_ISM_INPUTS )
3559 : {
3560 0 : return IVAS_ERR_INVALID_INPUT_ID;
3561 : }
3562 15940 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3563 15940 : break;
3564 1376302 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3565 1376302 : if ( inputIndex > RENDERER_MAX_MC_INPUTS )
3566 : {
3567 0 : return IVAS_ERR_INVALID_INPUT_ID;
3568 : }
3569 1376302 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3570 1376302 : break;
3571 4774375 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3572 4774375 : if ( inputIndex > RENDERER_MAX_SBA_INPUTS )
3573 : {
3574 0 : return IVAS_ERR_INVALID_INPUT_ID;
3575 : }
3576 4774375 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3577 4774375 : break;
3578 841016 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3579 841016 : if ( inputIndex > RENDERER_MAX_MASA_INPUTS )
3580 : {
3581 0 : return IVAS_ERR_INVALID_INPUT_ID;
3582 : }
3583 841016 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3584 841016 : break;
3585 0 : default:
3586 0 : return IVAS_ERR_INVALID_INPUT_ID;
3587 : }
3588 :
3589 : /* Ensure input ID matches and that input is active */
3590 7007633 : if ( pInputBase->id != inputId || pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
3591 : {
3592 0 : return IVAS_ERR_INVALID_INPUT_ID;
3593 : }
3594 :
3595 : /* Validation done, set value via output parameter */
3596 7007633 : *ppInput = pInputBase;
3597 :
3598 7007633 : return IVAS_ERR_OK;
3599 : }
3600 :
3601 :
3602 91908 : static void *getInputByIndex(
3603 : void *inputsArray,
3604 : const size_t index,
3605 : const IVAS_REND_AudioConfigType inputType )
3606 : {
3607 91908 : switch ( inputType )
3608 : {
3609 7782 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3610 7782 : return (input_mc *) inputsArray + index;
3611 12450 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3612 12450 : return (input_sba *) inputsArray + index;
3613 63492 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3614 63492 : return (input_ism *) inputsArray + index;
3615 8184 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3616 8184 : return (input_masa *) inputsArray + index;
3617 0 : default:
3618 0 : break;
3619 : }
3620 :
3621 : /* this should be unreachable */
3622 0 : assert( 0 );
3623 :
3624 : /* include a final return to make the linter happy and avoid problems with wmc_tool (see #1355) */
3625 : return NULL;
3626 : }
3627 :
3628 :
3629 25412 : static ivas_error findFreeInputSlot(
3630 : void *inputs,
3631 : const IVAS_REND_AudioConfigType inputType,
3632 : const int32_t maxInputs,
3633 : int32_t *inputIndex )
3634 : {
3635 : /* Using a void pointer and a separately provided type is a hack for this function
3636 : to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
3637 : Assumptions:
3638 : - input_base is always the first member in the input struct
3639 : - memory alignments of original input type and input_base are the same
3640 : */
3641 : int32_t i;
3642 : bool canAddInput;
3643 : const input_base *pInputBase;
3644 :
3645 25412 : canAddInput = false;
3646 :
3647 : /* Find first unused input in array */
3648 41084 : for ( i = 0; i < maxInputs; ++i )
3649 : {
3650 41084 : pInputBase = (const input_base *) getInputByIndex( inputs, i, inputType );
3651 :
3652 41084 : if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
3653 : {
3654 25412 : *inputIndex = i;
3655 25412 : canAddInput = true;
3656 25412 : break;
3657 : }
3658 : }
3659 :
3660 25412 : if ( !canAddInput )
3661 : {
3662 0 : return IVAS_ERR_TOO_MANY_INPUTS;
3663 : }
3664 :
3665 25412 : return IVAS_ERR_OK;
3666 : }
3667 :
3668 :
3669 : /*-------------------------------------------------------------------------
3670 : * Function getCldfbRendFlag()
3671 : *
3672 : *
3673 : *------------------------------------------------------------------------*/
3674 :
3675 79918 : static int16_t getCldfbRendFlag(
3676 : IVAS_REND_HANDLE hIvasRend, /* i : Renderer handle */
3677 : const IVAS_REND_AudioConfigType new_configType )
3678 : {
3679 : int16_t i;
3680 79918 : int16_t numMasaInputs = 0, numSbaInputs = 0;
3681 : int16_t isCldfbRend;
3682 :
3683 79918 : isCldfbRend = 0;
3684 : /* This function is called during three different phases of renderer processing:
3685 : * - IVAS_REND_AddInput()
3686 : * - IVAS_REND_FeedRenderConfig()
3687 : * - IVAS_REND_GetSplitBinauralBitstream()
3688 : * Only the last case can assume all inputs are present for the current frame to be rendered */
3689 79918 : if ( hIvasRend->hRendererConfig != NULL )
3690 : {
3691 159836 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3692 : {
3693 79918 : numMasaInputs += ( hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ? 0 : 1;
3694 : }
3695 159836 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3696 : {
3697 79918 : numSbaInputs += ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1;
3698 : }
3699 79918 : if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
3700 : {
3701 16888 : isCldfbRend = 1;
3702 : }
3703 : }
3704 :
3705 79918 : return isCldfbRend;
3706 : }
3707 :
3708 : /*-------------------------------------------------------------------------
3709 : * Function isar_pre_rend_init()
3710 : *
3711 : *
3712 : *------------------------------------------------------------------------*/
3713 :
3714 11066 : static ivas_error isar_pre_rend_init(
3715 : SPLIT_REND_WRAPPER *pSplitRendWrapper,
3716 : IVAS_REND_AudioBuffer *pSplitRendEncBuffer,
3717 : ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config,
3718 : IVAS_REND_HeadRotData headRotData,
3719 : const int32_t outputSampleRate,
3720 : const AUDIO_CONFIG outConfig,
3721 : const int16_t cldfb_in_flag,
3722 : const int16_t num_subframes )
3723 : {
3724 : bool realloc;
3725 : ivas_error error;
3726 : IVAS_REND_AudioBufferConfig bufConfig;
3727 :
3728 11066 : realloc = false;
3729 :
3730 : /* only perform init if split rendering output */
3731 11066 : if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
3732 : {
3733 10152 : return IVAS_ERR_OK;
3734 : }
3735 :
3736 : /* these functions should only be called once during initial allocation */
3737 914 : if ( pSplitRendEncBuffer->data == NULL )
3738 : {
3739 472 : if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
3740 : {
3741 328 : ISAR_PRE_REND_GetMultiBinPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData, headRotData.sr_pose_pred_axis );
3742 : }
3743 144 : else if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
3744 : {
3745 144 : isar_renderSplitUpdateNoCorrectionPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData );
3746 : }
3747 :
3748 472 : 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 )
3749 : {
3750 0 : return error;
3751 : }
3752 : }
3753 :
3754 : /* We may need to change the allocated buffer size if a new input is added.
3755 : * If the cldfb_in_flag is different from what was previously allocated for the buffer, change the size */
3756 914 : if ( pSplitRendEncBuffer->data != NULL && ( cldfb_in_flag != pSplitRendEncBuffer->config.is_cldfb ) )
3757 : {
3758 68 : realloc = true;
3759 : }
3760 :
3761 914 : if ( pSplitRendEncBuffer->data == NULL || realloc )
3762 : {
3763 : /* set buffer config */
3764 540 : bufConfig.is_cldfb = cldfb_in_flag;
3765 540 : bufConfig.numSamplesPerChannel = cldfb_in_flag ? MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL : L_FRAME_MAX;
3766 540 : bufConfig.numChannels = BINAURAL_CHANNELS * pSplitRendWrapper->multiBinPoseData.num_poses;
3767 540 : pSplitRendEncBuffer->config = bufConfig;
3768 :
3769 : /* allocate memory */
3770 540 : if ( realloc )
3771 : {
3772 68 : free( pSplitRendEncBuffer->data );
3773 : }
3774 :
3775 540 : if ( ( pSplitRendEncBuffer->data = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL )
3776 : {
3777 0 : return IVAS_ERR_FAILED_ALLOC;
3778 : }
3779 : }
3780 :
3781 914 : return IVAS_ERR_OK;
3782 : }
3783 10354 : static IVAS_ROOM_SIZE_T getDefaultReverbSize(
3784 : input_ism *ismInputs,
3785 : input_masa *masaInputs,
3786 : input_mc *mcInputs,
3787 : input_sba *sbaInputs )
3788 : {
3789 : bool combinedFormat;
3790 : int16_t i;
3791 : int16_t nActiveInputsIsm, nActiveInputsMasa, nActiveInputsSba, nActiveInputsMc;
3792 : IVAS_ROOM_SIZE_T selectedReverb;
3793 10354 : selectedReverb = IVAS_ROOM_SIZE_MEDIUM;
3794 :
3795 10354 : combinedFormat = false;
3796 10354 : nActiveInputsIsm = 0;
3797 10354 : nActiveInputsMasa = 0;
3798 10354 : nActiveInputsMc = 0;
3799 10354 : nActiveInputsSba = 0;
3800 :
3801 51770 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
3802 : {
3803 41416 : if ( ismInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3804 : {
3805 6226 : nActiveInputsIsm++;
3806 : }
3807 : }
3808 20708 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
3809 : {
3810 10354 : if ( masaInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3811 : {
3812 560 : nActiveInputsMasa++;
3813 : }
3814 : }
3815 20708 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
3816 : {
3817 10354 : if ( mcInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3818 : {
3819 2594 : nActiveInputsMc++;
3820 : }
3821 : }
3822 20708 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
3823 : {
3824 10354 : if ( sbaInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3825 : {
3826 974 : nActiveInputsSba++;
3827 : }
3828 : }
3829 :
3830 : /* ISM present with MASA/SBA inputs; treat as combined format */
3831 10354 : if ( nActiveInputsIsm && ( nActiveInputsMasa || nActiveInputsSba ) )
3832 : {
3833 0 : combinedFormat = true;
3834 : }
3835 :
3836 10354 : if ( combinedFormat )
3837 : {
3838 0 : selectedReverb = IVAS_ROOM_SIZE_MEDIUM;
3839 : }
3840 : else
3841 : {
3842 : /* Only set large if ISM is present alone */
3843 10354 : if ( nActiveInputsIsm && !nActiveInputsMc )
3844 : {
3845 6226 : selectedReverb = IVAS_ROOM_SIZE_LARGE;
3846 : }
3847 : /* if only MC is present, set medium; Will not be overridden by the subsequent block */
3848 4128 : else if ( nActiveInputsMc )
3849 : {
3850 2594 : selectedReverb = IVAS_ROOM_SIZE_MEDIUM;
3851 : }
3852 1534 : else if ( nActiveInputsMasa || nActiveInputsSba )
3853 : {
3854 1534 : selectedReverb = IVAS_ROOM_SIZE_SMALL;
3855 : }
3856 : }
3857 :
3858 10354 : return selectedReverb;
3859 : }
3860 :
3861 :
3862 : /*-------------------------------------------------------------------*
3863 : * IVAS_REND_AddInput()
3864 : *
3865 : *
3866 : *-------------------------------------------------------------------*/
3867 :
3868 25412 : ivas_error IVAS_REND_AddInput(
3869 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3870 : const AUDIO_CONFIG inConfig, /* i : audio config for a new input */
3871 : IVAS_REND_InputId *inputId /* o : ID of the new input */
3872 : )
3873 : {
3874 : ivas_error error;
3875 : int32_t maxNumInputsOfType;
3876 : void *inputsArray;
3877 : IVAS_REND_AudioConfigType inputType;
3878 : ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles * );
3879 : void ( *setInputDelay )( void *, bool );
3880 : int32_t inputIndex;
3881 : bool splitPreRendCldfb;
3882 :
3883 25412 : splitPreRendCldfb = false;
3884 :
3885 : /* Validate function arguments */
3886 25412 : if ( hIvasRend == NULL || inputId == NULL )
3887 : {
3888 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3889 : }
3890 :
3891 25412 : if ( hIvasRend->hRendererConfig != NULL )
3892 : {
3893 : int16_t cldfb_in_flag;
3894 11066 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) );
3895 :
3896 11066 : if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper,
3897 : &hIvasRend->splitRendEncBuffer,
3898 11066 : &hIvasRend->hRendererConfig->split_rend_config,
3899 : hIvasRend->headRotData,
3900 : hIvasRend->sampleRateOut,
3901 : hIvasRend->outputConfig,
3902 : cldfb_in_flag,
3903 11066 : hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
3904 : {
3905 0 : return error;
3906 : }
3907 :
3908 : /*assumes that input has been added which means codec has been set to either lcld or lc3plus (even if render config specified default)*/
3909 11066 : splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD );
3910 : }
3911 :
3912 25412 : inputType = getAudioConfigType( inConfig );
3913 25412 : switch ( inputType )
3914 : {
3915 15940 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3916 15940 : maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
3917 15940 : inputsArray = hIvasRend->inputsIsm;
3918 15940 : activateInput = setRendInputActiveIsm;
3919 15940 : setInputDelay = setRendInputDelayIsm;
3920 15940 : break;
3921 2594 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3922 2594 : maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
3923 2594 : inputsArray = hIvasRend->inputsMc;
3924 2594 : activateInput = setRendInputActiveMc;
3925 2594 : setInputDelay = setRendInputDelayMc;
3926 2594 : break;
3927 4150 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3928 4150 : maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
3929 4150 : inputsArray = hIvasRend->inputsSba;
3930 4150 : activateInput = setRendInputActiveSba;
3931 4150 : setInputDelay = setRendInputDelaySba;
3932 4150 : break;
3933 2728 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3934 2728 : maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
3935 2728 : inputsArray = hIvasRend->inputsMasa;
3936 2728 : activateInput = setRendInputActiveMasa;
3937 2728 : setInputDelay = setRendInputDelayMasa;
3938 2728 : break;
3939 0 : default:
3940 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
3941 : }
3942 :
3943 : /* Find first free input in array corresponding to input type */
3944 25412 : if ( ( error = findFreeInputSlot( inputsArray, inputType, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
3945 : {
3946 0 : return error;
3947 : }
3948 :
3949 25412 : *inputId = makeInputId( inConfig, inputIndex );
3950 25412 : if ( ( error = activateInput( getInputByIndex( inputsArray, inputIndex, inputType ), inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ) != IVAS_ERR_OK )
3951 : {
3952 0 : return error;
3953 : }
3954 :
3955 25412 : setInputDelay( getInputByIndex( inputsArray, inputIndex, inputType ), splitPreRendCldfb );
3956 :
3957 : /* set global maximum delay after adding an input */
3958 25412 : setMaxGlobalDelayNs( hIvasRend );
3959 :
3960 : /* select default reverb size after adding an input */
3961 25412 : if ( hIvasRend->selectedRoomReverbSize == DEFAULT_REVERB_UNSET )
3962 : {
3963 10354 : IVAS_REND_SetReverbRoomSize( hIvasRend,
3964 10354 : getDefaultReverbSize( hIvasRend->inputsIsm,
3965 10354 : hIvasRend->inputsMasa,
3966 10354 : hIvasRend->inputsMc,
3967 10354 : hIvasRend->inputsSba ) );
3968 : }
3969 :
3970 25412 : return IVAS_ERR_OK;
3971 : }
3972 :
3973 :
3974 : /*-------------------------------------------------------------------*
3975 : * IVAS_REND_ConfigureCustomInputLoudspeakerLayout()
3976 : *
3977 : *
3978 : * Note: this will reset any custom LFE routing set for the input
3979 : *-------------------------------------------------------------------*/
3980 :
3981 630 : ivas_error IVAS_REND_ConfigureCustomInputLoudspeakerLayout(
3982 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
3983 : const IVAS_REND_InputId inputId, /* i : ID of the input */
3984 : const IVAS_CUSTOM_LS_DATA layout /* i : custom loudspeaker layout for input */
3985 : )
3986 : {
3987 : input_mc *inputMc;
3988 : ivas_error error;
3989 :
3990 : /* Validate function arguments */
3991 630 : if ( hIvasRend == NULL )
3992 : {
3993 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3994 : }
3995 :
3996 630 : if ( ( error = validateCustomLsLayout( layout ) ) != IVAS_ERR_OK )
3997 : {
3998 0 : return error;
3999 : }
4000 :
4001 630 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputMc ) ) != IVAS_ERR_OK )
4002 : {
4003 0 : return error;
4004 : }
4005 :
4006 630 : if ( inputMc->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
4007 : {
4008 : /* Specifying details of custom speaker layout only makes sense if input config is set to custom speaker layout */
4009 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4010 : }
4011 :
4012 : /* Re-initialize panning gains for the MC input, This includes re-initializing LFE handling
4013 : * for the new input layout, which means custom LFE handling is overwritten, if previously
4014 : * set for the MC input. */
4015 630 : inputMc->customLsInput = makeCustomLsSetup( layout );
4016 :
4017 630 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
4018 :
4019 630 : if ( ( error = initEfap( &inputMc->efapInWrapper, inputMc->base.inConfig, &inputMc->customLsInput ) ) != IVAS_ERR_OK )
4020 : {
4021 0 : return error;
4022 : }
4023 :
4024 630 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
4025 : {
4026 216 : if ( ( error = initMcBinauralRendering( inputMc,
4027 216 : inputMc->base.inConfig,
4028 : hIvasRend->outputConfig,
4029 : hIvasRend->hRendererConfig,
4030 : hIvasRend->hHrtfs.hHrtfCrend,
4031 : hIvasRend->hHrtfs.hHrtfStatistics,
4032 : FALSE ) ) != IVAS_ERR_OK )
4033 : {
4034 0 : return error;
4035 : }
4036 : }
4037 :
4038 630 : if ( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
4039 : {
4040 0 : return error;
4041 : }
4042 :
4043 630 : return IVAS_ERR_OK;
4044 : }
4045 :
4046 :
4047 : /*-------------------------------------------------------------------*
4048 : * IVAS_REND_SetObjectIDs()
4049 : *
4050 : *
4051 : *-------------------------------------------------------------------*/
4052 :
4053 10354 : ivas_error IVAS_REND_SetObjectIDs(
4054 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
4055 : )
4056 : {
4057 : int16_t i;
4058 :
4059 : /* Validate function arguments */
4060 10354 : if ( hIvasRend == NULL )
4061 : {
4062 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4063 : }
4064 :
4065 51770 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
4066 : {
4067 41416 : hIvasRend->inputsIsm[i].object_id = i;
4068 : }
4069 :
4070 10354 : return IVAS_ERR_OK;
4071 : }
4072 :
4073 :
4074 : /*-------------------------------------------------------------------*
4075 : * IVAS_REND_SetInputGain()
4076 : *
4077 : *
4078 : *-------------------------------------------------------------------*/
4079 :
4080 25412 : ivas_error IVAS_REND_SetInputGain(
4081 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4082 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4083 : const float gain /* i : linear gain (not in dB) */
4084 : )
4085 : {
4086 : input_base *inputBase;
4087 : ivas_error error;
4088 :
4089 : /* Validate function arguments */
4090 25412 : if ( hIvasRend == NULL )
4091 : {
4092 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4093 : }
4094 :
4095 25412 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4096 : {
4097 0 : return error;
4098 : }
4099 :
4100 25412 : inputBase->gain = gain;
4101 :
4102 25412 : return IVAS_ERR_OK;
4103 : }
4104 :
4105 :
4106 : /*-------------------------------------------------------------------*
4107 : * IVAS_REND_SetInputLfeMtx()
4108 : *
4109 : *
4110 : *-------------------------------------------------------------------*/
4111 :
4112 0 : ivas_error IVAS_REND_SetInputLfeMtx(
4113 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4114 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4115 : const IVAS_REND_LfePanMtx *lfePanMtx /* i : LFE panning matrix */
4116 : )
4117 : {
4118 : int16_t i;
4119 : input_base *pInputBase;
4120 : input_mc *pInputMc;
4121 : ivas_error error;
4122 :
4123 : /* Validate function arguments */
4124 0 : if ( hIvasRend == NULL )
4125 : {
4126 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4127 : }
4128 :
4129 0 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ) != IVAS_ERR_OK )
4130 : {
4131 0 : return error;
4132 : }
4133 :
4134 0 : if ( getAudioConfigType( pInputBase->inConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
4135 : {
4136 : /* Custom LFE panning matrix only makes sense with channel-based input */
4137 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4138 : }
4139 0 : pInputMc = (input_mc *) pInputBase;
4140 :
4141 : /* copy LFE panning matrix */
4142 0 : for ( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; i++ )
4143 : {
4144 0 : mvr2r( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
4145 : }
4146 :
4147 0 : if ( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
4148 : {
4149 0 : return error;
4150 : }
4151 :
4152 0 : return IVAS_ERR_OK;
4153 : }
4154 :
4155 :
4156 : /*-------------------------------------------------------------------*
4157 : * IVAS_REND_SetInputLfePos()
4158 : *
4159 : *
4160 : *-------------------------------------------------------------------*/
4161 :
4162 0 : ivas_error IVAS_REND_SetInputLfePos(
4163 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4164 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4165 : const float inputGain, /* i : Input gain to be applied to the LFE channel(s) */
4166 : const float outputAzimuth, /* i : Output azimuth position */
4167 : const float outputElevation /* i : Output elevation position */
4168 : )
4169 : {
4170 : input_base *pInputBase;
4171 : input_mc *pInputMc;
4172 : ivas_error error;
4173 :
4174 : /* Validate function arguments */
4175 0 : if ( hIvasRend == NULL )
4176 : {
4177 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4178 : }
4179 :
4180 0 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ) != IVAS_ERR_OK )
4181 : {
4182 0 : return error;
4183 : }
4184 :
4185 0 : if ( getAudioConfigType( pInputBase->inConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
4186 : {
4187 : /* Custom LFE routing only makes sense with channel-based input */
4188 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4189 : }
4190 0 : pInputMc = (input_mc *) pInputBase;
4191 :
4192 0 : pInputMc->lfeRouting.pan_lfe = true;
4193 0 : pInputMc->lfeRouting.lfeInputGain = inputGain;
4194 0 : pInputMc->lfeRouting.lfeOutputAzimuth = outputAzimuth;
4195 0 : pInputMc->lfeRouting.lfeOutputElevation = outputElevation;
4196 :
4197 0 : if ( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
4198 : {
4199 0 : return error;
4200 : }
4201 :
4202 0 : return IVAS_ERR_OK;
4203 : }
4204 :
4205 :
4206 : /*-------------------------------------------------------------------*
4207 : * IVAS_REND_RemoveInput()
4208 : *
4209 : *
4210 : *-------------------------------------------------------------------*/
4211 : /* ToDo; unused function */
4212 0 : ivas_error IVAS_REND_RemoveInput(
4213 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4214 : const IVAS_REND_InputId inputId /* i : ID of the input */
4215 : )
4216 : {
4217 : ivas_error error;
4218 : input_base *inputBase;
4219 :
4220 : /* Validate function arguments */
4221 0 : if ( hIvasRend == NULL )
4222 : {
4223 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4224 : }
4225 :
4226 0 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4227 : {
4228 0 : return error;
4229 : }
4230 :
4231 0 : switch ( getAudioConfigType( inputBase->inConfig ) )
4232 : {
4233 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
4234 0 : clearInputIsm( (input_ism *) inputBase );
4235 0 : break;
4236 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
4237 0 : clearInputMc( (input_mc *) inputBase );
4238 0 : break;
4239 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
4240 0 : clearInputSba( (input_sba *) inputBase );
4241 0 : break;
4242 0 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
4243 0 : clearInputMasa( (input_masa *) inputBase );
4244 0 : break;
4245 0 : default:
4246 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
4247 : }
4248 :
4249 : /* set global maximum delay after removing an input */
4250 0 : setMaxGlobalDelayNs( hIvasRend );
4251 :
4252 0 : return IVAS_ERR_OK;
4253 : }
4254 :
4255 :
4256 : /*-------------------------------------------------------------------*
4257 : * IVAS_REND_GetInputNumChannels()
4258 : *
4259 : *
4260 : *-------------------------------------------------------------------*/
4261 :
4262 7007633 : ivas_error IVAS_REND_GetInputNumChannels(
4263 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
4264 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4265 : int16_t *numChannels /* o : number of channels of the input */
4266 : )
4267 : {
4268 : ivas_error error;
4269 : const input_base *pInput;
4270 :
4271 : /* Validate function arguments */
4272 7007633 : if ( hIvasRend == NULL || numChannels == NULL )
4273 : {
4274 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4275 : }
4276 :
4277 7007633 : if ( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ) != IVAS_ERR_OK )
4278 : {
4279 0 : return error;
4280 : }
4281 :
4282 7007633 : if ( ( error = getRendInputNumChannels( pInput, numChannels ) ) != IVAS_ERR_OK )
4283 : {
4284 0 : return error;
4285 : }
4286 :
4287 7007633 : return IVAS_ERR_OK;
4288 : }
4289 :
4290 :
4291 : /*-------------------------------------------------------------------*
4292 : * IVAS_REND_GetNumAllObjects()
4293 : *
4294 : *
4295 : *-------------------------------------------------------------------*/
4296 :
4297 15940 : ivas_error IVAS_REND_GetNumAllObjects(
4298 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
4299 : int16_t *numChannels /* o : number of all objects */
4300 : )
4301 : {
4302 15940 : if ( hIvasRend == NULL || numChannels == NULL )
4303 : {
4304 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4305 : }
4306 :
4307 15940 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA1 || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA2 )
4308 : {
4309 132 : *numChannels = (int16_t) hIvasRend->inputsIsm[0].total_num_objects;
4310 : }
4311 :
4312 15940 : return IVAS_ERR_OK;
4313 : }
4314 :
4315 :
4316 : /*-------------------------------------------------------------------*
4317 : * IVAS_REND_GetDelay()
4318 : *
4319 : *
4320 : *-------------------------------------------------------------------*/
4321 :
4322 472 : ivas_error IVAS_REND_GetDelay(
4323 : IVAS_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
4324 : int16_t *nSamples, /* o : Renderer delay in samples */
4325 : int32_t *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
4326 : )
4327 : {
4328 : int32_t max_latency_ns;
4329 :
4330 : /* Validate function arguments */
4331 472 : if ( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
4332 : {
4333 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4334 : }
4335 :
4336 472 : *nSamples = 0;
4337 472 : *timeScale = hIvasRend->sampleRateOut;
4338 :
4339 472 : max_latency_ns = getMaxGlobalDelayNs( hIvasRend );
4340 :
4341 472 : *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns );
4342 :
4343 472 : return IVAS_ERR_OK;
4344 : }
4345 :
4346 : /*-------------------------------------------------------------------*
4347 : * IVAS_REND_FeedInputAudio()
4348 : *
4349 : *
4350 : *-------------------------------------------------------------------*/
4351 :
4352 22816121 : ivas_error IVAS_REND_FeedInputAudio(
4353 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4354 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4355 : const IVAS_REND_ReadOnlyAudioBuffer inputAudio, /* i : buffer with input audio */
4356 : const bool flushInputs /* i : flush input audio */
4357 : )
4358 : {
4359 : ivas_error error;
4360 : input_base *inputBase;
4361 : int16_t numInputChannels;
4362 : int16_t cldfb2tdSampleFact;
4363 :
4364 : /* Validate function arguments */
4365 22816121 : if ( hIvasRend == NULL || inputAudio.data == NULL )
4366 : {
4367 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4368 : }
4369 :
4370 22816121 : cldfb2tdSampleFact = ( inputAudio.config.is_cldfb ) ? 2 : 1;
4371 :
4372 22816121 : if ( inputAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
4373 22816121 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 1 ) )
4374 : {
4375 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
4376 : }
4377 :
4378 22816121 : if ( inputAudio.config.numChannels <= 0 || MAX_INPUT_CHANNELS < inputAudio.config.numChannels )
4379 : {
4380 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4381 : }
4382 :
4383 22816121 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
4384 10262962 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
4385 10134594 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
4386 10133658 : ( inputAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( BINAURAL_RENDERING_FRAME_SIZE_MS * hIvasRend->num_subframes ) * hIvasRend->sampleRateOut )
4387 : {
4388 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
4389 : }
4390 :
4391 22816121 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4392 : {
4393 0 : return error;
4394 : }
4395 :
4396 22816121 : if ( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ) != IVAS_ERR_OK )
4397 : {
4398 0 : return error;
4399 : }
4400 :
4401 22816121 : if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA1 || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA2 ) && inputBase->inConfig == IVAS_AUDIO_CONFIG_OBA )
4402 : {
4403 27612 : numInputChannels = (int16_t) hIvasRend->inputsIsm[0].total_num_objects;
4404 : }
4405 :
4406 22816121 : if ( numInputChannels != inputAudio.config.numChannels )
4407 : {
4408 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4409 : }
4410 :
4411 22816121 : inputBase->inputBuffer.config = inputAudio.config;
4412 22816121 : if ( ( error = alignInputDelay(
4413 : inputBase,
4414 : inputAudio,
4415 : hIvasRend->maxGlobalDelayNs,
4416 : hIvasRend->sampleRateOut,
4417 : cldfb2tdSampleFact,
4418 : flushInputs ) ) != IVAS_ERR_OK )
4419 : {
4420 0 : return error;
4421 : }
4422 22816121 : inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact;
4423 :
4424 22816121 : return IVAS_ERR_OK;
4425 : }
4426 :
4427 :
4428 : /*-------------------------------------------------------------------*
4429 : * IVAS_REND_FeedInputObjectMetadata()
4430 : *
4431 : *
4432 : *-------------------------------------------------------------------*/
4433 :
4434 15806288 : ivas_error IVAS_REND_FeedInputObjectMetadata(
4435 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4436 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4437 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
4438 : )
4439 : {
4440 : input_base *inputBase;
4441 : input_ism *inputIsm;
4442 : ivas_error error;
4443 :
4444 : /* Validate function arguments */
4445 15806288 : if ( hIvasRend == NULL )
4446 : {
4447 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4448 : }
4449 :
4450 15806288 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4451 : {
4452 0 : return error;
4453 : }
4454 :
4455 15806288 : if ( inputBase->inConfig != IVAS_AUDIO_CONFIG_OBA )
4456 : {
4457 : /* Object metadata should only be fed for object inputs */
4458 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4459 : }
4460 :
4461 15806288 : inputIsm = (input_ism *) inputBase;
4462 15806288 : inputIsm->previousPos = inputIsm->currentPos;
4463 15806288 : inputIsm->currentPos = objectPosition;
4464 :
4465 15806288 : return IVAS_ERR_OK;
4466 : }
4467 :
4468 :
4469 : /*-------------------------------------------------------------------*
4470 : * IVAS_REND_FeedInputObjectMetadataToOMasa()
4471 : *
4472 : *
4473 : *-------------------------------------------------------------------*/
4474 :
4475 89784 : ivas_error IVAS_REND_FeedInputObjectMetadataToOMasa(
4476 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4477 : const int16_t inputIndex, /* i : Index of the input */
4478 : const IVAS_ISM_METADATA objectPosition /* i : object position struct */
4479 : )
4480 : {
4481 : /* Validate function arguments */
4482 89784 : if ( hIvasRend == NULL )
4483 : {
4484 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4485 : }
4486 :
4487 : /* Set position to OMasa struct */
4488 89784 : hIvasRend->inputsIsm->hOMasa->ism_azimuth[inputIndex] = objectPosition.azimuth;
4489 89784 : hIvasRend->inputsIsm->hOMasa->ism_elevation[inputIndex] = objectPosition.elevation;
4490 :
4491 89784 : return IVAS_ERR_OK;
4492 : }
4493 :
4494 :
4495 : /*-------------------------------------------------------------------*
4496 : * IVAS_REND_FeedInputMasaMetadata()
4497 : *
4498 : *
4499 : *-------------------------------------------------------------------*/
4500 :
4501 373860 : ivas_error IVAS_REND_FeedInputMasaMetadata(
4502 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4503 : const IVAS_REND_InputId inputId, /* i : ID of the input */
4504 : IVAS_MASA_METADATA_HANDLE masaMetadata /* i : MASA metadata frame */
4505 : )
4506 : {
4507 : ivas_error error;
4508 : input_base *inputBase;
4509 : input_masa *inputMasa;
4510 :
4511 : /* Validate function arguments */
4512 373860 : if ( hIvasRend == NULL )
4513 : {
4514 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4515 : }
4516 :
4517 373860 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4518 : {
4519 0 : return error;
4520 : }
4521 :
4522 373860 : if ( getAudioConfigType( inputBase->inConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
4523 : {
4524 : /* MASA metadata should only be fed for MASA inputs */
4525 0 : return IVAS_ERR_METADATA_NOT_EXPECTED;
4526 : }
4527 :
4528 373860 : inputMasa = (input_masa *) inputBase;
4529 373860 : inputMasa->masaMetadata = *masaMetadata;
4530 373860 : inputMasa->metadataHasBeenFed = true;
4531 :
4532 373860 : return IVAS_ERR_OK;
4533 : }
4534 :
4535 :
4536 : /*-------------------------------------------------------------------*
4537 : * IVAS_REND_InitConfig()
4538 : *
4539 : *
4540 : *-------------------------------------------------------------------*/
4541 :
4542 10354 : ivas_error IVAS_REND_InitConfig(
4543 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4544 : const AUDIO_CONFIG outAudioConfig /* i : output audioConfig */
4545 : )
4546 : {
4547 : ivas_error error;
4548 : bool rendererConfigEnabled;
4549 :
4550 10354 : rendererConfigEnabled = ( getAudioConfigType( outAudioConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
4551 :
4552 10354 : if ( rendererConfigEnabled )
4553 : {
4554 4540 : hIvasRend->rendererConfigEnabled = 1;
4555 : }
4556 : else
4557 : {
4558 5814 : hIvasRend->rendererConfigEnabled = 0;
4559 : }
4560 :
4561 10354 : if ( rendererConfigEnabled )
4562 : {
4563 4540 : if ( ( error = ivas_render_config_open( &( hIvasRend->hRendererConfig ) ) ) != IVAS_ERR_OK )
4564 : {
4565 0 : return error;
4566 : }
4567 4540 : if ( ( error = ivas_render_config_init_from_rom( &hIvasRend->hRendererConfig ) ) != IVAS_ERR_OK )
4568 : {
4569 0 : return error;
4570 : }
4571 : }
4572 : else
4573 : {
4574 5814 : hIvasRend->hRendererConfig = NULL;
4575 : }
4576 :
4577 10354 : return IVAS_ERR_OK;
4578 : }
4579 :
4580 :
4581 : /*-------------------------------------------------------------------*
4582 : * IVAS_REND_GetRenderConfig()
4583 : *
4584 : *
4585 : *-------------------------------------------------------------------*/
4586 :
4587 1696 : ivas_error IVAS_REND_GetRenderConfig(
4588 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
4589 : const IVAS_RENDER_CONFIG_HANDLE hRCout /* o : Render configuration handle */
4590 : )
4591 : {
4592 : RENDER_CONFIG_HANDLE hRCin;
4593 :
4594 1696 : if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL || hRCout == NULL )
4595 : {
4596 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4597 : }
4598 :
4599 1696 : hRCin = hIvasRend->hRendererConfig;
4600 :
4601 1696 : hRCout->roomAcoustics.aeID = hRCin->roomAcoustics.aeID;
4602 1696 : hRCout->roomAcoustics.nBands = hRCin->roomAcoustics.nBands;
4603 1696 : hRCout->roomAcoustics.acousticPreDelay = hRCin->roomAcoustics.acousticPreDelay;
4604 1696 : hRCout->roomAcoustics.inputPreDelay = hRCin->roomAcoustics.inputPreDelay;
4605 1696 : mvr2r( hRCin->directivity, hRCout->directivity, 3 * MAX_NUM_OBJECTS );
4606 :
4607 1696 : mvr2r( hRCin->roomAcoustics.pFc_input, hRCout->roomAcoustics.pFc_input, CLDFB_NO_CHANNELS_MAX );
4608 1696 : mvr2r( hRCin->roomAcoustics.pAcoustic_rt60, hRCout->roomAcoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX );
4609 1696 : mvr2r( hRCin->roomAcoustics.pAcoustic_dsr, hRCout->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX );
4610 :
4611 1696 : hRCout->split_rend_config.splitRendBitRate = ISAR_MAX_SPLIT_REND_BITRATE;
4612 1696 : hRCout->split_rend_config.dof = 3;
4613 1696 : hRCout->split_rend_config.hq_mode = 0;
4614 1696 : hRCout->split_rend_config.codec_delay_ms = 0;
4615 1696 : hRCout->split_rend_config.isar_frame_size_ms = 20;
4616 1696 : hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
4617 1696 : hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
4618 1696 : hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
4619 1696 : hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
4620 1696 : hRCout->split_rend_config.lc3plus_highres = 0;
4621 :
4622 1696 : hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er;
4623 1696 : hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
4624 :
4625 1696 : mvr2r( hRCin->distAtt, hRCout->distAtt, 3 );
4626 :
4627 1696 : return IVAS_ERR_OK;
4628 : }
4629 :
4630 :
4631 : /*-------------------------------------------------------------------*
4632 : * IVAS_REND_FeedRenderConfig()
4633 : *
4634 : *
4635 : *-------------------------------------------------------------------*/
4636 :
4637 3190 : ivas_error IVAS_REND_FeedRenderConfig(
4638 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
4639 : const IVAS_RENDER_CONFIG_DATA renderConfig /* i : Render configuration struct */
4640 : )
4641 : {
4642 : RENDER_CONFIG_HANDLE hRenderConfig;
4643 : uint16_t i;
4644 : input_ism *pIsmInput;
4645 : input_masa *pMasaInput;
4646 : input_mc *pMcInput;
4647 : input_sba *pSbaInput;
4648 : ivas_error error;
4649 :
4650 3190 : if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
4651 : {
4652 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4653 : }
4654 3190 : hRenderConfig = hIvasRend->hRendererConfig;
4655 :
4656 3190 : hRenderConfig->roomAcoustics.aeID = renderConfig.roomAcoustics.aeID;
4657 3190 : hRenderConfig->roomAcoustics.nBands = renderConfig.roomAcoustics.nBands;
4658 3190 : hRenderConfig->roomAcoustics.acousticPreDelay = renderConfig.roomAcoustics.acousticPreDelay;
4659 3190 : hRenderConfig->roomAcoustics.inputPreDelay = renderConfig.roomAcoustics.inputPreDelay;
4660 3190 : mvr2r( renderConfig.roomAcoustics.pFc_input, hRenderConfig->roomAcoustics.pFc_input, CLDFB_NO_CHANNELS_MAX );
4661 3190 : mvr2r( renderConfig.roomAcoustics.pAcoustic_rt60, hRenderConfig->roomAcoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX );
4662 3190 : mvr2r( renderConfig.roomAcoustics.pAcoustic_dsr, hRenderConfig->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX );
4663 3190 : mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 * MAX_NUM_OBJECTS );
4664 3190 : mvr2r( renderConfig.distAtt, hRenderConfig->distAtt, 3 );
4665 :
4666 3190 : hRenderConfig->roomAcoustics.use_er = 0;
4667 3190 : if ( renderConfig.roomAcoustics.use_er == 1 )
4668 : {
4669 1686 : hRenderConfig->roomAcoustics.use_er = renderConfig.roomAcoustics.use_er;
4670 1686 : hRenderConfig->roomAcoustics.lowComplexity = renderConfig.roomAcoustics.lowComplexity;
4671 1686 : hRenderConfig->roomAcoustics.dimensions = renderConfig.roomAcoustics.dimensions;
4672 1686 : hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.roomAcoustics.ListenerOrigin;
4673 :
4674 1686 : mvr2r( renderConfig.roomAcoustics.AbsCoeff, hRenderConfig->roomAcoustics.AbsCoeff, IVAS_ROOM_ABS_COEFF );
4675 : }
4676 :
4677 : /* Re-initialize reverb instance if already available */
4678 : /* ISM inputs */
4679 15950 : for ( i = 0, pIsmInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pIsmInput )
4680 : {
4681 12760 : if ( pIsmInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4682 : {
4683 : /* Skip inactive inputs */
4684 9760 : continue;
4685 : }
4686 3000 : if ( pIsmInput->hReverb != NULL )
4687 : {
4688 3000 : if ( ( error = ivas_reverb_open( &pIsmInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK )
4689 : {
4690 0 : return error;
4691 : }
4692 : }
4693 3000 : if ( pIsmInput->crendWrapper != NULL && pIsmInput->crendWrapper->hCrend[0] != NULL )
4694 : {
4695 0 : if ( ( error = ivas_reverb_open( &pIsmInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK )
4696 : {
4697 0 : return error;
4698 : }
4699 : }
4700 : }
4701 :
4702 : /* MASA inputs */
4703 6380 : for ( i = 0, pMasaInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pMasaInput )
4704 : {
4705 3190 : if ( pMasaInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4706 : {
4707 : /* Skip inactive inputs */
4708 3040 : continue;
4709 : }
4710 :
4711 150 : if ( pMasaInput->hMasaExtRend != NULL )
4712 : {
4713 150 : if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
4714 : {
4715 150 : ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
4716 :
4717 150 : if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb,
4718 : hIvasRend->hHrtfs.hHrtfStatistics,
4719 150 : pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands,
4720 : CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
4721 150 : &( hRenderConfig->roomAcoustics ),
4722 150 : *pMasaInput->base.ctx.pOutSampleRate,
4723 : NULL,
4724 : NULL,
4725 : NULL ) ) != IVAS_ERR_OK )
4726 : {
4727 0 : return error;
4728 : }
4729 : }
4730 :
4731 150 : if ( pMasaInput->hMasaExtRend->hReverb != NULL )
4732 : {
4733 0 : ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hReverb );
4734 :
4735 0 : if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb,
4736 : hIvasRend->hHrtfs.hHrtfStatistics,
4737 0 : pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands,
4738 : CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
4739 0 : &( hRenderConfig->roomAcoustics ),
4740 0 : *pMasaInput->base.ctx.pOutSampleRate,
4741 : NULL,
4742 : NULL,
4743 : NULL ) ) != IVAS_ERR_OK )
4744 : {
4745 0 : return error;
4746 : }
4747 : }
4748 : }
4749 : }
4750 :
4751 : /* Multi-channel inputs */
4752 6380 : for ( i = 0, pMcInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pMcInput )
4753 : {
4754 3190 : if ( pMcInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4755 : {
4756 : /* Skip inactive inputs */
4757 3094 : continue;
4758 : }
4759 :
4760 96 : if ( pMcInput->hReverb != NULL )
4761 : {
4762 0 : if ( ( error = ivas_reverb_open( &pMcInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK )
4763 : {
4764 0 : return error;
4765 : }
4766 : }
4767 :
4768 96 : if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
4769 : {
4770 96 : if ( ( error = ivas_reverb_open( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK )
4771 : {
4772 0 : return error;
4773 : }
4774 : }
4775 : }
4776 :
4777 : /* SBA inputs */
4778 6380 : for ( i = 0, pSbaInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pSbaInput )
4779 : {
4780 3190 : if ( pSbaInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4781 : {
4782 : /* Skip inactive inputs */
4783 2290 : continue;
4784 : }
4785 :
4786 900 : if ( pSbaInput->crendWrapper != NULL && pSbaInput->crendWrapper->hCrend[0] != NULL && pSbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
4787 : {
4788 900 : if ( ( error = ivas_reverb_open( &pSbaInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pSbaInput->base.ctx.pOutSampleRate ) ) != IVAS_ERR_OK )
4789 : {
4790 0 : return error;
4791 : }
4792 : }
4793 : }
4794 :
4795 3190 : hRenderConfig->split_rend_config = renderConfig.split_rend_config;
4796 : /* Overwrite any pose correction settings if 0 DOF (no pose correction) was selected */
4797 3190 : if ( hRenderConfig->split_rend_config.dof == 0 )
4798 : {
4799 144 : hRenderConfig->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
4800 : }
4801 :
4802 3190 : hRenderConfig->split_rend_config.codec = renderConfig.split_rend_config.codec;
4803 :
4804 3190 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
4805 : {
4806 472 : if ( ( error = isar_split_rend_validate_config( &hRenderConfig->split_rend_config, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0 ) ) != IVAS_ERR_OK )
4807 : {
4808 0 : return error;
4809 : }
4810 : }
4811 :
4812 : /* Must re-initialize split rendering config in case renderer config is updated after adding renderer inputs */
4813 : /* if its not initialized yet then no need to re-initialize, initialization will happen while adding inputs*/
4814 3190 : if ( hIvasRend->splitRendEncBuffer.data != NULL && hIvasRend->hRendererConfig != NULL )
4815 : {
4816 : int16_t cldfb_in_flag;
4817 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
4818 :
4819 0 : if ( hIvasRend->splitRendWrapper != NULL )
4820 : {
4821 0 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
4822 0 : free( hIvasRend->splitRendWrapper );
4823 0 : hIvasRend->splitRendWrapper = NULL;
4824 : }
4825 :
4826 0 : if ( ( error = isar_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 )
4827 : {
4828 0 : return error;
4829 : }
4830 : }
4831 :
4832 3190 : return IVAS_ERR_OK;
4833 : }
4834 :
4835 :
4836 : /*-------------------------------------------------------------------*
4837 : * IVAS_REND_SetHeadRotation()
4838 : *
4839 : *
4840 : *-------------------------------------------------------------------*/
4841 :
4842 2335424 : ivas_error IVAS_REND_SetHeadRotation(
4843 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4844 : const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */
4845 : const IVAS_VECTOR3 Pos, /* i : listener positions for next rendering call */
4846 : const ISAR_SPLIT_REND_ROT_AXIS rot_axis, /* i : external control for rotation axis for split rendering */
4847 : const int16_t sf_idx /* i : subframe index */
4848 : )
4849 : {
4850 : int16_t i;
4851 : IVAS_QUATERNION rotQuat;
4852 : ivas_error error;
4853 :
4854 : /* Validate function arguments */
4855 2335424 : if ( hIvasRend == NULL )
4856 : {
4857 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4858 : }
4859 :
4860 2335424 : if ( getAudioConfigType( hIvasRend->outputConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
4861 : {
4862 : /* Head rotation can be set only with binaural output */
4863 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
4864 : }
4865 :
4866 2335424 : hIvasRend->headRotData.headRotEnabled = 1;
4867 :
4868 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
4869 4670848 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
4870 : {
4871 2335424 : if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
4872 : {
4873 320647 : if ( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i],
4874 : hIvasRend->inputsMc[i].base.inConfig,
4875 : hIvasRend->outputConfig,
4876 : hIvasRend->hRendererConfig,
4877 : hIvasRend->hHrtfs.hHrtfCrend,
4878 : hIvasRend->hHrtfs.hHrtfStatistics,
4879 : TRUE ) ) != IVAS_ERR_OK )
4880 : {
4881 0 : return error;
4882 : }
4883 : }
4884 : }
4885 :
4886 : /* check for Euler angle signaling */
4887 2335424 : if ( headRot.w == -3.0f )
4888 : {
4889 214652 : Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat );
4890 : }
4891 : else
4892 : {
4893 2120772 : rotQuat = headRot;
4894 : }
4895 :
4896 2335424 : if ( ( error = ivas_orient_trk_Process( hIvasRend->headRotData.hOrientationTracker, rotQuat, FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES, &hIvasRend->headRotData.headPositions[sf_idx] ) ) != IVAS_ERR_OK )
4897 : {
4898 0 : return error;
4899 : }
4900 :
4901 2335424 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
4902 :
4903 2335424 : hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
4904 :
4905 2335424 : return IVAS_ERR_OK;
4906 : }
4907 :
4908 :
4909 : /*-------------------------------------------------------------------*
4910 : * IVAS_REND_DisableHeadRotation()
4911 : *
4912 : *
4913 : *-------------------------------------------------------------------*/
4914 :
4915 7427389 : ivas_error IVAS_REND_DisableHeadRotation(
4916 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
4917 : )
4918 : {
4919 : int16_t i;
4920 : ivas_error error;
4921 :
4922 : /* Validate function arguments */
4923 7427389 : if ( hIvasRend == NULL )
4924 : {
4925 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4926 : }
4927 :
4928 7427389 : hIvasRend->headRotData.headRotEnabled = 0;
4929 :
4930 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
4931 7427389 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
4932 : {
4933 4961304 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
4934 : {
4935 2480652 : if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
4936 : {
4937 238086 : if ( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i],
4938 : hIvasRend->inputsMc[i].base.inConfig,
4939 : hIvasRend->outputConfig,
4940 : hIvasRend->hRendererConfig,
4941 : hIvasRend->hHrtfs.hHrtfCrend,
4942 : hIvasRend->hHrtfs.hHrtfStatistics,
4943 : TRUE ) ) != IVAS_ERR_OK )
4944 : {
4945 0 : return error;
4946 : }
4947 : }
4948 : }
4949 : }
4950 :
4951 7427389 : return IVAS_ERR_OK;
4952 : }
4953 :
4954 :
4955 : /*-------------------------------------------------------------------*
4956 : * IVAS_REND_SetSplitRendBFI()
4957 : *
4958 : *
4959 : *-------------------------------------------------------------------*/
4960 :
4961 0 : ivas_error IVAS_REND_SetSplitRendBFI(
4962 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4963 : const int16_t bfi /* i : bad frame indicator */
4964 : )
4965 : {
4966 0 : hIvasRend->splitRendBFI = bfi;
4967 :
4968 0 : return IVAS_ERR_OK;
4969 : }
4970 :
4971 :
4972 : /*-------------------------------------------------------------------*
4973 : * IVAS_REND_SetOrientationTrackingMode()
4974 : *
4975 : *
4976 : *-------------------------------------------------------------------*/
4977 :
4978 10354 : ivas_error IVAS_REND_SetOrientationTrackingMode(
4979 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
4980 : const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i : Head orientation tracking type */
4981 : )
4982 : {
4983 10354 : if ( hIvasRend->headRotData.headRotEnabled == 0 )
4984 : {
4985 8388 : return IVAS_ERR_OK;
4986 : }
4987 :
4988 1966 : return ivas_orient_trk_SetTrackingType( hIvasRend->headRotData.hOrientationTracker, orientation_tracking );
4989 : }
4990 :
4991 :
4992 : /*-------------------------------------------------------------------*
4993 : * IVAS_REND_SetReferenceRotation()
4994 : *
4995 : *
4996 : *-------------------------------------------------------------------*/
4997 :
4998 1080 : ivas_error IVAS_REND_SetReferenceRotation(
4999 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5000 : const IVAS_QUATERNION refRot /* i : Reference rotation */
5001 : )
5002 : {
5003 : ivas_error error;
5004 :
5005 : /* Validate function arguments */
5006 1080 : if ( hIvasRend == NULL )
5007 : {
5008 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5009 : }
5010 :
5011 1080 : if ( ( error = ivas_orient_trk_SetReferenceRotation( hIvasRend->headRotData.hOrientationTracker, refRot ) ) != IVAS_ERR_OK )
5012 : {
5013 0 : return error;
5014 : }
5015 :
5016 1080 : return IVAS_ERR_OK;
5017 : }
5018 :
5019 :
5020 : /*-------------------------------------------------------------------*
5021 : * IVAS_REND_GetMainOrientation()
5022 : *
5023 : *
5024 : *-------------------------------------------------------------------*/
5025 : // ToDo: not used
5026 0 : ivas_error IVAS_REND_GetMainOrientation(
5027 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5028 : IVAS_QUATERNION *pOrientation /* i/o: Quaternion pointer for main orientation */
5029 : )
5030 : {
5031 : ivas_error error;
5032 :
5033 0 : if ( hIvasRend == NULL || pOrientation == NULL )
5034 : {
5035 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5036 : }
5037 :
5038 0 : if ( ( error = ivas_orient_trk_GetMainOrientation( hIvasRend->headRotData.hOrientationTracker, pOrientation ) ) != IVAS_ERR_OK )
5039 : {
5040 0 : return error;
5041 : }
5042 :
5043 0 : return IVAS_ERR_OK;
5044 : }
5045 :
5046 :
5047 : /*-------------------------------------------------------------------*
5048 : * IVAS_REND_GetTrackedRotation()
5049 : *
5050 : *
5051 : *-------------------------------------------------------------------*/
5052 : // ToDo: not used
5053 0 : ivas_error IVAS_REND_GetTrackedRotation(
5054 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5055 : IVAS_QUATERNION *pRotation /* i/o: Quaternion pointer processed rotation */
5056 : )
5057 : {
5058 : ivas_error error;
5059 :
5060 0 : if ( hIvasRend == NULL || pRotation == NULL )
5061 : {
5062 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5063 : }
5064 :
5065 0 : if ( ( error = ivas_orient_trk_GetTrackedRotation( hIvasRend->headRotData.hOrientationTracker, pRotation ) ) != IVAS_ERR_OK )
5066 : {
5067 0 : return error;
5068 : }
5069 :
5070 0 : return IVAS_ERR_OK;
5071 : }
5072 :
5073 :
5074 : /*---------------------------------------------------------------------*
5075 : * IVAS_REND_SetReferenceVector( )
5076 : *
5077 : * Sets a reference vector spanning from listenerPos to refPos. Only
5078 : * available in OTR_TRACKING_REF_VEC and OTR_TRACKING_REF_VEC_LEV modes.
5079 : *---------------------------------------------------------------------*/
5080 :
5081 4860 : ivas_error IVAS_REND_SetReferenceVector(
5082 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5083 : const IVAS_VECTOR3 listenerPos, /* i : Listener position */
5084 : const IVAS_VECTOR3 refPos /* i : Reference position */
5085 : )
5086 : {
5087 4860 : if ( hIvasRend == NULL || hIvasRend->headRotData.hOrientationTracker == NULL )
5088 : {
5089 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5090 : }
5091 :
5092 4860 : return ivas_orient_trk_SetReferenceVector( hIvasRend->headRotData.hOrientationTracker, listenerPos, refPos );
5093 : }
5094 :
5095 :
5096 : /*---------------------------------------------------------------------*
5097 : * IVAS_REND_SetExternalOrientation()
5098 : *
5099 : *
5100 : *---------------------------------------------------------------------*/
5101 :
5102 0 : ivas_error IVAS_REND_SetExternalOrientation(
5103 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5104 : IVAS_QUATERNION *orientation, /* i : external orientation data */
5105 : int8_t enableHeadRotation, /* i : flag to enable head rotation for this frame */
5106 : int8_t enableExternalOrientation, /* i : flag to enable external orientation for this frame */
5107 : int8_t enableRotationInterpolation, /* i : flag to interpolate rotations from current and previous frames */
5108 : int16_t numFramesToTargetOrientation, /* i : number of frames until target orientation is reached */
5109 : const int16_t sf_idx /* i : subframe index */
5110 : )
5111 : {
5112 : /* Validate function arguments */
5113 0 : if ( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL )
5114 : {
5115 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5116 : }
5117 :
5118 0 : if ( orientation == NULL )
5119 : {
5120 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = 0;
5121 : }
5122 : else
5123 : {
5124 0 : QuaternionInverse( *orientation, &hIvasRend->hExternalOrientationData->Quaternions[sf_idx] );
5125 :
5126 0 : hIvasRend->hExternalOrientationData->enableHeadRotation[sf_idx] = enableHeadRotation;
5127 0 : hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = enableExternalOrientation;
5128 0 : hIvasRend->hExternalOrientationData->enableRotationInterpolation[sf_idx] = enableRotationInterpolation;
5129 0 : hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[sf_idx] = numFramesToTargetOrientation;
5130 : }
5131 :
5132 0 : return IVAS_ERR_OK;
5133 : }
5134 :
5135 :
5136 : /*---------------------------------------------------------------------*
5137 : * IVAS_REND_CombineHeadAndExternalOrientation()
5138 : *
5139 : *
5140 : *---------------------------------------------------------------------*/
5141 :
5142 8806803 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
5143 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
5144 : )
5145 : {
5146 8806803 : if ( hIvasRend == NULL )
5147 : {
5148 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5149 : }
5150 :
5151 8806803 : return combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
5152 : }
5153 :
5154 :
5155 : /*---------------------------------------------------------------------*
5156 : * IVAS_REND_GetCombinedOrientation()
5157 : *
5158 : *
5159 : *---------------------------------------------------------------------*/
5160 : // ToDo: not used
5161 0 : ivas_error IVAS_REND_GetCombinedOrientation(
5162 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5163 : IVAS_QUATERNION *pOrientation /* i/o: Quaternion pointer processed orientation */
5164 : )
5165 : {
5166 : int16_t i;
5167 :
5168 0 : if ( hIvasRend == NULL || pOrientation == NULL )
5169 : {
5170 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5171 : }
5172 :
5173 0 : if ( hIvasRend->hCombinedOrientationData != NULL )
5174 : {
5175 0 : for ( i = 0; i < hIvasRend->hCombinedOrientationData->num_subframes; ++i )
5176 : {
5177 0 : pOrientation[i] = hIvasRend->hCombinedOrientationData->Quaternions[i];
5178 : }
5179 : }
5180 :
5181 0 : return IVAS_ERR_OK;
5182 : }
5183 :
5184 : /*---------------------------------------------------------------------*
5185 : * IVAS_REND_GetCombinedOrientation()
5186 : *
5187 : *
5188 : *---------------------------------------------------------------------*/
5189 0 : ivas_error IVAS_REND_GetReverbRoomSize(
5190 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5191 : IVAS_ROOM_SIZE_T *reverbRoomSize /* o : Reverb room size */
5192 : )
5193 : {
5194 0 : switch ( hIvasRend->selectedRoomReverbSize )
5195 : {
5196 0 : case DEFAULT_REVERB_SMALL:
5197 0 : *reverbRoomSize = IVAS_ROOM_SIZE_SMALL;
5198 0 : break;
5199 0 : case DEFAULT_REVERB_MEDIUM:
5200 0 : *reverbRoomSize = IVAS_ROOM_SIZE_MEDIUM;
5201 0 : break;
5202 0 : case DEFAULT_REVERB_LARGE:
5203 0 : *reverbRoomSize = IVAS_ROOM_SIZE_LARGE;
5204 0 : break;
5205 0 : case DEFAULT_REVERB_UNSET:
5206 : default:
5207 0 : *reverbRoomSize = IVAS_ROOM_SIZE_AUTO;
5208 0 : break;
5209 : }
5210 :
5211 0 : return IVAS_ERR_OK;
5212 : }
5213 :
5214 : /*---------------------------------------------------------------------*
5215 : * IVAS_REND_GetCombinedOrientation()
5216 : *
5217 : *
5218 : *---------------------------------------------------------------------*/
5219 10354 : ivas_error IVAS_REND_SetReverbRoomSize(
5220 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
5221 : const IVAS_ROOM_SIZE_T reverbRoomSize /* i : Reverb room size */
5222 : )
5223 : {
5224 : ivas_error error;
5225 :
5226 10354 : switch ( reverbRoomSize )
5227 : {
5228 1534 : case IVAS_ROOM_SIZE_SMALL:
5229 1534 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_SMALL;
5230 1534 : break;
5231 2594 : case IVAS_ROOM_SIZE_MEDIUM:
5232 2594 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_MEDIUM;
5233 2594 : break;
5234 6226 : case IVAS_ROOM_SIZE_LARGE:
5235 6226 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_LARGE;
5236 6226 : break;
5237 0 : case IVAS_ROOM_SIZE_AUTO:
5238 : default:
5239 0 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_UNSET;
5240 0 : break; /* will be setup in IVAS_REND_AddInput() */
5241 : }
5242 :
5243 10354 : if ( hIvasRend->hRendererConfig != NULL )
5244 : {
5245 4540 : if ( ( error = ivas_render_config_change_defaults( hIvasRend->hRendererConfig, hIvasRend->selectedRoomReverbSize ) ) != IVAS_ERR_OK )
5246 : {
5247 0 : return error;
5248 : }
5249 : }
5250 : else
5251 : {
5252 5814 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5253 : }
5254 :
5255 4540 : return IVAS_ERR_OK;
5256 : }
5257 :
5258 :
5259 : /*-------------------------------------------------------------------*
5260 : * Local functions
5261 : *-------------------------------------------------------------------*/
5262 :
5263 : /* Take one channel from input buffer and copy it to each channel
5264 : in output buffer, with different gain applied per output channel.
5265 : This function takes 2 gain vectors - one for the beginning and one
5266 : for the end of the buffer. Gain values are lineraly interpolated
5267 : for all samples in between. */
5268 47092353 : static void renderBufferChannelLerp(
5269 : const IVAS_REND_AudioBuffer inAudio,
5270 : const int32_t inChannelIdx,
5271 : const float *const gainsCurrent,
5272 : const float *const gainsPrev,
5273 : IVAS_REND_AudioBuffer outAudio )
5274 : {
5275 : const float *inSmpl;
5276 : float *outSmpl;
5277 : float fadeIn;
5278 : float fadeOut;
5279 : int32_t i;
5280 : const float *lastInSmpl;
5281 : int16_t outChnlIdx;
5282 : float currentGain;
5283 : float previousGain;
5284 :
5285 : /* Pointer to behind last input sample */
5286 47092353 : lastInSmpl = getSmplPtr( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
5287 :
5288 447903651 : for ( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
5289 : {
5290 400811298 : currentGain = gainsCurrent[outChnlIdx];
5291 400811298 : previousGain = gainsPrev == NULL ? 0.f : gainsPrev[outChnlIdx];
5292 :
5293 : /* Process current output channel only if applying non-zero gains */
5294 400811298 : if ( fabsf( currentGain ) > EPSILON || ( gainsPrev != NULL && fabsf( previousGain ) > EPSILON ) )
5295 : {
5296 : /* Reset input pointer to the beginning of input channel */
5297 230920396 : inSmpl = getSmplPtr( inAudio, inChannelIdx, 0 );
5298 :
5299 : /* Set output pointer to first output channel sample */
5300 230920396 : outSmpl = getSmplPtr( outAudio, outChnlIdx, 0 );
5301 :
5302 230920396 : if ( gainsPrev == NULL || fabsf( previousGain - currentGain ) <= EPSILON )
5303 : {
5304 : /* If no interpolation from previous frame, apply current gain */
5305 : do
5306 : {
5307 62737943120 : *outSmpl += currentGain * ( *inSmpl );
5308 62737943120 : ++outSmpl;
5309 62737943120 : ++inSmpl;
5310 :
5311 62737943120 : } while ( inSmpl != lastInSmpl );
5312 : }
5313 : else
5314 : {
5315 8754690 : i = 0;
5316 :
5317 : /* Otherwise use weighted average between previous and current gain */
5318 : do
5319 : {
5320 3667391040 : fadeIn = (float) i / ( outAudio.config.numSamplesPerChannel - 1 );
5321 3667391040 : fadeOut = 1.0f - fadeIn;
5322 :
5323 3667391040 : *outSmpl += ( fadeIn * currentGain + fadeOut * previousGain ) * ( *inSmpl );
5324 3667391040 : ++outSmpl;
5325 3667391040 : ++inSmpl;
5326 3667391040 : ++i;
5327 3667391040 : } while ( inSmpl != lastInSmpl );
5328 : }
5329 : }
5330 : }
5331 :
5332 47092353 : return;
5333 : }
5334 :
5335 :
5336 : /* Take one channel from input buffer and copy it to each channel
5337 : in output buffer, with different gain applied per output channel */
5338 36943573 : static void renderBufferChannel(
5339 : const IVAS_REND_AudioBuffer inAudio,
5340 : const int32_t inChannelIdx,
5341 : const float *const outputGains,
5342 : IVAS_REND_AudioBuffer outAudio )
5343 : {
5344 36943573 : renderBufferChannelLerp( inAudio, inChannelIdx, outputGains, NULL, outAudio );
5345 :
5346 36943573 : return;
5347 : }
5348 :
5349 :
5350 972532 : static ivas_error chooseCrossfade(
5351 : const IVAS_REND_HeadRotData *headRotData,
5352 : const float **pCrossfade )
5353 : {
5354 972532 : *pCrossfade = headRotData->crossfade;
5355 :
5356 972532 : return IVAS_ERR_OK;
5357 : }
5358 :
5359 111946 : static ivas_error rotateFrameMc(
5360 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
5361 : AUDIO_CONFIG inConfig, /* i : Input Audio config */
5362 : const LSSETUP_CUSTOM_STRUCT *pInCustomLs, /* i : Input Custom LS setup */
5363 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
5364 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
5365 : rotation_gains gains_prev, /* i/o: Previous frame rotation gains */
5366 : const EFAP_HANDLE hEFAPdata, /* i : EFAP structure */
5367 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
5368 : )
5369 : {
5370 : int16_t i;
5371 : int16_t j;
5372 : const float *crossfade;
5373 : int16_t num_subframes;
5374 : int16_t subframe_idx, subframe_len;
5375 : int16_t azimuth, elevation;
5376 : int16_t is_planar_setup, lfe_idx;
5377 : int16_t nchan;
5378 : int16_t ch_in, ch_out;
5379 : int16_t ch_in_woLFE, ch_out_woLFE;
5380 : float *readPtr, *writePtr;
5381 : const float *ls_azimuth, *ls_elevation;
5382 : rotation_matrix Rmat;
5383 : rotation_gains gains;
5384 : float tmp_gains[MAX_INPUT_CHANNELS];
5385 : ivas_error error;
5386 :
5387 111946 : push_wmops( "rotateFrameMc" );
5388 111946 : if ( ( error = chooseCrossfade( headRotData, &crossfade ) ) != IVAS_ERR_OK )
5389 : {
5390 0 : return error;
5391 : }
5392 111946 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
5393 :
5394 111946 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
5395 : {
5396 67462 : if ( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ) != IVAS_ERR_OK )
5397 : {
5398 0 : return error;
5399 : }
5400 : }
5401 : else
5402 : {
5403 44484 : nchan = pInCustomLs->num_spk + pInCustomLs->num_lfe;
5404 : }
5405 :
5406 111946 : if ( ( error = getMcConfigValues( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ) != IVAS_ERR_OK )
5407 : {
5408 0 : return error;
5409 : }
5410 :
5411 : /* initialize gains to passthrough */
5412 1378814 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
5413 : {
5414 1266868 : set_zero( gains[ch_in], nchan );
5415 1266868 : gains[ch_in][ch_in] = 1.f;
5416 : }
5417 :
5418 : /* subframe loop */
5419 :
5420 111946 : subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
5421 323180 : for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5422 : {
5423 844936 : for ( i = 0; i < 3; i++ )
5424 : {
5425 633702 : if ( hCombinedOrientationData != NULL )
5426 : {
5427 2534808 : for ( j = 0; j < 3; j++ )
5428 : {
5429 1901106 : Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j];
5430 : }
5431 : }
5432 : else
5433 : {
5434 : /* Set to identity */
5435 0 : set_zero( Rmat[i], 3 );
5436 0 : Rmat[i][i] = 1.0f;
5437 : }
5438 : }
5439 :
5440 2631506 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
5441 : {
5442 : /* skip LFE */
5443 2420272 : if ( ch_in == lfe_idx )
5444 : {
5445 139984 : continue;
5446 : }
5447 :
5448 : /* input channel index without LFE */
5449 2280288 : ch_in_woLFE = ( ( lfe_idx > 0 ) && ( ch_in >= lfe_idx ) ) ? ch_in - 1 : ch_in;
5450 :
5451 : /* gains for current subframe rotation */
5452 2280288 : rotateAziEle( ls_azimuth[ch_in_woLFE], ls_elevation[ch_in_woLFE], &azimuth, &elevation, Rmat, is_planar_setup );
5453 :
5454 2280288 : if ( hEFAPdata != NULL && ( ls_azimuth[ch_in_woLFE] != azimuth || ls_elevation[ch_in_woLFE] != elevation ) )
5455 : {
5456 1243879 : efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP );
5457 :
5458 14483727 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
5459 : {
5460 : /* skip LFE */
5461 13239848 : if ( ch_out == lfe_idx )
5462 : {
5463 1243879 : continue;
5464 : }
5465 :
5466 : /* output channel index without LFE */
5467 11995969 : ch_out_woLFE = ( ( lfe_idx > 0 ) && ( ch_out >= lfe_idx ) ) ? ch_out - 1 : ch_out;
5468 :
5469 11995969 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE];
5470 : }
5471 : }
5472 : }
5473 :
5474 : /* apply panning gains by mtx multiplication */
5475 2631506 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
5476 : {
5477 32423088 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
5478 : {
5479 30002816 : writePtr = getSmplPtr( outAudio, ch_out, subframe_idx * subframe_len );
5480 30002816 : readPtr = getSmplPtr( inAudio, ch_in, subframe_idx * subframe_len );
5481 : /* crossfade with previous rotation gains */
5482 5543997056 : for ( i = 0; i < subframe_len; i++ )
5483 : {
5484 5513994240 : *writePtr++ +=
5485 5513994240 : ( *readPtr ) * ( ( 1 - crossfade[i] ) * gains_prev[ch_in][ch_out] ) +
5486 5513994240 : ( *readPtr ) * ( crossfade[i] * gains[ch_in][ch_out] );
5487 5513994240 : readPtr++;
5488 : }
5489 : }
5490 : }
5491 :
5492 : /* move gains to gains_prev */
5493 2631506 : for ( i = 0; i < nchan; i++ )
5494 : {
5495 2420272 : mvr2r( gains[i], gains_prev[i], nchan );
5496 : }
5497 : }
5498 :
5499 111946 : pop_wmops();
5500 111946 : return IVAS_ERR_OK;
5501 : }
5502 :
5503 :
5504 860586 : static ivas_error rotateFrameSba(
5505 : IVAS_REND_AudioBuffer inAudio, /* i : Input Audio buffer */
5506 : const AUDIO_CONFIG inConfig, /* i : Input Audio config */
5507 : const IVAS_REND_HeadRotData *headRotData, /* i : Head rotation data */
5508 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i : Combined head and external orientations */
5509 : rotation_gains gains_prev, /* i/o: Previous frame rotation gains */
5510 : IVAS_REND_AudioBuffer outAudio /* o : Output Audio buffer */
5511 : )
5512 : {
5513 : int16_t i, l, n, m;
5514 : int16_t m1, m2;
5515 : int16_t shd_rot_max_order;
5516 : const float *crossfade;
5517 : int16_t num_subframes;
5518 : int16_t subframe_idx, subframe_len;
5519 :
5520 : float *writePtr;
5521 : rotation_matrix Rmat;
5522 : float tmpRot[2 * HEADROT_ORDER + 1];
5523 : rotation_gains gains;
5524 : ivas_error error;
5525 : int16_t idx;
5526 : float val, cf, oneminuscf;
5527 :
5528 860586 : push_wmops( "rotateFrameSba" );
5529 :
5530 860586 : if ( ( error = chooseCrossfade( headRotData, &crossfade ) ) != IVAS_ERR_OK )
5531 : {
5532 0 : return error;
5533 : }
5534 860586 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
5535 :
5536 860586 : if ( ( error = getAmbisonicsOrder( inConfig, &shd_rot_max_order ) ) != IVAS_ERR_OK )
5537 : {
5538 0 : return error;
5539 : }
5540 :
5541 860586 : subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
5542 2506431 : for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5543 : {
5544 : /* initialize rotation matrices with zeros */
5545 27979365 : for ( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5546 : {
5547 26333520 : set_zero( gains[i], HEADROT_SHMAT_DIM );
5548 : }
5549 :
5550 6583380 : for ( i = 0; i < 3; i++ )
5551 : {
5552 4937535 : if ( hCombinedOrientationData != NULL )
5553 : {
5554 19750140 : for ( l = 0; l < 3; l++ )
5555 : {
5556 14812605 : Rmat[i][l] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][l];
5557 : }
5558 : }
5559 : else
5560 : {
5561 : /* Set to identity */
5562 0 : set_zero( Rmat[i], 3 );
5563 0 : Rmat[i][i] = 1.0f;
5564 : }
5565 : }
5566 :
5567 : /* calculate ambisonics rotation matrices for the previous and current frames */
5568 1645845 : SHrotmatgen( gains, Rmat, shd_rot_max_order );
5569 :
5570 304902645 : for ( i = 0; i < subframe_len; i++ )
5571 : {
5572 303256800 : idx = subframe_idx * subframe_len + i;
5573 303256800 : cf = crossfade[i];
5574 303256800 : oneminuscf = 1 - cf;
5575 : /* As the rotation matrix becomes block diagonal in a SH basis, we can*/
5576 : /* apply each angular-momentum block individually to save complexity. */
5577 :
5578 : /* loop over l blocks */
5579 303256800 : m1 = 1;
5580 303256800 : m2 = 4;
5581 936427680 : for ( l = 1; l <= shd_rot_max_order; l++ )
5582 : {
5583 : /* compute mtx-vector product for this l */
5584 3459179520 : for ( n = m1; n < m2; n++ )
5585 : {
5586 2826008640 : tmpRot[n - m1] = 0.f;
5587 :
5588 17003185920 : for ( m = m1; m < m2; m++ )
5589 : {
5590 14177177280 : val = inAudio.data[m * inAudio.config.numSamplesPerChannel + idx];
5591 : /* crossfade with previous rotation gains */
5592 14177177280 : tmpRot[n - m1] += ( cf * gains[n][m] * val + oneminuscf * gains_prev[n][m] * val );
5593 : }
5594 : }
5595 : /* write back the result */
5596 3459179520 : for ( n = m1; n < m2; n++ )
5597 : {
5598 2826008640 : writePtr = getSmplPtr( outAudio, n, idx );
5599 2826008640 : ( *writePtr ) = tmpRot[n - m1];
5600 : }
5601 633170880 : m1 = m2;
5602 633170880 : m2 += 2 * ( l + 1 ) + 1;
5603 : }
5604 : }
5605 :
5606 : /* move SHrotmat to SHrotmat_prev */
5607 27979365 : for ( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5608 : {
5609 26333520 : mvr2r( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
5610 : }
5611 : }
5612 :
5613 860586 : pop_wmops();
5614 :
5615 860586 : return IVAS_ERR_OK;
5616 : }
5617 :
5618 :
5619 1599620 : static ivas_error renderIsmToBinaural(
5620 : const input_ism *ismInput,
5621 : IVAS_REND_AudioBuffer outAudio )
5622 : {
5623 : float tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5624 : ivas_error error;
5625 : int16_t ism_md_subframe_update_ext;
5626 :
5627 1599620 : push_wmops( "renderIsmToBinaural" );
5628 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5629 1599620 : ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS );
5630 :
5631 1599620 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpTDRendBuffer );
5632 :
5633 1599620 : if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext,
5634 1599620 : *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer ) ) != IVAS_ERR_OK )
5635 : {
5636 0 : return error;
5637 : }
5638 :
5639 1599620 : accumulate2dArrayToBuffer( tmpTDRendBuffer, &outAudio );
5640 :
5641 1599620 : pop_wmops();
5642 :
5643 1599620 : return IVAS_ERR_OK;
5644 : }
5645 :
5646 :
5647 1248 : static int16_t getNumSubframesInBuffer(
5648 : const IVAS_REND_AudioBuffer *buffer,
5649 : const int32_t sampleRate )
5650 : {
5651 : int16_t cldfb2tdSampleFact;
5652 :
5653 1248 : cldfb2tdSampleFact = buffer->config.is_cldfb ? 2 : 1;
5654 :
5655 : #ifdef DEBUGGING
5656 : assert( buffer->config.numSamplesPerChannel % ( sampleRate / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES * cldfb2tdSampleFact ) == 0 );
5657 : #endif
5658 :
5659 1248 : return (int16_t) ( buffer->config.numSamplesPerChannel / ( sampleRate / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES * cldfb2tdSampleFact ) );
5660 : }
5661 :
5662 :
5663 1599620 : static ivas_error renderIsmToBinauralRoom(
5664 : input_ism *ismInput,
5665 : IVAS_REND_AudioBuffer outAudio )
5666 : {
5667 : int16_t position_changed;
5668 : int16_t i, j;
5669 : int16_t azi_rot, ele_rot;
5670 : int16_t subframe_idx;
5671 : int16_t tmp;
5672 : rotation_matrix Rmat;
5673 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5674 : ivas_error error;
5675 : pan_vector currentPanGains;
5676 : IVAS_REND_AudioBuffer tmpMcBuffer;
5677 : IVAS_ISM_METADATA rotatedPosPrev;
5678 : IVAS_ISM_METADATA rotatedPos;
5679 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
5680 : int8_t combinedOrientationEnabled;
5681 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
5682 :
5683 27193540 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5684 : {
5685 25593920 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
5686 : }
5687 :
5688 1599620 : push_wmops( "renderIsmToBinauralRoom" );
5689 :
5690 1599620 : rotatedPosPrev = defaultObjectPosition();
5691 1599620 : rotatedPos = defaultObjectPosition();
5692 :
5693 1599620 : hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
5694 1599620 : combinedOrientationEnabled = 0;
5695 1599620 : if ( *hCombinedOrientationData != NULL )
5696 : {
5697 802220 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5698 : {
5699 :
5700 802220 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5701 : {
5702 802220 : combinedOrientationEnabled = 1;
5703 802220 : break;
5704 : }
5705 : }
5706 : }
5707 :
5708 1599620 : if ( combinedOrientationEnabled )
5709 : {
5710 1604440 : for ( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
5711 : {
5712 3208880 : for ( i = 0; i < 3; i++ )
5713 : {
5714 2406660 : if ( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
5715 : {
5716 9626640 : for ( j = 0; j < 3; j++ )
5717 : {
5718 7219980 : Rmat[i][j] = ( *hCombinedOrientationData )->Rmat[subframe_idx][i][j];
5719 : }
5720 : }
5721 : else
5722 : {
5723 : /* Set to identity */
5724 0 : set_zero( Rmat[i], 3 );
5725 0 : Rmat[i][i] = 1.0f;
5726 : }
5727 : }
5728 : }
5729 : }
5730 :
5731 : /* get previous position */
5732 1599620 : if ( combinedOrientationEnabled )
5733 : {
5734 802220 : rotateAziEle( ismInput->previousPos.azimuth, ismInput->previousPos.elevation, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
5735 802220 : rotatedPosPrev.azimuth = (float) azi_rot;
5736 802220 : rotatedPosPrev.elevation = (float) ele_rot;
5737 : }
5738 : else
5739 : {
5740 797400 : rotatedPosPrev.azimuth = ismInput->previousPos.azimuth;
5741 797400 : rotatedPosPrev.elevation = ismInput->previousPos.elevation;
5742 : }
5743 :
5744 : /* get current position */
5745 1599620 : if ( combinedOrientationEnabled )
5746 : {
5747 802220 : rotateAziEle( ismInput->currentPos.azimuth, ismInput->currentPos.elevation, &azi_rot, &ele_rot, Rmat, 0 );
5748 802220 : rotatedPos.azimuth = (float) azi_rot;
5749 802220 : rotatedPos.elevation = (float) ele_rot;
5750 : }
5751 : else
5752 : {
5753 797400 : rotatedPos.azimuth = ismInput->currentPos.azimuth;
5754 797400 : rotatedPos.elevation = ismInput->currentPos.elevation;
5755 : }
5756 :
5757 1599620 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged( &rotatedPos, &rotatedPosPrev );
5758 :
5759 : /* set previous gains if this is the first frame */
5760 1599620 : if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper, rotatedPosPrev.azimuth, rotatedPosPrev.elevation, ismInput->prev_pan_gains ) ) != IVAS_ERR_OK )
5761 : {
5762 0 : return error;
5763 : }
5764 :
5765 : /* compute gains only if position changed */
5766 1599620 : if ( position_changed )
5767 : {
5768 369796 : if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper,
5769 : rotatedPos.azimuth,
5770 : rotatedPos.elevation,
5771 : currentPanGains ) ) != IVAS_ERR_OK )
5772 : {
5773 0 : return error;
5774 : }
5775 : }
5776 :
5777 : /* intermediate rendering to 7_1_4 */
5778 1599620 : tmpMcBuffer = ismInput->base.inputBuffer;
5779 :
5780 1599620 : if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK )
5781 : {
5782 0 : return error;
5783 : }
5784 :
5785 1599620 : tmpMcBuffer.config.numChannels = tmp;
5786 1599620 : tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) );
5787 1599620 : set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels );
5788 :
5789 1599620 : renderBufferChannelLerp( ismInput->base.inputBuffer, 0,
5790 : position_changed ? currentPanGains : ismInput->prev_pan_gains,
5791 : position_changed ? ismInput->prev_pan_gains : NULL,
5792 : tmpMcBuffer );
5793 :
5794 1599620 : copyBufferTo2dArray( tmpMcBuffer, tmpRendBuffer );
5795 :
5796 : /* save gains for next frame */
5797 6398480 : for ( i = 0; i < 3; i++ )
5798 : {
5799 4798860 : mvr2r( Rmat[i], ismInput->rot_mat_prev[i], 3 );
5800 : }
5801 :
5802 1599620 : if ( position_changed )
5803 : {
5804 369796 : mvr2r( currentPanGains, ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5805 : }
5806 :
5807 : /* render 7_1_4 with BRIRs */
5808 1599620 : if ( ( error = ivas_rend_crendProcessSubframe( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR, NULL, NULL,
5809 1599620 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, ismInput->base.inputBuffer.config.numSamplesPerChannel, *ismInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
5810 : {
5811 0 : return error;
5812 : }
5813 :
5814 1599620 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
5815 :
5816 1599620 : free( tmpMcBuffer.data );
5817 1599620 : pop_wmops();
5818 :
5819 1599620 : return IVAS_ERR_OK;
5820 : }
5821 :
5822 :
5823 3991820 : static ivas_error renderIsmToBinauralReverb(
5824 : input_ism *ismInput,
5825 : IVAS_REND_AudioBuffer outAudio )
5826 : {
5827 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
5828 : ivas_error error;
5829 : int16_t ism_md_subframe_update_ext;
5830 :
5831 3991820 : push_wmops( "renderIsmToBinauralRoom" );
5832 :
5833 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5834 3991820 : ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS );
5835 :
5836 3991820 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer );
5837 :
5838 3991820 : if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb,
5839 3991820 : ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK )
5840 : {
5841 0 : return error;
5842 : }
5843 :
5844 3991820 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
5845 3991820 : pop_wmops();
5846 :
5847 3991820 : return IVAS_ERR_OK;
5848 : }
5849 :
5850 :
5851 6135216 : static ivas_error renderIsmToMc(
5852 : input_ism *ismInput,
5853 : const IVAS_REND_AudioBuffer outAudio )
5854 : {
5855 : int8_t position_changed;
5856 : pan_vector currentPanGains;
5857 : ivas_error error;
5858 :
5859 6135216 : push_wmops( "renderIsmToMc" );
5860 :
5861 6135216 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged( &ismInput->currentPos, &ismInput->previousPos );
5862 6135216 : if ( *ismInput->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_STEREO )
5863 : {
5864 828078 : if ( ismInput->nonDiegeticPan )
5865 : {
5866 23430 : ismInput->prev_pan_gains[0] = currentPanGains[0] = ( ismInput->nonDiegeticPanGain + 1.f ) * 0.5f;
5867 23430 : ismInput->prev_pan_gains[1] = currentPanGains[1] = 1.f - currentPanGains[0];
5868 : }
5869 : else
5870 : {
5871 804648 : set_zero( currentPanGains, MAX_OUTPUT_CHANNELS );
5872 :
5873 804648 : ivas_ism_get_stereo_gains( ismInput->currentPos.azimuth, ismInput->currentPos.elevation, ¤tPanGains[0], ¤tPanGains[1] );
5874 :
5875 804648 : set_zero( ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5876 :
5877 804648 : ivas_ism_get_stereo_gains( ismInput->previousPos.azimuth, ismInput->previousPos.elevation, &ismInput->prev_pan_gains[0], &ismInput->prev_pan_gains[1] );
5878 : }
5879 : }
5880 : else
5881 : {
5882 : /* compute gains only if position changed */
5883 5307138 : if ( position_changed )
5884 : {
5885 : // TODO tmu review when #215 is resolved
5886 952128 : if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper,
5887 952128 : (int16_t) floorf( ismInput->currentPos.azimuth + 0.5f ),
5888 952128 : (int16_t) floorf( ismInput->currentPos.elevation + 0.5f ),
5889 : currentPanGains ) ) != IVAS_ERR_OK )
5890 : {
5891 0 : return error;
5892 : }
5893 : }
5894 :
5895 : /* set previous gains if this is the first frame */
5896 5307138 : if ( !ismInput->firstFrameRendered )
5897 : {
5898 : // TODO tmu review when #215 is resolved
5899 5688 : if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper,
5900 5688 : (int16_t) floorf( ismInput->previousPos.azimuth + 0.5f ),
5901 5688 : (int16_t) floorf( ismInput->previousPos.elevation + 0.5f ),
5902 5688 : ismInput->prev_pan_gains ) ) != IVAS_ERR_OK )
5903 : {
5904 0 : return error;
5905 : }
5906 : }
5907 : }
5908 :
5909 : /* Assume num channels in audio buffer to be 1.
5910 : * This should have been validated in IVAS_REND_FeedInputAudio() */
5911 6135216 : renderBufferChannelLerp( ismInput->base.inputBuffer, 0,
5912 : position_changed ? currentPanGains : ismInput->prev_pan_gains,
5913 : position_changed ? ismInput->prev_pan_gains : NULL,
5914 : outAudio );
5915 :
5916 6135216 : if ( position_changed )
5917 : {
5918 1102128 : mvr2r( currentPanGains, ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5919 : }
5920 :
5921 6135216 : pop_wmops();
5922 :
5923 6135216 : return IVAS_ERR_OK;
5924 : }
5925 :
5926 :
5927 2413944 : static ivas_error renderIsmToSba(
5928 : input_ism *ismInput,
5929 : const AUDIO_CONFIG outConfig,
5930 : const IVAS_REND_AudioBuffer outAudio )
5931 : {
5932 : int8_t position_changed;
5933 : int16_t ambiOrderOut;
5934 : int16_t numOutChannels;
5935 : pan_vector currentPanGains;
5936 : ivas_error error;
5937 2413944 : error = IVAS_ERR_OK;
5938 :
5939 2413944 : push_wmops( "renderIsmToSba" );
5940 :
5941 2413944 : if ( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ) != IVAS_ERR_OK )
5942 : {
5943 0 : return error;
5944 : }
5945 :
5946 2413944 : if ( ( error = getAmbisonicsOrder( outConfig, &ambiOrderOut ) ) != IVAS_ERR_OK )
5947 : {
5948 0 : return error;
5949 : }
5950 :
5951 2413944 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged( &ismInput->currentPos, &ismInput->previousPos );
5952 :
5953 : /* set previous gains if this is the first frame */
5954 2413944 : if ( !ismInput->firstFrameRendered )
5955 : {
5956 : // TODO tmu review when #215 is resolved
5957 2304 : ivas_dirac_dec_get_response( (int16_t) floorf( ismInput->previousPos.azimuth + 0.5f ),
5958 2304 : (int16_t) floorf( ismInput->previousPos.elevation + 0.5f ),
5959 2304 : ismInput->prev_pan_gains,
5960 : ambiOrderOut );
5961 : }
5962 :
5963 : /* compute gains only if position changed */
5964 2413944 : if ( position_changed )
5965 : {
5966 : // TODO tmu review when #215 is resolved
5967 380880 : ivas_dirac_dec_get_response( (int16_t) floorf( ismInput->currentPos.azimuth + 0.5f ),
5968 380880 : (int16_t) floorf( ismInput->currentPos.elevation + 0.5f ),
5969 : currentPanGains,
5970 : ambiOrderOut );
5971 : }
5972 :
5973 : /* Assume num channels in audio buffer to be 1.
5974 : * This should have been validated in IVAS_REND_FeedInputAudio() */
5975 2413944 : renderBufferChannelLerp( ismInput->base.inputBuffer, 0,
5976 : position_changed ? currentPanGains : ismInput->prev_pan_gains,
5977 : position_changed ? ismInput->prev_pan_gains : NULL,
5978 : outAudio );
5979 :
5980 2413944 : if ( position_changed )
5981 : {
5982 380880 : mvr2r( currentPanGains, ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5983 : }
5984 2413944 : pop_wmops();
5985 :
5986 2413944 : return error;
5987 : }
5988 :
5989 :
5990 66068 : static ivas_error renderIsmToSplitBinaural(
5991 : input_ism *ismInput,
5992 : const IVAS_REND_AudioBuffer outAudio )
5993 : {
5994 : ivas_error error;
5995 : float tmpProcessing[MAX_NUM_OBJECTS][L_FRAME48k];
5996 : int16_t pos_idx;
5997 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
5998 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
5999 : IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
6000 : int16_t i, ch, slot_idx, num_bands;
6001 : float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
6002 : float tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
6003 : float tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
6004 66068 : int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
6005 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
6006 : int16_t ism_md_subframe_update_ext;
6007 :
6008 66068 : push_wmops( "renderIsmToSplitBinaural" );
6009 :
6010 66068 : pSplitRendWrapper = ismInput->base.ctx.pSplitRendWrapper;
6011 66068 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
6012 :
6013 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6014 66068 : ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS );
6015 :
6016 66068 : pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData;
6017 :
6018 66068 : if ( pMultiBinPoseData->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
6019 : {
6020 186912 : for ( i = 1; i < pCombinedOrientationData->num_subframes; ++i )
6021 : {
6022 140184 : pCombinedOrientationData->Quaternions[i] = pCombinedOrientationData->Quaternions[0];
6023 : }
6024 : }
6025 :
6026 : /* Save current head positions */
6027 330340 : for ( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6028 : {
6029 264272 : originalHeadRot[i] = pCombinedOrientationData->Quaternions[i];
6030 : }
6031 :
6032 : /* Copy input audio to a processing buffer. */
6033 66068 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing );
6034 :
6035 334520 : for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6036 : {
6037 : /* Update head positions */
6038 268452 : if ( pos_idx != 0 )
6039 : {
6040 1011920 : for ( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6041 : {
6042 809536 : if ( originalHeadRot[i].w == -3.0f )
6043 : {
6044 0 : pCombinedOrientationData->Quaternions[i].w = -3.0f;
6045 0 : pCombinedOrientationData->Quaternions[i].x = originalHeadRot[i].x + pMultiBinPoseData->relative_head_poses[pos_idx][0];
6046 0 : pCombinedOrientationData->Quaternions[i].y = originalHeadRot[i].y + pMultiBinPoseData->relative_head_poses[pos_idx][1];
6047 0 : pCombinedOrientationData->Quaternions[i].z = originalHeadRot[i].z + pMultiBinPoseData->relative_head_poses[pos_idx][2];
6048 : }
6049 : else
6050 : {
6051 809536 : pCombinedOrientationData->Quaternions[i].w = -3.0f;
6052 809536 : Quat2EulerDegree( originalHeadRot[i],
6053 809536 : &pCombinedOrientationData->Quaternions[i].z,
6054 809536 : &pCombinedOrientationData->Quaternions[i].y,
6055 809536 : &pCombinedOrientationData->Quaternions[i].x );
6056 809536 : pCombinedOrientationData->Quaternions[i].x += pMultiBinPoseData->relative_head_poses[pos_idx][0];
6057 809536 : pCombinedOrientationData->Quaternions[i].y += pMultiBinPoseData->relative_head_poses[pos_idx][1];
6058 809536 : pCombinedOrientationData->Quaternions[i].z += pMultiBinPoseData->relative_head_poses[pos_idx][2];
6059 : }
6060 : }
6061 : }
6062 :
6063 : /* Render */
6064 268452 : if ( ( error = ivas_td_binaural_renderer_ext( ( pos_idx == 0 ) ? &ismInput->tdRendWrapper : &ismInput->splitTdRendWrappers[pos_idx - 1], ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos,
6065 268452 : NULL, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, output_frame, tmpProcessing ) ) != IVAS_ERR_OK )
6066 : {
6067 0 : return error;
6068 : }
6069 :
6070 268452 : if ( outAudio.config.is_cldfb )
6071 : {
6072 : /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */
6073 73140 : num_bands = (int16_t) ( ( BINAURAL_MAXBANDS * *ismInput->base.ctx.pOutSampleRate ) / 48000 );
6074 219420 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
6075 : {
6076 2486760 : for ( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ )
6077 : {
6078 2340480 : cldfbAnalysis_ts( &tmpProcessing[ch][num_bands * slot_idx],
6079 2340480 : &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0],
6080 2340480 : &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0],
6081 : num_bands,
6082 2340480 : ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch] );
6083 : }
6084 : }
6085 : }
6086 : else
6087 : {
6088 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
6089 : * overwrite original audio, which is still needed for rendering next head pose. */
6090 195312 : mvr2r( tmpProcessing[0], tmpBinaural[BINAURAL_CHANNELS * pos_idx], output_frame );
6091 195312 : mvr2r( tmpProcessing[1], tmpBinaural[BINAURAL_CHANNELS * pos_idx + 1], output_frame );
6092 : }
6093 :
6094 : /* Overwrite processing buffer with original input audio again */
6095 268452 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing );
6096 : }
6097 :
6098 : /* Restore original head rotation */
6099 330340 : for ( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6100 : {
6101 264272 : pCombinedOrientationData->Quaternions[i] = originalHeadRot[i];
6102 : }
6103 :
6104 66068 : if ( outAudio.config.is_cldfb )
6105 : {
6106 18020 : accumulateCLDFBArrayToBuffer( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio );
6107 : }
6108 : else
6109 : {
6110 48048 : accumulate2dArrayToBuffer( tmpBinaural, &outAudio );
6111 : }
6112 66068 : pop_wmops();
6113 :
6114 : /* Encoding to split rendering bitstream done at a higher level */
6115 66068 : return IVAS_ERR_OK;
6116 : }
6117 :
6118 :
6119 27612 : static void renderIsmToMasa(
6120 : input_ism *ismInput,
6121 : IVAS_REND_AudioBuffer outAudio )
6122 : {
6123 : float tmpRendBuffer[MAX_NUM_OBJECTS][L_FRAME48k];
6124 :
6125 27612 : push_wmops( "renderIsmToMasa" );
6126 :
6127 27612 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer );
6128 :
6129 27612 : ivas_omasa_ana( ismInput->hOMasa, tmpRendBuffer, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
6130 :
6131 27612 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6132 :
6133 27612 : pop_wmops();
6134 :
6135 27612 : return;
6136 : }
6137 :
6138 :
6139 15833900 : static ivas_error renderInputIsm(
6140 : input_ism *ismInput,
6141 : const AUDIO_CONFIG outConfig,
6142 : const IVAS_REND_AudioBuffer outAudio )
6143 : {
6144 : ivas_error error;
6145 : IVAS_REND_AudioBuffer inAudio;
6146 : int16_t cldfb2tdSampleFact;
6147 :
6148 15833900 : error = IVAS_ERR_OK;
6149 15833900 : inAudio = ismInput->base.inputBuffer;
6150 :
6151 15833900 : cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
6152 15833900 : if ( ismInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel )
6153 : {
6154 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" );
6155 : }
6156 15833900 : ismInput->base.numNewSamplesPerChannel = 0;
6157 :
6158 : /* Apply input gain to new audio */
6159 15833900 : v_multc( inAudio.data, ismInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
6160 :
6161 : /* set combined orientation subframe info to start info */
6162 15833900 : ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
6163 :
6164 15833900 : switch ( getAudioConfigType( outConfig ) )
6165 : {
6166 6135216 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6167 6135216 : error = renderIsmToMc( ismInput, outAudio );
6168 6135216 : break;
6169 2413944 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6170 2413944 : error = renderIsmToSba( ismInput, outConfig, outAudio );
6171 2413944 : break;
6172 7257128 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6173 : switch ( outConfig )
6174 : {
6175 1599620 : case IVAS_AUDIO_CONFIG_BINAURAL:
6176 1599620 : error = renderIsmToBinaural( ismInput, outAudio );
6177 1599620 : break;
6178 1599620 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6179 1599620 : error = renderIsmToBinauralRoom( ismInput, outAudio );
6180 1599620 : break;
6181 66068 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
6182 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
6183 66068 : error = renderIsmToSplitBinaural( ismInput, outAudio );
6184 66068 : break;
6185 3991820 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6186 3991820 : error = renderIsmToBinauralReverb( ismInput, outAudio );
6187 3991820 : break;
6188 0 : default:
6189 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6190 : }
6191 7257128 : break;
6192 27612 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6193 27612 : renderIsmToMasa( ismInput, outAudio );
6194 27612 : break;
6195 0 : default:
6196 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6197 : }
6198 :
6199 : /* Check error here to keep switch statement more compact */
6200 15833900 : if ( error != IVAS_ERR_OK )
6201 : {
6202 0 : return error;
6203 : }
6204 :
6205 15833900 : ismInput->firstFrameRendered = TRUE;
6206 :
6207 15833900 : return error;
6208 : }
6209 :
6210 :
6211 8806803 : static ivas_error renderActiveInputsIsm(
6212 : IVAS_REND_HANDLE hIvasRend,
6213 : IVAS_REND_AudioBuffer outAudio )
6214 : {
6215 : int16_t i;
6216 : input_ism *pCurrentInput;
6217 : ivas_error error;
6218 :
6219 44034015 : for ( i = 0, pCurrentInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pCurrentInput )
6220 : {
6221 35227212 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
6222 : {
6223 : /* Skip inactive inputs */
6224 19393312 : continue;
6225 : }
6226 :
6227 15833900 : if ( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
6228 : {
6229 0 : return error;
6230 : }
6231 : }
6232 :
6233 8806803 : return IVAS_ERR_OK;
6234 : }
6235 :
6236 :
6237 418774 : static ivas_error renderLfeToBinaural(
6238 : const input_mc *mcInput,
6239 : const AUDIO_CONFIG outConfig,
6240 : IVAS_REND_AudioBuffer outAudio )
6241 : {
6242 : int16_t lfe_idx;
6243 : int16_t pose_idx, num_poses;
6244 : float gain;
6245 : int16_t ear_idx;
6246 : float tmpLfeBuffer[L_FRAME_MAX];
6247 : int16_t frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
6248 : const float *lfeInput;
6249 : float *writePtr;
6250 :
6251 418774 : assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" );
6252 :
6253 418774 : push_wmops( "renderLfeToBinaural" );
6254 :
6255 418774 : gain = GAIN_LFE;
6256 :
6257 418774 : if ( mcInput->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
6258 : {
6259 285322 : lfe_idx = LFE_CHANNEL;
6260 : }
6261 133452 : else if ( mcInput->customLsInput.num_lfe > 0 )
6262 : {
6263 0 : lfe_idx = mcInput->customLsInput.lfe_idx[0];
6264 : }
6265 : else
6266 : {
6267 : /* no LFE to render */
6268 133452 : return IVAS_ERR_OK;
6269 : }
6270 :
6271 : /* --- Prepare LFE signal to be added to binaural output --- */
6272 285322 : lfeInput = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 );
6273 285322 : frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
6274 285322 : num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
6275 285322 : num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame;
6276 :
6277 285322 : assert( mcInput->binauralDelaySmp <= MAX_BIN_DELAY_SAMPLES );
6278 :
6279 : /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
6280 285322 : v_multc( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame );
6281 :
6282 : /* Continue filling tmp buffer, now with LFE signal from current frame */
6283 285322 : v_multc( lfeInput, gain, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame );
6284 :
6285 : /* Save remaining LFE samples of current frame for next frame */
6286 285322 : mvr2r( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer, num_cpy_smpl_prev_frame );
6287 :
6288 : /* Copy LFE to left and right binaural channels for all poses */
6289 285322 : if ( mcInput->base.ctx.pSplitRendWrapper != NULL )
6290 : {
6291 21052 : num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
6292 : }
6293 : else
6294 : {
6295 264270 : num_poses = 1;
6296 : }
6297 :
6298 604132 : for ( pose_idx = 0; pose_idx < num_poses; ++pose_idx )
6299 : {
6300 956430 : for ( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
6301 : {
6302 637620 : writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS + ear_idx, 0 );
6303 637620 : v_add( writePtr, tmpLfeBuffer, writePtr, frame_size );
6304 : }
6305 : }
6306 :
6307 285322 : pop_wmops();
6308 :
6309 285322 : return IVAS_ERR_OK;
6310 : }
6311 :
6312 :
6313 104014 : static ivas_error renderMcToBinaural(
6314 : input_mc *mcInput,
6315 : const AUDIO_CONFIG outConfig,
6316 : IVAS_REND_AudioBuffer outAudio )
6317 : {
6318 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6319 : AUDIO_CONFIG inConfig;
6320 : ivas_error error;
6321 : IVAS_REND_AudioBuffer tmpRotBuffer;
6322 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6323 : int8_t combinedOrientationEnabled;
6324 : int16_t subframe_idx;
6325 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6326 : int16_t i;
6327 :
6328 1768238 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6329 : {
6330 1664224 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6331 : }
6332 :
6333 104014 : push_wmops( "renderMcToBinaural" );
6334 104014 : inConfig = mcInput->base.inConfig;
6335 :
6336 104014 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6337 104014 : combinedOrientationEnabled = 0;
6338 104014 : if ( *hCombinedOrientationData != NULL )
6339 : {
6340 53212 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6341 : {
6342 53212 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6343 : {
6344 53212 : combinedOrientationEnabled = 1;
6345 53212 : break;
6346 : }
6347 : }
6348 : }
6349 :
6350 104014 : if ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) )
6351 : {
6352 64522 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6353 :
6354 64522 : if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
6355 64522 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK )
6356 : {
6357 0 : return error;
6358 : }
6359 : }
6360 : else
6361 : {
6362 : /* apply rotation */
6363 39492 : if ( combinedOrientationEnabled )
6364 : {
6365 10932 : tmpRotBuffer = mcInput->base.inputBuffer;
6366 10932 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6367 10932 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6368 :
6369 10932 : if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
6370 : {
6371 0 : return error;
6372 : }
6373 :
6374 10932 : copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer );
6375 10932 : free( tmpRotBuffer.data );
6376 : }
6377 : else
6378 : {
6379 28560 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6380 : }
6381 :
6382 : /* call CREND */
6383 39492 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL,
6384 39492 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
6385 : {
6386 0 : return error;
6387 : }
6388 : }
6389 :
6390 104014 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6391 :
6392 104014 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6393 : {
6394 0 : return error;
6395 : }
6396 :
6397 104014 : pop_wmops();
6398 104014 : return IVAS_ERR_OK;
6399 : }
6400 :
6401 :
6402 204740 : static ivas_error renderMcToBinauralRoom(
6403 : input_mc *mcInput,
6404 : const AUDIO_CONFIG outConfig,
6405 : IVAS_REND_AudioBuffer outAudio )
6406 : {
6407 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6408 : AUDIO_CONFIG inConfig;
6409 : ivas_error error;
6410 : IVAS_REND_AudioBuffer tmpRotBuffer;
6411 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6412 : int16_t i;
6413 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6414 : int8_t combinedOrientationEnabled;
6415 : int16_t subframe_idx;
6416 :
6417 3480580 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6418 : {
6419 3275840 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6420 : }
6421 :
6422 204740 : push_wmops( "renderMcToBinauralRoom" );
6423 204740 : inConfig = mcInput->base.inConfig;
6424 :
6425 204740 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6426 204740 : combinedOrientationEnabled = 0;
6427 204740 : if ( *hCombinedOrientationData != NULL )
6428 : {
6429 61940 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6430 : {
6431 61940 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6432 : {
6433 61940 : combinedOrientationEnabled = 1;
6434 61940 : break;
6435 : }
6436 : }
6437 : }
6438 :
6439 204740 : if ( ( mcInput->hReverb != NULL && outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) ) )
6440 : {
6441 20038 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6442 :
6443 20038 : if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
6444 20038 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK )
6445 : {
6446 0 : return error;
6447 : }
6448 : }
6449 : else
6450 : {
6451 : /* apply rotation */
6452 184702 : if ( combinedOrientationEnabled )
6453 : {
6454 41902 : tmpRotBuffer = mcInput->base.inputBuffer;
6455 41902 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6456 41902 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6457 :
6458 41902 : if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
6459 : {
6460 0 : return error;
6461 : }
6462 :
6463 41902 : copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer );
6464 41902 : free( tmpRotBuffer.data );
6465 : }
6466 : else
6467 : {
6468 142800 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6469 : }
6470 :
6471 : /* call CREND */
6472 184702 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL,
6473 184702 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
6474 : {
6475 0 : return error;
6476 : }
6477 : }
6478 :
6479 204740 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6480 :
6481 204740 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6482 : {
6483 0 : return error;
6484 : }
6485 :
6486 204740 : pop_wmops();
6487 204740 : return IVAS_ERR_OK;
6488 : }
6489 :
6490 :
6491 88968 : static ivas_error renderMcCustomLsToBinauralRoom(
6492 : input_mc *mcInput,
6493 : const AUDIO_CONFIG outConfig,
6494 : IVAS_REND_AudioBuffer outAudio )
6495 : {
6496 : int16_t i;
6497 : int16_t tmp;
6498 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6499 : ivas_error error;
6500 : IVAS_REND_AudioBuffer tmpRotBuffer;
6501 : IVAS_REND_AudioBuffer tmpMcBuffer;
6502 : IVAS_REND_AudioBuffer *tmpBufPtr;
6503 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6504 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6505 : int8_t combinedOrientationEnabled;
6506 : int16_t subframe_idx;
6507 :
6508 88968 : push_wmops( "renderMcCustomLsToBinauralRoom" );
6509 88968 : tmpRotBuffer = outAudio; /* avoid compilation warning */
6510 :
6511 1512456 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6512 : {
6513 1423488 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6514 : }
6515 :
6516 88968 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6517 88968 : combinedOrientationEnabled = 0;
6518 88968 : if ( *hCombinedOrientationData != NULL )
6519 : {
6520 44484 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6521 : {
6522 44484 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6523 : {
6524 44484 : combinedOrientationEnabled = 1;
6525 44484 : break;
6526 : }
6527 : }
6528 : }
6529 :
6530 : /* apply rotation */
6531 88968 : if ( combinedOrientationEnabled )
6532 : {
6533 44484 : tmpRotBuffer = mcInput->base.inputBuffer;
6534 44484 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6535 44484 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6536 :
6537 44484 : if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
6538 : {
6539 0 : return error;
6540 : }
6541 : }
6542 :
6543 : /* intermediate conversion to 7_1_4 */
6544 88968 : tmpMcBuffer = mcInput->base.inputBuffer;
6545 :
6546 88968 : if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK )
6547 : {
6548 0 : return error;
6549 : }
6550 :
6551 88968 : tmpMcBuffer.config.numChannels = tmp;
6552 88968 : tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) );
6553 88968 : set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels );
6554 :
6555 88968 : tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &mcInput->base.inputBuffer;
6556 1360680 : for ( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
6557 : {
6558 1271712 : renderBufferChannel( *tmpBufPtr, i, mcInput->panGains[i], tmpMcBuffer );
6559 : }
6560 88968 : copyBufferTo2dArray( tmpMcBuffer, tmpCrendBuffer );
6561 :
6562 : /* call CREND */
6563 88968 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL,
6564 88968 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
6565 : {
6566 0 : return error;
6567 : }
6568 :
6569 88968 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
6570 :
6571 88968 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6572 : {
6573 0 : return error;
6574 : }
6575 :
6576 88968 : if ( combinedOrientationEnabled )
6577 : {
6578 44484 : free( tmpRotBuffer.data );
6579 : }
6580 88968 : free( tmpMcBuffer.data );
6581 :
6582 88968 : pop_wmops();
6583 88968 : return IVAS_ERR_OK;
6584 : }
6585 :
6586 :
6587 678799 : static void renderMcToMc(
6588 : const input_mc *mcInput,
6589 : IVAS_REND_AudioBuffer outAudio )
6590 : {
6591 : int16_t i;
6592 : IVAS_REND_AudioBuffer inAudio;
6593 :
6594 678799 : push_wmops( "renderMcToMc" );
6595 678799 : inAudio = mcInput->base.inputBuffer;
6596 :
6597 5280886 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6598 : {
6599 4602087 : renderBufferChannel( inAudio, i, mcInput->panGains[i], outAudio );
6600 : }
6601 :
6602 678799 : pop_wmops();
6603 678799 : return;
6604 : }
6605 :
6606 :
6607 262299 : static void renderMcToSba(
6608 : const input_mc *mcInput,
6609 : IVAS_REND_AudioBuffer outAudio )
6610 : {
6611 : int16_t i;
6612 : IVAS_REND_AudioBuffer inAudio;
6613 :
6614 262299 : push_wmops( "renderMcToSba" );
6615 262299 : inAudio = mcInput->base.inputBuffer;
6616 :
6617 2077212 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6618 : {
6619 1814913 : renderBufferChannel( inAudio, i, mcInput->panGains[i], outAudio );
6620 : }
6621 :
6622 262299 : pop_wmops();
6623 262299 : return;
6624 : }
6625 :
6626 :
6627 13836 : static void renderMcToMasa(
6628 : input_mc *mcInput,
6629 : IVAS_REND_AudioBuffer outAudio )
6630 : {
6631 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6632 :
6633 13836 : push_wmops( "renderMcToMasa" );
6634 13836 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6635 :
6636 13836 : ivas_mcmasa_ana( mcInput->hMcMasa, tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, mcInput->base.inputBuffer.config.numChannels );
6637 :
6638 13836 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6639 :
6640 13836 : pop_wmops();
6641 13836 : return;
6642 : }
6643 :
6644 :
6645 21052 : static ivas_error renderMcToSplitBinaural(
6646 : input_mc *mcInput,
6647 : const AUDIO_CONFIG outConfig,
6648 : IVAS_REND_AudioBuffer outAudio )
6649 : {
6650 : int16_t i, j, pos_idx;
6651 : int16_t sf;
6652 : int16_t output_frame;
6653 : ivas_error error;
6654 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
6655 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
6656 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6657 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6658 : float tmpSplitBinauralBuffer[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
6659 : AUDIO_CONFIG inConfig;
6660 : IVAS_REND_AudioBuffer tmpRotBuffer;
6661 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
6662 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
6663 :
6664 21052 : push_wmops( "renderMcToSplitBinaural" );
6665 21052 : inConfig = mcInput->base.inConfig;
6666 21052 : output_frame = mcInput->base.inputBuffer.config.numSamplesPerChannel;
6667 :
6668 21052 : pSplitRendWrapper = mcInput->base.ctx.pSplitRendWrapper;
6669 21052 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
6670 :
6671 357884 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6672 : {
6673 336832 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6674 : }
6675 :
6676 : /* save current head positions */
6677 21052 : pCombinedOrientationDataLocal = *mcInput->base.ctx.pCombinedOrientationData;
6678 21052 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
6679 21052 : if ( pMultiBinPoseData->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
6680 : {
6681 37632 : for ( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
6682 : {
6683 28224 : combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0];
6684 112896 : for ( i = 0; i < 3; i++ )
6685 : {
6686 338688 : for ( j = 0; j < 3; j++ )
6687 : {
6688 254016 : combinedOrientationDataLocal.Rmat[sf][i][j] = combinedOrientationDataLocal.Rmat[0][i][j];
6689 : }
6690 : }
6691 : }
6692 : }
6693 :
6694 : /* temporary buffer for rotation in source format for CREND */
6695 21052 : tmpRotBuffer = mcInput->base.inputBuffer;
6696 21052 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inConfig != IVAS_AUDIO_CONFIG_5_1 && inConfig != IVAS_AUDIO_CONFIG_7_1 )
6697 : {
6698 3604 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6699 : }
6700 :
6701 75592 : for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6702 : {
6703 : /* Update head positions */
6704 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
6705 257784 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
6706 : {
6707 203244 : Quaternions_orig[i] = combinedOrientationDataLocal.Quaternions[i];
6708 203244 : Quaternions_abs.w = -3.0f;
6709 203244 : Quat2EulerDegree( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/
6710 :
6711 203244 : Quaternions_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0];
6712 203244 : Quaternions_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1];
6713 203244 : Quaternions_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2];
6714 203244 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs;
6715 203244 : QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] );
6716 : }
6717 :
6718 54540 : if ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM || inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 )
6719 : {
6720 : /* tdrend processing overview:
6721 : * 1. copy from inputBuffer to tmpRendBuffer
6722 : * 2. td_binaural_renderer_ext: inplace processing in tmpRendBuffer
6723 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
6724 : * 4. LFE mixing
6725 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
6726 :
6727 : /* copy input to tdrend input/output buffer */
6728 39912 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6729 :
6730 : /* perform rotation in source format to tmpRotBuffer */
6731 39912 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
6732 :
6733 : /* Render */
6734 39912 : if ( ( error = ivas_td_binaural_renderer_ext( ( 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 ) ) != IVAS_ERR_OK )
6735 : {
6736 0 : return error;
6737 : }
6738 :
6739 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
6740 : * overwrite original audio, which is still needed for rendering next head pose. */
6741 39912 : mvr2r( tmpRendBuffer[0], tmpSplitBinauralBuffer[2 * pos_idx], output_frame );
6742 39912 : mvr2r( tmpRendBuffer[1], tmpSplitBinauralBuffer[2 * pos_idx + 1], output_frame );
6743 : }
6744 : else
6745 : {
6746 : /* crend processing overview:
6747 : * 1. rotateFrameMc: inputBuffer to tmpRotBuffer
6748 : * 2. crend_process: tmpRotBuffer to tmpRendBuffer
6749 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
6750 : * 4. LFE mixing
6751 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
6752 :
6753 : /* copy input for in-place rotation */
6754 14628 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6755 :
6756 : /* perform rotation in source format to tmpRotBuffer */
6757 14628 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
6758 14628 : if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, mcInput->rot_gains_prev[pos_idx], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
6759 : {
6760 0 : return error;
6761 : }
6762 :
6763 14628 : copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer );
6764 :
6765 : /* call CREND (rotation already performed) */
6766 14628 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL,
6767 14628 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, pos_idx ) ) != IVAS_ERR_OK )
6768 : {
6769 0 : return error;
6770 : }
6771 :
6772 : /* Copy rendererd audio to tmp storage buffer, Copying directly to output would
6773 : * overwrite original audio, which is still needed for rendering next head pose. */
6774 14628 : mvr2r( tmpRendBuffer[0], tmpSplitBinauralBuffer[2 * pos_idx], output_frame );
6775 14628 : mvr2r( tmpRendBuffer[1], tmpSplitBinauralBuffer[2 * pos_idx + 1], output_frame );
6776 : }
6777 :
6778 : /* restore original headrotation data */
6779 257784 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
6780 : {
6781 203244 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i];
6782 : }
6783 : }
6784 :
6785 21052 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inConfig != IVAS_AUDIO_CONFIG_5_1 && inConfig != IVAS_AUDIO_CONFIG_7_1 )
6786 : {
6787 : /* free temporary buffer for rotation in source format for CREND */
6788 3604 : free( tmpRotBuffer.data );
6789 : }
6790 :
6791 21052 : accumulate2dArrayToBuffer( tmpSplitBinauralBuffer, &outAudio );
6792 :
6793 21052 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6794 : {
6795 0 : return error;
6796 : }
6797 :
6798 21052 : pop_wmops();
6799 21052 : return IVAS_ERR_OK;
6800 : }
6801 :
6802 :
6803 1373708 : static ivas_error renderInputMc(
6804 : input_mc *mcInput,
6805 : const AUDIO_CONFIG outConfig,
6806 : IVAS_REND_AudioBuffer outAudio )
6807 : {
6808 : ivas_error error;
6809 : IVAS_REND_AudioBuffer inAudio;
6810 :
6811 1373708 : error = IVAS_ERR_OK;
6812 :
6813 1373708 : inAudio = mcInput->base.inputBuffer;
6814 :
6815 1373708 : if ( mcInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel )
6816 : {
6817 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" );
6818 : }
6819 1373708 : mcInput->base.numNewSamplesPerChannel = 0;
6820 :
6821 : /* Apply input gain to new audio */
6822 1373708 : v_multc( inAudio.data, mcInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
6823 :
6824 : /* set combined orientation subframe info to start info */
6825 1373708 : ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
6826 :
6827 1373708 : switch ( getAudioConfigType( outConfig ) )
6828 : {
6829 678799 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6830 678799 : renderMcToMc( mcInput, outAudio );
6831 678799 : break;
6832 262299 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6833 262299 : renderMcToSba( mcInput, outAudio );
6834 262299 : break;
6835 418774 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6836 : switch ( outConfig )
6837 : {
6838 104014 : case IVAS_AUDIO_CONFIG_BINAURAL:
6839 104014 : error = renderMcToBinaural( mcInput, outConfig, outAudio );
6840 104014 : break;
6841 293708 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6842 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6843 293708 : if ( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
6844 : {
6845 88968 : error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
6846 : }
6847 : else
6848 : {
6849 204740 : error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
6850 : }
6851 293708 : break;
6852 21052 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
6853 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
6854 21052 : error = renderMcToSplitBinaural( mcInput, outConfig, outAudio );
6855 21052 : break;
6856 0 : default:
6857 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6858 : }
6859 418774 : break;
6860 13836 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6861 13836 : renderMcToMasa( mcInput, outAudio );
6862 13836 : break;
6863 0 : default:
6864 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6865 : }
6866 :
6867 1373708 : return error;
6868 : }
6869 :
6870 :
6871 8806803 : static ivas_error renderActiveInputsMc(
6872 : IVAS_REND_HANDLE hIvasRend,
6873 : IVAS_REND_AudioBuffer outAudio )
6874 : {
6875 : int16_t i;
6876 : input_mc *pCurrentInput;
6877 : ivas_error error;
6878 :
6879 17613606 : for ( i = 0, pCurrentInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pCurrentInput )
6880 : {
6881 8806803 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
6882 : {
6883 : /* Skip inactive inputs */
6884 7433095 : continue;
6885 : }
6886 :
6887 1373708 : if ( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
6888 : {
6889 0 : return error;
6890 : }
6891 : }
6892 :
6893 8806803 : return IVAS_ERR_OK;
6894 : }
6895 :
6896 :
6897 1827579 : static void renderSbaToMc(
6898 : const input_sba *sbaInput,
6899 : IVAS_REND_AudioBuffer outAudio )
6900 : {
6901 : int16_t i;
6902 : IVAS_REND_AudioBuffer inAudio;
6903 :
6904 1827579 : push_wmops( "renderSbaToMc" );
6905 1827579 : inAudio = sbaInput->base.inputBuffer;
6906 :
6907 19422300 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6908 : {
6909 17594721 : renderBufferChannel( inAudio, i, sbaInput->hoaDecMtx[i], outAudio );
6910 : }
6911 :
6912 1827579 : pop_wmops();
6913 1827579 : return;
6914 : }
6915 :
6916 :
6917 721746 : static void renderSbaToSba(
6918 : const input_sba *sbaInput,
6919 : IVAS_REND_AudioBuffer outAudio )
6920 : {
6921 : int16_t i;
6922 : IVAS_REND_AudioBuffer inAudio;
6923 :
6924 721746 : push_wmops( "renderSbaToSba" );
6925 721746 : inAudio = sbaInput->base.inputBuffer;
6926 :
6927 7667820 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6928 : {
6929 6946074 : renderBufferChannel( inAudio, i, sbaInput->hoaDecMtx[i], outAudio );
6930 : }
6931 :
6932 721746 : pop_wmops();
6933 721746 : return;
6934 : }
6935 :
6936 :
6937 26520 : static ivas_error renderSbaToMultiBinaural(
6938 : input_sba *sbaInput,
6939 : const AUDIO_CONFIG outConfig,
6940 : float out[][L_FRAME48k] )
6941 : {
6942 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6943 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6944 : int16_t sf;
6945 : int16_t i, j, pos_idx;
6946 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
6947 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
6948 : ivas_error error;
6949 : IVAS_REND_AudioBuffer tmpRotBuffer;
6950 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
6951 :
6952 450840 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6953 : {
6954 424320 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6955 : }
6956 26520 : push_wmops( "renderSbaToMultiBinaural" );
6957 26520 : pMultiBinPoseData = &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData;
6958 :
6959 26520 : pCombinedOrientationDataLocal = *sbaInput->base.ctx.pCombinedOrientationData;
6960 26520 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
6961 26520 : if ( pMultiBinPoseData->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
6962 : {
6963 81120 : for ( sf = 1; sf < combinedOrientationDataLocal.num_subframes; sf++ )
6964 : {
6965 60840 : combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0];
6966 243360 : for ( i = 0; i < 3; i++ )
6967 : {
6968 730080 : for ( j = 0; j < 3; j++ )
6969 : {
6970 547560 : combinedOrientationDataLocal.Rmat[sf][i][j] = combinedOrientationDataLocal.Rmat[0][i][j];
6971 : }
6972 : }
6973 : }
6974 : }
6975 :
6976 26520 : tmpRotBuffer = sbaInput->base.inputBuffer;
6977 26520 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6978 :
6979 144768 : for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6980 : {
6981 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
6982 591240 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
6983 : {
6984 472992 : Quaternions_orig[i] = combinedOrientationDataLocal.Quaternions[i];
6985 472992 : Quaternions_abs.w = -3.0f;
6986 472992 : Quat2EulerDegree( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/
6987 :
6988 472992 : Quaternions_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0];
6989 472992 : Quaternions_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1];
6990 472992 : Quaternions_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2];
6991 472992 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs;
6992 472992 : QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] );
6993 : }
6994 :
6995 :
6996 : /* copy input for in-place rotation */
6997 118248 : mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
6998 :
6999 118248 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7000 :
7001 118248 : if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, sbaInput->rot_gains_prev[pos_idx], tmpRotBuffer ) ) != IVAS_ERR_OK )
7002 : {
7003 0 : return error;
7004 : }
7005 :
7006 118248 : copyBufferTo2dArray( tmpRotBuffer, tmpCrendBuffer );
7007 :
7008 118248 : assert( sbaInput->crendWrapper->hCrend[0]->hReverb == NULL );
7009 :
7010 : /* call CREND */
7011 118248 : if ( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL,
7012 118248 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, pos_idx ) ) != IVAS_ERR_OK )
7013 : {
7014 0 : return error;
7015 : }
7016 :
7017 591240 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7018 : {
7019 472992 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i];
7020 : }
7021 :
7022 :
7023 : /* move to output */
7024 354744 : for ( i = 0; i < BINAURAL_CHANNELS; i++ )
7025 : {
7026 236496 : mvr2r( tmpCrendBuffer[i], out[pos_idx * BINAURAL_CHANNELS + i], tmpRotBuffer.config.numSamplesPerChannel );
7027 : }
7028 : }
7029 :
7030 26520 : free( tmpRotBuffer.data );
7031 :
7032 26520 : pop_wmops();
7033 26520 : return IVAS_ERR_OK;
7034 : }
7035 :
7036 :
7037 1248 : static void renderSbaToMultiBinauralCldfb(
7038 : input_sba *sbaInput,
7039 : float Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7040 : float Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7041 : const int16_t low_res_pre_rend_rot,
7042 : const int16_t num_subframes )
7043 : {
7044 : float Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7045 : float Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7046 :
7047 1248 : copyBufferToCLDFBarray( sbaInput->base.inputBuffer, Cldfb_RealBuffer, Cldfb_ImagBuffer );
7048 :
7049 1248 : ivas_rend_CldfbMultiBinRendProcess( sbaInput->cldfbRendWrapper.hCldfbRend, sbaInput->base.ctx.pCombinedOrientationData, &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData,
7050 : Cldfb_RealBuffer, Cldfb_ImagBuffer, Cldfb_Out_Real, Cldfb_Out_Imag, low_res_pre_rend_rot, num_subframes );
7051 :
7052 1248 : return;
7053 : }
7054 :
7055 :
7056 27768 : static ivas_error renderSbaToSplitBinaural(
7057 : input_sba *sbaInput,
7058 : const AUDIO_CONFIG outConfig,
7059 : IVAS_REND_AudioBuffer outAudio )
7060 : {
7061 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7062 : ivas_error error;
7063 : float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7064 : float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7065 :
7066 27768 : push_wmops( "renderSbaToSplitBinaural" );
7067 :
7068 27768 : if ( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
7069 : {
7070 1248 : renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 1,
7071 1248 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) );
7072 :
7073 1248 : accumulateCLDFBArrayToBuffer( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7074 : }
7075 : else
7076 : {
7077 26520 : if ( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer ) ) != IVAS_ERR_OK )
7078 : {
7079 0 : return error;
7080 : }
7081 :
7082 26520 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
7083 : }
7084 :
7085 27768 : pop_wmops();
7086 27768 : return IVAS_ERR_OK;
7087 : }
7088 :
7089 :
7090 1691634 : static ivas_error renderSbaToBinaural(
7091 : input_sba *sbaInput,
7092 : const AUDIO_CONFIG outConfig,
7093 : IVAS_REND_AudioBuffer outAudio )
7094 : {
7095 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7096 : ivas_error error;
7097 : IVAS_REND_AudioBuffer tmpRotBuffer;
7098 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7099 : int16_t i;
7100 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7101 : int8_t combinedOrientationEnabled;
7102 : int16_t subframe_idx;
7103 :
7104 1691634 : push_wmops( "renderSbaToBinaural" );
7105 1691634 : if ( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
7106 : {
7107 : float Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7108 : float Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7109 :
7110 0 : renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 0,
7111 0 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) );
7112 :
7113 0 : accumulateCLDFBArrayToBuffer( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7114 : }
7115 : else
7116 : {
7117 28757778 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7118 : {
7119 27066144 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7120 : }
7121 :
7122 1691634 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7123 1691634 : combinedOrientationEnabled = 0;
7124 1691634 : if ( *hCombinedOrientationData != NULL )
7125 : {
7126 494892 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7127 : {
7128 494892 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7129 : {
7130 494892 : combinedOrientationEnabled = 1;
7131 494892 : break;
7132 : }
7133 : }
7134 : }
7135 :
7136 : /* apply rotation */
7137 1691634 : if ( combinedOrientationEnabled )
7138 : {
7139 494892 : tmpRotBuffer = sbaInput->base.inputBuffer;
7140 494892 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
7141 :
7142 : /* copy input for in-place rotation */
7143 494892 : mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7144 :
7145 494892 : if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
7146 494892 : sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK )
7147 : {
7148 0 : return error;
7149 : }
7150 :
7151 494892 : copyBufferTo2dArray( tmpRotBuffer, tmpCrendBuffer );
7152 494892 : free( tmpRotBuffer.data );
7153 : }
7154 : else
7155 : {
7156 1196742 : copyBufferTo2dArray( sbaInput->base.inputBuffer, tmpCrendBuffer );
7157 : }
7158 :
7159 : /* call CREND */
7160 1691634 : if ( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL,
7161 1691634 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
7162 : {
7163 0 : return error;
7164 : }
7165 :
7166 1691634 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
7167 : }
7168 :
7169 1691634 : pop_wmops();
7170 1691634 : return IVAS_ERR_OK;
7171 : }
7172 :
7173 :
7174 487662 : static ivas_error renderSbaToBinauralRoom(
7175 : input_sba *sbaInput,
7176 : const AUDIO_CONFIG outConfig,
7177 : IVAS_REND_AudioBuffer outAudio )
7178 : {
7179 : int16_t i;
7180 : int16_t tmp;
7181 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7182 : ivas_error error;
7183 : IVAS_REND_AudioBuffer tmpRotBuffer;
7184 : IVAS_REND_AudioBuffer tmpMcBuffer;
7185 : IVAS_REND_AudioBuffer *tmpBufPtr;
7186 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7187 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7188 : int8_t combinedOrientationEnabled;
7189 : int16_t subframe_idx;
7190 :
7191 487662 : tmpRotBuffer = outAudio; /* avoid compilation warning */
7192 487662 : push_wmops( "renderSbaToBinauralRoom" );
7193 :
7194 8290254 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7195 : {
7196 7802592 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7197 : }
7198 :
7199 487662 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7200 487662 : combinedOrientationEnabled = 0;
7201 487662 : if ( *hCombinedOrientationData != NULL )
7202 : {
7203 247446 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7204 : {
7205 247446 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7206 : {
7207 247446 : combinedOrientationEnabled = 1;
7208 247446 : break;
7209 : }
7210 : }
7211 : }
7212 :
7213 : /* apply rotation */
7214 487662 : if ( combinedOrientationEnabled )
7215 : {
7216 247446 : tmpRotBuffer = sbaInput->base.inputBuffer;
7217 247446 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
7218 :
7219 : /* copy input for in-place rotation */
7220 247446 : mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7221 :
7222 247446 : if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
7223 247446 : sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK )
7224 : {
7225 0 : return error;
7226 : }
7227 : }
7228 :
7229 : /* intermediate rendering to 7_1_4 */
7230 487662 : tmpMcBuffer = sbaInput->base.inputBuffer;
7231 :
7232 487662 : if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK )
7233 : {
7234 0 : return error;
7235 : }
7236 :
7237 487662 : tmpMcBuffer.config.numChannels = tmp;
7238 487662 : tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) );
7239 487662 : set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numChannels * tmpMcBuffer.config.numSamplesPerChannel );
7240 :
7241 487662 : tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &sbaInput->base.inputBuffer;
7242 5201728 : for ( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
7243 : {
7244 4714066 : renderBufferChannel( *tmpBufPtr, i, sbaInput->hoaDecMtx[i], tmpMcBuffer );
7245 : }
7246 :
7247 487662 : copyBufferTo2dArray( tmpMcBuffer, tmpCrendBuffer );
7248 :
7249 : /* call CREND */
7250 487662 : if ( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL,
7251 487662 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
7252 : {
7253 0 : return error;
7254 : }
7255 :
7256 487662 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
7257 :
7258 487662 : if ( combinedOrientationEnabled )
7259 : {
7260 247446 : free( tmpRotBuffer.data );
7261 : }
7262 487662 : free( tmpMcBuffer.data );
7263 :
7264 487662 : pop_wmops();
7265 487662 : return IVAS_ERR_OK;
7266 : }
7267 :
7268 :
7269 13836 : static void renderSbaToMasa(
7270 : input_sba *sbaInput,
7271 : IVAS_REND_AudioBuffer outAudio )
7272 : {
7273 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7274 :
7275 13836 : push_wmops( "renderMcToMasa" );
7276 13836 : copyBufferTo2dArray( sbaInput->base.inputBuffer, tmpRendBuffer );
7277 13836 : ivas_dirac_ana( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels );
7278 13836 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
7279 :
7280 13836 : pop_wmops();
7281 13836 : return;
7282 : }
7283 :
7284 :
7285 4770225 : static ivas_error renderInputSba(
7286 : input_sba *sbaInput,
7287 : const AUDIO_CONFIG outConfig,
7288 : IVAS_REND_AudioBuffer outAudio )
7289 : {
7290 : ivas_error error;
7291 : IVAS_REND_AudioBuffer inAudio;
7292 : int16_t cldfb2tdSampleFact;
7293 :
7294 4770225 : error = IVAS_ERR_OK;
7295 4770225 : inAudio = sbaInput->base.inputBuffer;
7296 :
7297 4770225 : cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
7298 4770225 : if ( ( sbaInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) &&
7299 0 : ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
7300 : {
7301 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" );
7302 : }
7303 4770225 : sbaInput->base.numNewSamplesPerChannel = 0;
7304 :
7305 : /* Apply input gain to new audio */
7306 4770225 : v_multc( inAudio.data, sbaInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
7307 :
7308 : /* set combined orientation subframe info to start info */
7309 4770225 : ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
7310 :
7311 4770225 : switch ( getAudioConfigType( outConfig ) )
7312 : {
7313 1827579 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
7314 1827579 : renderSbaToMc( sbaInput, outAudio );
7315 1827579 : break;
7316 721746 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
7317 721746 : renderSbaToSba( sbaInput, outAudio );
7318 721746 : break;
7319 2207064 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
7320 : switch ( outConfig )
7321 : {
7322 27768 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
7323 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
7324 27768 : error = renderSbaToSplitBinaural( sbaInput, outConfig, outAudio );
7325 27768 : break;
7326 1691634 : case IVAS_AUDIO_CONFIG_BINAURAL:
7327 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
7328 1691634 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
7329 1691634 : break;
7330 487662 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
7331 487662 : error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
7332 487662 : break;
7333 0 : default:
7334 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7335 : }
7336 2207064 : break;
7337 13836 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
7338 13836 : renderSbaToMasa( sbaInput, outAudio );
7339 13836 : break;
7340 0 : default:
7341 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7342 : }
7343 :
7344 4770225 : return error;
7345 : }
7346 :
7347 :
7348 8806803 : static ivas_error renderActiveInputsSba(
7349 : IVAS_REND_HANDLE hIvasRend,
7350 : IVAS_REND_AudioBuffer outAudio )
7351 : {
7352 : int16_t i;
7353 : input_sba *pCurrentInput;
7354 : ivas_error error;
7355 :
7356 17613606 : for ( i = 0, pCurrentInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pCurrentInput )
7357 : {
7358 8806803 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
7359 : {
7360 : /* Skip inactive inputs */
7361 4036578 : continue;
7362 : }
7363 :
7364 4770225 : if ( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
7365 : {
7366 0 : return error;
7367 : }
7368 : }
7369 :
7370 8806803 : return IVAS_ERR_OK;
7371 : }
7372 :
7373 :
7374 790366 : static void copyMasaMetadataToDiracRenderer(
7375 : MASA_METADATA_FRAME *meta,
7376 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
7377 : const int16_t maxBin )
7378 : {
7379 : int16_t band, sf, bin;
7380 : int16_t meta_write_index;
7381 :
7382 790366 : hSpatParamRendCom->numParametricDirections = meta->descriptive_meta.numberOfDirections + 1;
7383 790366 : hSpatParamRendCom->numSimultaneousDirections = meta->descriptive_meta.numberOfDirections + 1;
7384 :
7385 3951830 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
7386 : {
7387 3161464 : meta_write_index = ( hSpatParamRendCom->dirac_bs_md_write_idx + sf ) % hSpatParamRendCom->dirac_md_buffer_length;
7388 :
7389 79036600 : for ( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
7390 : {
7391 203486976 : for ( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
7392 : {
7393 127611840 : hSpatParamRendCom->azimuth[meta_write_index][bin] = (int16_t) meta->directional_meta[0].azimuth[sf][band];
7394 127611840 : hSpatParamRendCom->elevation[meta_write_index][bin] = (int16_t) meta->directional_meta[0].elevation[sf][band];
7395 127611840 : hSpatParamRendCom->energy_ratio1[meta_write_index][bin] = meta->directional_meta[0].energy_ratio[sf][band];
7396 127611840 : hSpatParamRendCom->diffuseness_vector[meta_write_index][bin] = 1.0f - meta->directional_meta[0].energy_ratio[sf][band];
7397 127611840 : hSpatParamRendCom->spreadCoherence[meta_write_index][bin] = meta->directional_meta[0].spread_coherence[sf][band];
7398 127611840 : hSpatParamRendCom->surroundingCoherence[meta_write_index][bin] = meta->common_meta.surround_coherence[sf][band];
7399 :
7400 127611840 : if ( hSpatParamRendCom->numSimultaneousDirections == 2 )
7401 : {
7402 63698880 : hSpatParamRendCom->azimuth2[meta_write_index][bin] = (int16_t) meta->directional_meta[1].azimuth[sf][band];
7403 63698880 : hSpatParamRendCom->elevation2[meta_write_index][bin] = (int16_t) meta->directional_meta[1].elevation[sf][band];
7404 63698880 : hSpatParamRendCom->energy_ratio2[meta_write_index][bin] = meta->directional_meta[1].energy_ratio[sf][band];
7405 63698880 : hSpatParamRendCom->diffuseness_vector[meta_write_index][bin] -= meta->directional_meta[1].energy_ratio[sf][band];
7406 63698880 : hSpatParamRendCom->spreadCoherence2[meta_write_index][bin] = meta->directional_meta[1].spread_coherence[sf][band];
7407 : }
7408 : }
7409 : }
7410 : }
7411 :
7412 790366 : hSpatParamRendCom->dirac_bs_md_write_idx = ( hSpatParamRendCom->dirac_bs_md_write_idx + MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
7413 :
7414 790366 : return;
7415 : }
7416 :
7417 :
7418 27612 : static void renderMasaToMasa(
7419 : input_masa *masaInput,
7420 : IVAS_REND_AudioBuffer outAudio )
7421 : {
7422 : int16_t sf, band, dir, numDirs;
7423 : float ratioSum;
7424 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
7425 : MASA_METADATA_FRAME *inMeta;
7426 : float tmpBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7427 : int16_t ts, i, j, l_ts;
7428 : float Chan_RealBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
7429 : float Chan_ImagBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
7430 : int16_t band_m_idx, block_m_idx;
7431 : int16_t mrange[2];
7432 : int16_t brange[2];
7433 : int16_t numAnalysisChannels;
7434 :
7435 27612 : copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer );
7436 :
7437 : /* Calculate energy */
7438 27612 : l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
7439 27612 : numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
7440 :
7441 : /* do processing over all CLDFB time slots */
7442 138060 : for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
7443 : {
7444 110448 : mrange[0] = DirAC_block_grouping[block_m_idx];
7445 110448 : mrange[1] = DirAC_block_grouping[block_m_idx + 1];
7446 :
7447 110448 : set_zero( masaInput->hMasaPrerend->energy[block_m_idx], MASA_FREQUENCY_BANDS );
7448 :
7449 552240 : for ( ts = mrange[0]; ts < mrange[1]; ts++ )
7450 : {
7451 1118976 : for ( i = 0; i < numAnalysisChannels; i++ )
7452 : {
7453 677184 : cldfbAnalysis_ts( &( tmpBuffer[i][l_ts * ts] ), Chan_RealBuffer[i], Chan_ImagBuffer[i], l_ts, masaInput->hMasaPrerend->cldfbAnaEnc[i] );
7454 : }
7455 :
7456 : /* Compute channel energy for metadata processing */
7457 10308480 : for ( band_m_idx = 0; band_m_idx < masaInput->hMasaPrerend->nbands; band_m_idx++ )
7458 : {
7459 9866688 : brange[0] = masaInput->hMasaPrerend->band_grouping[band_m_idx];
7460 9866688 : brange[1] = masaInput->hMasaPrerend->band_grouping[band_m_idx + 1];
7461 :
7462 27538368 : for ( j = brange[0]; j < brange[1]; j++ )
7463 : {
7464 44759040 : for ( i = 0; i < numAnalysisChannels; i++ )
7465 : {
7466 27087360 : masaInput->hMasaPrerend->energy[block_m_idx][band_m_idx] += Chan_RealBuffer[0][j] * Chan_RealBuffer[0][j] + Chan_ImagBuffer[0][j] * Chan_ImagBuffer[0][j];
7467 : }
7468 : }
7469 : }
7470 : }
7471 : }
7472 :
7473 : /* Copy audio channels if mismatch in number of transports */
7474 27612 : if ( masaInput->base.inputBuffer.config.numChannels == 1 && outAudio.config.numChannels == 2 )
7475 : {
7476 6450 : mvr2r( tmpBuffer[0], tmpBuffer[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
7477 : }
7478 21162 : else if ( masaInput->base.inputBuffer.config.numChannels == 2 && outAudio.config.numChannels == 1 )
7479 : {
7480 7356 : v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
7481 : }
7482 :
7483 : /* Copy metadata */
7484 27612 : outMeta = masaInput->hMasaPrerend->hMasaOut;
7485 27612 : inMeta = &masaInput->masaMetadata;
7486 27612 : numDirs = inMeta->descriptive_meta.numberOfDirections + 1;
7487 :
7488 138060 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
7489 : {
7490 2761200 : for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
7491 : {
7492 : /* Remainder is always set to zero and energy removal is compensated in following steps
7493 : * to other ratios. */
7494 2650752 : inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
7495 :
7496 2650752 : ratioSum = 0;
7497 6667776 : for ( dir = 0; dir < numDirs; dir++ )
7498 : {
7499 4017024 : ratioSum += inMeta->directional_meta[dir].energy_ratio[sf][band];
7500 : }
7501 2650752 : ratioSum += inMeta->common_meta.diffuse_to_total_ratio[sf][band];
7502 :
7503 2650752 : if ( ratioSum == 0.0f )
7504 : {
7505 0 : for ( dir = 0; dir < numDirs; dir++ )
7506 : {
7507 0 : inMeta->directional_meta[dir].energy_ratio[sf][band] = 0.0f;
7508 : }
7509 0 : inMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f;
7510 : }
7511 2650752 : else if ( ratioSum != 1.0f )
7512 : {
7513 131652 : for ( dir = 0; dir < numDirs; dir++ )
7514 : {
7515 87768 : inMeta->directional_meta[dir].energy_ratio[sf][band] /= ratioSum;
7516 : }
7517 43884 : inMeta->common_meta.diffuse_to_total_ratio[sf][band] /= ratioSum;
7518 : }
7519 : }
7520 : }
7521 :
7522 138060 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
7523 : {
7524 2761200 : for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
7525 : {
7526 2650752 : outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
7527 6667776 : for ( dir = 0; dir < numDirs; dir++ )
7528 : {
7529 4017024 : outMeta->directionIndex[dir][sf][band] = index_theta_phi_16( &inMeta->directional_meta[dir].elevation[sf][band], &inMeta->directional_meta[dir].azimuth[sf][band], masaInput->hMasaPrerend->sph_grid16 );
7530 4017024 : outMeta->directToTotalRatio[dir][sf][band] = (uint8_t) floorf( inMeta->directional_meta[dir].energy_ratio[sf][band] * UINT8_MAX );
7531 4017024 : outMeta->diffuseToTotalRatio[sf][band] -= outMeta->directToTotalRatio[dir][sf][band];
7532 4017024 : outMeta->spreadCoherence[dir][sf][band] = (uint8_t) floorf( inMeta->directional_meta[dir].spread_coherence[sf][band] * UINT8_MAX );
7533 : }
7534 2650752 : outMeta->surroundCoherence[sf][band] = (uint8_t) floorf( inMeta->common_meta.surround_coherence[sf][band] * UINT8_MAX );
7535 : }
7536 : }
7537 :
7538 27612 : copy_masa_descriptive_meta( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
7539 :
7540 27612 : accumulate2dArrayToBuffer( tmpBuffer, &outAudio );
7541 :
7542 27612 : return;
7543 : }
7544 :
7545 :
7546 838288 : static ivas_error renderInputMasa(
7547 : input_masa *masaInput,
7548 : const AUDIO_CONFIG outConfig,
7549 : IVAS_REND_AudioBuffer outAudio )
7550 : {
7551 : IVAS_REND_AudioBuffer inAudio;
7552 : int16_t ch;
7553 : int16_t maxBin;
7554 : float *tmpBuffer[MAX_OUTPUT_CHANNELS];
7555 : float tmpBuffer_buff[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7556 : int16_t cldfb2tdSampleFact;
7557 : float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7558 : float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7559 :
7560 838288 : if ( !masaInput->metadataHasBeenFed )
7561 : {
7562 0 : return IVAS_ERR_MISSING_METADATA;
7563 : }
7564 :
7565 838288 : inAudio = masaInput->base.inputBuffer;
7566 838288 : cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
7567 838288 : if ( ( masaInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) &&
7568 0 : ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
7569 : {
7570 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" );
7571 : }
7572 838288 : masaInput->base.numNewSamplesPerChannel = 0;
7573 :
7574 : /* Apply input gain to new audio */
7575 838288 : v_multc( inAudio.data, masaInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
7576 :
7577 838288 : maxBin = (int16_t) ( *masaInput->base.ctx.pOutSampleRate * INV_CLDFB_BANDWIDTH );
7578 :
7579 : /* set combined orientation subframe info to start info */
7580 838288 : ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
7581 :
7582 838288 : if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7583 : {
7584 : /* MASA prerendering path for MASA -> MASA */
7585 27612 : renderMasaToMasa( masaInput, outAudio );
7586 : }
7587 : else
7588 : {
7589 : /* MASA external renderer -> other formats */
7590 : int16_t num_subframes;
7591 13781492 : for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
7592 : {
7593 12970816 : tmpBuffer[ch] = tmpBuffer_buff[ch];
7594 : }
7595 :
7596 810676 : copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer_buff );
7597 :
7598 810676 : num_subframes = (int16_t) ( masaInput->base.inputBuffer.config.numSamplesPerChannel / ( *masaInput->base.ctx.pOutSampleRate / ( IVAS_NUM_FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ) );
7599 :
7600 810676 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
7601 14416 : {
7602 : /* split rendering. use the combined of the first subframe in all subframes */
7603 : int16_t sf, i, j;
7604 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
7605 14416 : pCombinedOrientationData = *masaInput->base.ctx.pCombinedOrientationData;
7606 57664 : for ( sf = 1; sf < pCombinedOrientationData->num_subframes; sf++ )
7607 : {
7608 43248 : pCombinedOrientationData->Quaternions[sf] = pCombinedOrientationData->Quaternions[0];
7609 172992 : for ( i = 0; i < 3; i++ )
7610 : {
7611 518976 : for ( j = 0; j < 3; j++ )
7612 : {
7613 389232 : pCombinedOrientationData->Rmat[sf][i][j] = pCombinedOrientationData->Rmat[0][i][j];
7614 : }
7615 : }
7616 : }
7617 :
7618 14416 : copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
7619 :
7620 14416 : ivas_masa_ext_rend_parambin_render( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, num_subframes, masaInput->base.ctx.pSplitRendWrapper, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
7621 :
7622 14416 : accumulateCLDFBArrayToBuffer( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7623 : }
7624 : else
7625 : {
7626 : /* non-split path */
7627 796260 : switch ( masaInput->hMasaExtRend->renderer_type )
7628 : {
7629 369750 : case RENDERER_DIRAC:
7630 369750 : copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
7631 369750 : ivas_masa_ext_dirac_render( masaInput->hMasaExtRend, tmpBuffer, num_subframes );
7632 369750 : break;
7633 406200 : case RENDERER_STEREO_PARAMETRIC:
7634 : case RENDERER_BINAURAL_PARAMETRIC:
7635 : case RENDERER_BINAURAL_PARAMETRIC_ROOM:
7636 406200 : copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
7637 406200 : ivas_masa_ext_rend_parambin_render( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, num_subframes, NULL, NULL, NULL );
7638 406200 : break;
7639 20310 : case RENDERER_DISABLE:
7640 20310 : break; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
7641 0 : default:
7642 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
7643 : }
7644 :
7645 796260 : accumulate2dArrayToBuffer( tmpBuffer_buff, &outAudio );
7646 : }
7647 : }
7648 :
7649 838288 : return IVAS_ERR_OK;
7650 : }
7651 :
7652 :
7653 8806803 : static ivas_error renderActiveInputsMasa(
7654 : IVAS_REND_HANDLE hIvasRend,
7655 : IVAS_REND_AudioBuffer outAudio )
7656 : {
7657 : int16_t i;
7658 : input_masa *pCurrentInput;
7659 : ivas_error error;
7660 :
7661 17613606 : for ( i = 0, pCurrentInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pCurrentInput )
7662 : {
7663 8806803 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
7664 : {
7665 : /* Skip inactive inputs */
7666 7968515 : continue;
7667 : }
7668 :
7669 838288 : if ( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
7670 : {
7671 0 : return error;
7672 : }
7673 : }
7674 :
7675 8806803 : return IVAS_ERR_OK;
7676 : }
7677 :
7678 :
7679 : /*---------------------------------------------------------------------*
7680 : * IVAS_REND_GetMasaMetadata( )
7681 : *
7682 : * Get metadata of the estimated MASA frame
7683 : *---------------------------------------------------------------------*/
7684 :
7685 0 : ivas_error IVAS_REND_GetMasaMetadata(
7686 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7687 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to analyzed MASA metadata */
7688 : const IVAS_REND_AudioConfigType inputType /* i : Input type */
7689 : )
7690 : {
7691 0 : if ( hIvasRend == NULL )
7692 : {
7693 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7694 : }
7695 :
7696 : /* Get the metadata handle */
7697 0 : if ( inputType == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
7698 : {
7699 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7700 : }
7701 0 : else if ( inputType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
7702 : {
7703 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7704 : }
7705 0 : else if ( inputType == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
7706 : {
7707 0 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7708 : }
7709 : else
7710 : {
7711 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7712 : }
7713 :
7714 0 : return IVAS_ERR_OK;
7715 : }
7716 :
7717 :
7718 : /*---------------------------------------------------------------------*
7719 : * IVAS_REND_MergeMasaMetadata( )
7720 : *
7721 : * Merge MASA metadata from two formats
7722 : *---------------------------------------------------------------------*/
7723 :
7724 55080 : ivas_error IVAS_REND_MergeMasaMetadata(
7725 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7726 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to merged metadata */
7727 : const IVAS_REND_AudioConfigType inputType1, /* i : Input type 1 */
7728 : const IVAS_REND_AudioConfigType inputType2 /* i : Input type 2 */
7729 : )
7730 : {
7731 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
7732 : float( *inEne1 )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7733 : float( *inEne2 )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7734 :
7735 55080 : if ( hIvasRend == NULL )
7736 : {
7737 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7738 : }
7739 :
7740 : /* Input1 metadata and energy */
7741 55080 : if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
7742 : {
7743 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7744 0 : inEne1 = &( hIvasRend->inputsIsm->hOMasa->energy );
7745 : }
7746 55080 : else if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
7747 : {
7748 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7749 0 : inEne1 = &( hIvasRend->inputsMc->hMcMasa->energy );
7750 : }
7751 55080 : else if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
7752 : {
7753 41400 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7754 41400 : inEne1 = &( hIvasRend->inputsSba->hDirAC->energy );
7755 : }
7756 13680 : else if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7757 : {
7758 13680 : *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7759 13680 : inEne1 = &( hIvasRend->inputsMasa->hMasaPrerend->energy );
7760 : }
7761 : else
7762 : {
7763 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7764 : }
7765 :
7766 : /* Input2 metadata and energy */
7767 55080 : if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
7768 : {
7769 27480 : inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7770 27480 : inEne2 = &( hIvasRend->inputsIsm->hOMasa->energy );
7771 : }
7772 27600 : else if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
7773 : {
7774 13800 : inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7775 13800 : inEne2 = &( hIvasRend->inputsMc->hMcMasa->energy );
7776 : }
7777 13800 : else if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
7778 : {
7779 0 : inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
7780 0 : inEne2 = &( hIvasRend->inputsSba->hDirAC->energy );
7781 : }
7782 13800 : else if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7783 : {
7784 13800 : inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7785 13800 : inEne2 = &( hIvasRend->inputsMasa->hMasaPrerend->energy );
7786 : }
7787 : else
7788 : {
7789 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7790 : }
7791 :
7792 : /* Merge metadata */
7793 55080 : ivas_prerend_merge_masa_metadata( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1, inMeta2, inputType2, *inEne2 );
7794 55080 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA1 ? 0u : 1u;
7795 :
7796 55080 : return IVAS_ERR_OK;
7797 : }
7798 :
7799 :
7800 : /*---------------------------------------------------------------------*
7801 : * IVAS_REND_SetTotalNumberOfObjects( )
7802 : *
7803 : * Set the total number of objects to the first object data
7804 : *---------------------------------------------------------------------*/
7805 :
7806 6502 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
7807 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7808 : const uint16_t total_num_objects /* i : total number of objects */
7809 : )
7810 : {
7811 6502 : if ( hIvasRend == NULL )
7812 : {
7813 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7814 : }
7815 :
7816 6502 : hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
7817 :
7818 6502 : return IVAS_ERR_OK;
7819 : }
7820 :
7821 :
7822 : /*---------------------------------------------------------------------*
7823 : * IVAS_REND_SetIsmMetadataDelay( )
7824 : *
7825 : * Set the Metadata Delay in ms in order to sync with audio delay
7826 : *---------------------------------------------------------------------*/
7827 :
7828 6502 : ivas_error IVAS_REND_SetIsmMetadataDelay(
7829 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7830 : const int16_t sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */
7831 : )
7832 : {
7833 : int16_t i;
7834 :
7835 6502 : if ( hIvasRend == NULL )
7836 : {
7837 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7838 : }
7839 :
7840 32510 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
7841 : {
7842 26008 : hIvasRend->inputsIsm[i].ism_metadata_delay_ms = sync_md_delay;
7843 : }
7844 :
7845 6502 : return IVAS_ERR_OK;
7846 : }
7847 :
7848 :
7849 : /*-------------------------------------------------------------------*
7850 : * getSamplesInternal()
7851 : *
7852 : *
7853 : *-------------------------------------------------------------------*/
7854 :
7855 8806803 : static ivas_error getSamplesInternal(
7856 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7857 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7858 : )
7859 : {
7860 : ivas_error error;
7861 : int16_t numOutChannels;
7862 : int16_t cldfb2tdSampleFact;
7863 :
7864 : /* Validate function arguments */
7865 8806803 : if ( hIvasRend == NULL || outAudio.data == NULL )
7866 : {
7867 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7868 : }
7869 :
7870 8806803 : cldfb2tdSampleFact = ( outAudio.config.is_cldfb ) ? 2 : 1;
7871 :
7872 8806803 : if ( outAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
7873 8806803 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
7874 : {
7875 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
7876 : }
7877 :
7878 8806803 : if ( outAudio.config.numChannels <= 0 || MAX_OUTPUT_CHANNELS < outAudio.config.numChannels )
7879 : {
7880 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7881 : }
7882 :
7883 8806803 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
7884 3860066 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
7885 3792150 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
7886 3791214 : ( outAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( hIvasRend->num_subframes * BINAURAL_RENDERING_FRAME_SIZE_MS ) * hIvasRend->sampleRateOut )
7887 : {
7888 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
7889 : }
7890 :
7891 : /* Check that there is allowed configuration for MASA format output */
7892 8806803 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7893 : {
7894 : int16_t i;
7895 27612 : int16_t numMasaInputs = 0;
7896 27612 : int16_t numOtherInputs = 0;
7897 :
7898 55224 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
7899 : {
7900 27612 : numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7901 : }
7902 :
7903 55224 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
7904 : {
7905 27612 : numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7906 : }
7907 :
7908 55224 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
7909 : {
7910 27612 : numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7911 : }
7912 :
7913 : /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
7914 27612 : numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7915 :
7916 27612 : if ( numMasaInputs == 0 || numOtherInputs == 0 )
7917 : {
7918 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
7919 : }
7920 : }
7921 :
7922 8806803 : if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
7923 : {
7924 0 : return error;
7925 : }
7926 :
7927 8806803 : if ( numOutChannels != outAudio.config.numChannels &&
7928 45168 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
7929 936 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
7930 : {
7931 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7932 : }
7933 :
7934 : /* Clear output buffer */
7935 8806803 : set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
7936 :
7937 8806803 : if ( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
7938 : {
7939 0 : return error;
7940 : }
7941 :
7942 8806803 : if ( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
7943 : {
7944 0 : return error;
7945 : }
7946 :
7947 8806803 : if ( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
7948 : {
7949 0 : return error;
7950 : }
7951 :
7952 8806803 : if ( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
7953 : {
7954 0 : return error;
7955 : }
7956 :
7957 8806803 : return IVAS_ERR_OK;
7958 : }
7959 :
7960 : /*-------------------------------------------------------------------*
7961 : * IVAS_REND_GetSamples()
7962 : *
7963 : *
7964 : *-------------------------------------------------------------------*/
7965 :
7966 8737951 : ivas_error IVAS_REND_GetSamples(
7967 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7968 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7969 : )
7970 : {
7971 : ivas_error error;
7972 :
7973 8737951 : if ( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
7974 : {
7975 0 : return error;
7976 : }
7977 :
7978 8737951 : if ( outAudio.config.is_cldfb == 0 )
7979 : {
7980 : #ifndef DISABLE_LIMITER
7981 : #ifdef DEBUGGING
7982 : hIvasRend->numClipping +=
7983 : #endif
7984 8737951 : limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
7985 : #endif
7986 : }
7987 :
7988 : /* update global cominbed orientation start index */
7989 8737951 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
7990 :
7991 8737951 : return IVAS_ERR_OK;
7992 : }
7993 :
7994 :
7995 : /*-------------------------------------------------------------------*
7996 : * IVAS_REND_GetSplitBinauralBitstream()
7997 : *
7998 : *
7999 : *-------------------------------------------------------------------*/
8000 :
8001 68852 : ivas_error IVAS_REND_GetSplitBinauralBitstream(
8002 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
8003 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
8004 : IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */
8005 : )
8006 : {
8007 : ivas_error error;
8008 : int16_t ch;
8009 : int16_t cldfb_in_flag;
8010 : int16_t i, ro_md_flag;
8011 : int16_t num_poses_orig;
8012 : float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
8013 : float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8014 : float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8015 : IVAS_REND_AudioBufferConfig *pSplitEncBufConfig;
8016 : ISAR_SPLIT_REND_CONFIG_HANDLE pSplitRendConfig;
8017 : ISAR_SPLIT_REND_BITS_DATA bits;
8018 : float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX];
8019 : float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX];
8020 : int16_t j;
8021 :
8022 1170484 : for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i )
8023 : {
8024 18727744 : for ( j = 0; j < CLDFB_NO_COL_MAX; ++j )
8025 : {
8026 17626112 : p_Cldfb_RealBuffer_Binaural[i][j] = Cldfb_RealBuffer_Binaural[i][j];
8027 17626112 : p_Cldfb_ImagBuffer_Binaural[i][j] = Cldfb_ImagBuffer_Binaural[i][j];
8028 : }
8029 : }
8030 :
8031 1170484 : for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ch++ )
8032 : {
8033 1101632 : tmpBinaural[ch] = tmpBinaural_buff[ch];
8034 : }
8035 :
8036 68852 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
8037 68852 : pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config;
8038 68852 : pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config;
8039 :
8040 : /* 0 DoF / No pose correction retains frame size */
8041 68852 : pSplitEncBufConfig->is_cldfb = cldfb_in_flag;
8042 68852 : if ( pSplitRendConfig->dof == 0 || pSplitRendConfig->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
8043 : {
8044 23684 : pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
8045 : }
8046 : /* Pose correction requires 20ms */
8047 : else
8048 : {
8049 45168 : pSplitEncBufConfig->numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
8050 : }
8051 68852 : pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
8052 :
8053 68852 : num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
8054 68852 : ISAR_PRE_REND_GetMultiBinPoseData( pSplitRendConfig,
8055 68852 : &hIvasRend->splitRendWrapper->multiBinPoseData,
8056 : hIvasRend->headRotData.sr_pose_pred_axis );
8057 68852 : assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" );
8058 :
8059 : /* hIvasRend->splitRendEncBuffer contains multi-pose data for BINAURAL_SPLIT_CODED output
8060 : outAudio used later for main pose BINAURAL_SPLIT_PCM output */
8061 68852 : if ( ( error = getSamplesInternal( hIvasRend, hIvasRend->splitRendEncBuffer ) ) != IVAS_ERR_OK )
8062 : {
8063 0 : return error;
8064 : }
8065 :
8066 : /* copy outputs */
8067 68852 : if ( hIvasRend->splitRendEncBuffer.config.is_cldfb == 1 )
8068 : {
8069 15664 : cldfb_in_flag = 1;
8070 15664 : copyBufferToCLDFBarray( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
8071 : }
8072 : else
8073 : {
8074 53188 : cldfb_in_flag = 0;
8075 53188 : copyBufferTo2dArray( hIvasRend->splitRendEncBuffer, tmpBinaural_buff );
8076 : }
8077 :
8078 : /* Encode split rendering bitstream */
8079 68852 : convertBitsBufferToInternalBitsBuff( *hBits, &bits );
8080 :
8081 68852 : ro_md_flag = 0;
8082 250532 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8083 : {
8084 205112 : if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
8085 : {
8086 23432 : ro_md_flag = 1;
8087 23432 : break;
8088 : }
8089 : }
8090 :
8091 68852 : if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper,
8092 : hIvasRend->headRotData.headPositions[0],
8093 : pSplitRendConfig->splitRendBitRate,
8094 : pSplitRendConfig->codec,
8095 68852 : pSplitRendConfig->isar_frame_size_ms,
8096 68852 : pSplitRendConfig->codec_frame_size_ms,
8097 : &bits,
8098 : p_Cldfb_RealBuffer_Binaural,
8099 : p_Cldfb_ImagBuffer_Binaural,
8100 68852 : ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ),
8101 : tmpBinaural,
8102 : 1,
8103 : cldfb_in_flag,
8104 68852 : ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0,
8105 : ro_md_flag ) ) != IVAS_ERR_OK )
8106 : {
8107 0 : return error;
8108 : }
8109 :
8110 68852 : convertInternalBitsBuffToBitsBuffer( hBits, bits );
8111 :
8112 : /* copy over first pose data to outAudio */
8113 68852 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
8114 : {
8115 : /* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */
8116 936 : set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
8117 936 : accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio );
8118 : }
8119 :
8120 68852 : if ( outAudio.config.is_cldfb == 0 )
8121 : {
8122 : #ifndef DISABLE_LIMITER
8123 : #ifdef DEBUGGING
8124 : hIvasRend->numClipping +=
8125 : #endif
8126 67604 : limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
8127 : #endif
8128 : }
8129 :
8130 : /* update global cominbed orientation start index */
8131 68852 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
8132 :
8133 68852 : return IVAS_ERR_OK;
8134 : }
8135 :
8136 :
8137 : /*-------------------------------------------------------------------*
8138 : * IVAS_REND_GetSplitRendBitstreamHeader()
8139 : *
8140 : *
8141 : *-------------------------------------------------------------------*/
8142 :
8143 472 : ivas_error IVAS_REND_GetSplitRendBitstreamHeader(
8144 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8145 : ISAR_SPLIT_REND_CODEC *pCodec, /* o : pointer to codec setting */
8146 : ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o : pointer to pose correction mode */
8147 : int16_t *pCodec_frame_size_ms, /* o : pointer to codec frame size setting */
8148 : int16_t *pIsar_frame_size_ms, /* o : pointer to ISAR frame size setting */
8149 : int16_t *pLc3plusHighRes /* o : pointer to LC3plus High-Res setting */
8150 : )
8151 : {
8152 472 : if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
8153 : {
8154 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8155 : }
8156 :
8157 472 : *pCodec = hIvasRend->hRendererConfig->split_rend_config.codec;
8158 472 : *pCodec_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms;
8159 472 : *pIsar_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms;
8160 472 : *poseCorrection = hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode;
8161 472 : *pLc3plusHighRes = hIvasRend->hRendererConfig->split_rend_config.lc3plus_highres;
8162 :
8163 472 : return IVAS_ERR_OK;
8164 : }
8165 :
8166 :
8167 : /*-------------------------------------------------------------------*
8168 : * IVAS_REND_Close()
8169 : *
8170 : *
8171 : *-------------------------------------------------------------------*/
8172 :
8173 10354 : void IVAS_REND_Close(
8174 : IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
8175 : )
8176 : {
8177 : uint16_t i;
8178 : IVAS_REND_HANDLE hIvasRend;
8179 :
8180 : /* Validate function arguments */
8181 10354 : if ( phIvasRend == NULL || *phIvasRend == NULL )
8182 : {
8183 0 : return;
8184 : }
8185 10354 : hIvasRend = *phIvasRend;
8186 :
8187 10354 : if ( hIvasRend->efapOutWrapper.hEfap != NULL )
8188 : {
8189 7326 : efap_free_data( &hIvasRend->efapOutWrapper.hEfap );
8190 : }
8191 :
8192 : /* clear inputs */
8193 51770 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8194 : {
8195 41416 : clearInputIsm( &hIvasRend->inputsIsm[i] );
8196 : }
8197 20708 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
8198 : {
8199 10354 : clearInputMc( &hIvasRend->inputsMc[i] );
8200 : }
8201 20708 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
8202 : {
8203 10354 : clearInputSba( &hIvasRend->inputsSba[i] );
8204 10354 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
8205 : }
8206 20708 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
8207 : {
8208 10354 : clearInputMasa( &hIvasRend->inputsMasa[i] );
8209 : }
8210 :
8211 : /* clear Config. Renderer */
8212 10354 : ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
8213 :
8214 10354 : ivas_limiter_close( &hIvasRend->hLimiter );
8215 :
8216 : /* Split binaural rendering */
8217 10354 : if ( hIvasRend->splitRendWrapper != NULL )
8218 : {
8219 472 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
8220 472 : free( hIvasRend->splitRendWrapper );
8221 472 : hIvasRend->splitRendWrapper = NULL;
8222 : }
8223 :
8224 10354 : closeHeadRotation( hIvasRend );
8225 :
8226 10354 : ivas_external_orientation_close( &hIvasRend->hExternalOrientationData );
8227 10354 : ivas_combined_orientation_close( &hIvasRend->hCombinedOrientationData );
8228 :
8229 : /* Fastconv HRTF memories */
8230 10354 : ivas_binaural_hrtf_close( &hIvasRend->hHrtfs.hHrtfFastConv );
8231 :
8232 : /* Parametric binauralizer HRTF filters */
8233 10354 : ivas_HRTF_binary_close( &( hIvasRend->hHrtfs.hHrtfTD ) );
8234 10354 : ivas_HRTF_CRend_binary_close( &( hIvasRend->hHrtfs.hHrtfCrend ) );
8235 10354 : ivas_HRTF_fastconv_binary_close( &( hIvasRend->hHrtfs.hHrtfFastConv ) );
8236 10354 : ivas_HRTF_parambin_binary_close( &( hIvasRend->hHrtfs.hHrtfParambin ) );
8237 10354 : ivas_HRTF_statistics_close( &( hIvasRend->hHrtfs.hHrtfStatistics ) );
8238 :
8239 10354 : free( hIvasRend );
8240 10354 : *phIvasRend = NULL;
8241 :
8242 10354 : return;
8243 : }
8244 :
8245 :
8246 : /*-------------------------------------------------------------------*
8247 : * IVAS_REND_openCldfb()
8248 : *
8249 : *
8250 : *-------------------------------------------------------------------*/
8251 :
8252 8 : ivas_error IVAS_REND_openCldfb(
8253 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
8254 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS],
8255 : const int16_t num_in_chs,
8256 : const int16_t num_out_chs,
8257 : const int32_t output_Fs )
8258 : {
8259 : int16_t n;
8260 : ivas_error error;
8261 :
8262 136 : for ( n = 0; n < num_in_chs; n++ )
8263 : {
8264 128 : if ( ( error = openCldfb( &( cldfbAna[n] ), CLDFB_ANALYSIS, output_Fs, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
8265 : {
8266 0 : return error;
8267 : }
8268 : }
8269 8 : for ( ; n < RENDERER_MAX_INPUT_CHANNELS; n++ )
8270 : {
8271 0 : cldfbAna[n] = NULL;
8272 : }
8273 :
8274 24 : for ( n = 0; n < num_out_chs; n++ )
8275 : {
8276 16 : if ( ( error = openCldfb( &( cldfbSyn[n] ), CLDFB_SYNTHESIS, output_Fs, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
8277 : {
8278 0 : return error;
8279 : }
8280 : }
8281 120 : for ( ; n < RENDERER_MAX_OUTPUT_CHANNELS; n++ )
8282 : {
8283 112 : cldfbSyn[n] = NULL;
8284 : }
8285 :
8286 8 : return IVAS_ERR_OK;
8287 : }
8288 :
8289 :
8290 : /*-------------------------------------------------------------------*
8291 : * IVAS_REND_closeCldfb()
8292 : *
8293 : *
8294 : *-------------------------------------------------------------------*/
8295 :
8296 8 : void IVAS_REND_closeCldfb(
8297 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
8298 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS] )
8299 : {
8300 : int16_t n;
8301 :
8302 136 : for ( n = 0; n < RENDERER_MAX_INPUT_CHANNELS; n++ )
8303 : {
8304 128 : if ( cldfbAna[n] != NULL )
8305 : {
8306 128 : deleteCldfb( &( cldfbAna[n] ) );
8307 128 : cldfbAna[n] = NULL;
8308 : }
8309 : }
8310 :
8311 136 : for ( n = 0; n < RENDERER_MAX_OUTPUT_CHANNELS; n++ )
8312 : {
8313 128 : if ( cldfbSyn[n] != NULL )
8314 : {
8315 16 : deleteCldfb( &( cldfbSyn[n] ) );
8316 16 : cldfbSyn[n] = NULL;
8317 : }
8318 : }
8319 :
8320 8 : return;
8321 : }
8322 :
8323 :
8324 : /*-------------------------------------------------------------------*
8325 : * IVAS_REND_cldfbSynthesis_wrapper()
8326 : *
8327 : *
8328 : *-------------------------------------------------------------------*/
8329 :
8330 317440 : void IVAS_REND_cldfbAnalysis_ts_wrapper(
8331 : const float *timeIn, /* i : time buffer */
8332 : float realBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : real value buffer */
8333 : float imagBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : imag value buffer */
8334 : const int16_t samplesToProcess, /* i : samples to process */
8335 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb /* i : filterbank state */
8336 : )
8337 : {
8338 317440 : cldfbAnalysis_ts( timeIn, realBuffer, imagBuffer, samplesToProcess, h_cldfb );
8339 :
8340 317440 : return;
8341 : }
8342 :
8343 :
8344 : /*-------------------------------------------------------------------*
8345 : * IVAS_REND_cldfbSynthesis_wrapper()
8346 : *
8347 : *
8348 : *-------------------------------------------------------------------*/
8349 :
8350 2496 : void IVAS_REND_cldfbSynthesis_wrapper(
8351 : float **realBuffer, /* i : real values */
8352 : float **imagBuffer, /* i : imag values */
8353 : float *timeOut, /* o : output time domain samples */
8354 : const int16_t samplesToProcess, /* i : number of processed samples */
8355 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb /* i : filter bank state */
8356 : )
8357 : {
8358 2496 : cldfbSynthesis( realBuffer, imagBuffer, timeOut, samplesToProcess, h_cldfb );
8359 :
8360 2496 : return;
8361 : }
8362 :
8363 :
8364 : #ifdef DEBUGGING
8365 : /*-------------------------------------------------------------------*
8366 : * IVAS_REND_GetNoCLipping()
8367 : *
8368 : *
8369 : *-------------------------------------------------------------------*/
8370 :
8371 : int32_t IVAS_REND_GetNoCLipping(
8372 : IVAS_REND_CONST_HANDLE hIvasRend )
8373 : {
8374 : return hIvasRend->numClipping;
8375 : }
8376 :
8377 : int32_t IVAS_REND_GetCntFramesLimited(
8378 : IVAS_REND_CONST_HANDLE hIvasRend )
8379 : {
8380 : if ( hIvasRend->hLimiter == NULL )
8381 : {
8382 : return 0;
8383 : }
8384 :
8385 : return hIvasRend->hLimiter->cnt_frames_limited;
8386 : }
8387 : #endif
8388 :
8389 :
8390 : /*---------------------------------------------------------------------*
8391 : * IVAS_REND_GetHrtfTdHandle( )
8392 : *
8393 : *
8394 : *---------------------------------------------------------------------*/
8395 :
8396 0 : ivas_error IVAS_REND_GetHrtfTdHandle(
8397 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8398 : IVAS_DEC_HRTF_TD_HANDLE **hHrtfTD /* o : TD rend. HRTF handle */
8399 : )
8400 : {
8401 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfTD == NULL )
8402 : {
8403 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8404 : }
8405 :
8406 0 : *hHrtfTD = &hIvasRend->hHrtfs.hHrtfTD;
8407 :
8408 0 : return IVAS_ERR_OK;
8409 : }
8410 :
8411 :
8412 : /*---------------------------------------------------------------------*
8413 : * IVAS_REND_GetHrtfCRendHandle( )
8414 : *
8415 : *
8416 : *---------------------------------------------------------------------*/
8417 :
8418 0 : ivas_error IVAS_REND_GetHrtfCRendHandle(
8419 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8420 : IVAS_DEC_HRTF_CREND_HANDLE **hHrtfCrend /* o : Crend HRTF handle */
8421 : )
8422 : {
8423 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfCrend == NULL )
8424 : {
8425 0 : return IVAS_ERR_WRONG_PARAMS;
8426 : }
8427 :
8428 0 : *hHrtfCrend = &hIvasRend->hHrtfs.hHrtfCrend;
8429 :
8430 0 : return IVAS_ERR_OK;
8431 : }
8432 :
8433 :
8434 : /*---------------------------------------------------------------------*
8435 : * IVAS_REND_GetHrtfFastConvHandle( )
8436 : *
8437 : *
8438 : *---------------------------------------------------------------------*/
8439 :
8440 0 : ivas_error IVAS_REND_GetHrtfFastConvHandle(
8441 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8442 : IVAS_DEC_HRTF_FASTCONV_HANDLE **hHrtfFastConv /* o : FASTCONV HRTF handle */
8443 : )
8444 : {
8445 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfFastConv == NULL )
8446 : {
8447 0 : return IVAS_ERR_WRONG_PARAMS;
8448 : }
8449 :
8450 0 : *hHrtfFastConv = &hIvasRend->hHrtfs.hHrtfFastConv;
8451 :
8452 0 : return IVAS_ERR_OK;
8453 : }
8454 :
8455 :
8456 : /*---------------------------------------------------------------------*
8457 : * IVAS_REND_GetHrtfParamBinHandle( )
8458 : *
8459 : *
8460 : *---------------------------------------------------------------------*/
8461 :
8462 0 : ivas_error IVAS_REND_GetHrtfParamBinHandle(
8463 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8464 : IVAS_DEC_HRTF_PARAMBIN_HANDLE **hHrtfParambin /* o : Parametric binauralizer HRTF handle */
8465 : )
8466 : {
8467 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfParambin == NULL )
8468 : {
8469 0 : return IVAS_ERR_WRONG_PARAMS;
8470 : }
8471 :
8472 0 : *hHrtfParambin = &hIvasRend->hHrtfs.hHrtfParambin;
8473 :
8474 0 : return IVAS_ERR_OK;
8475 : }
8476 :
8477 : /*---------------------------------------------------------------------*
8478 : * IVAS_REND_GetHrtfStatisticsHandle( )
8479 : *
8480 : *
8481 : *---------------------------------------------------------------------*/
8482 :
8483 0 : ivas_error IVAS_REND_GetHrtfStatisticsHandle(
8484 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8485 : IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */
8486 : )
8487 : {
8488 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfStatistics == NULL )
8489 : {
8490 0 : return IVAS_ERR_WRONG_PARAMS;
8491 : }
8492 :
8493 0 : *hHrtfStatistics = &hIvasRend->hHrtfs.hHrtfStatistics;
8494 :
8495 0 : return IVAS_ERR_OK;
8496 : }
8497 :
8498 1200 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
8499 : input_masa *inputMasa )
8500 : {
8501 : int16_t nchan_out_woLFE;
8502 : int16_t nchan_transport;
8503 : uint16_t i, j, k;
8504 : float ls_azimuth[MAX_OUTPUT_CHANNELS];
8505 : float ls_elevation[MAX_OUTPUT_CHANNELS];
8506 : int32_t output_Fs;
8507 : ivas_error error;
8508 : DIRAC_REND_HANDLE hDirACRend;
8509 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
8510 :
8511 1200 : error = IVAS_ERR_OK;
8512 :
8513 1200 : hDirACRend = NULL;
8514 1200 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
8515 :
8516 1200 : hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
8517 :
8518 : /*-----------------------------------------------------------------*
8519 : * prepare library opening
8520 : *-----------------------------------------------------------------*/
8521 :
8522 1200 : if ( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
8523 : {
8524 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
8525 : }
8526 :
8527 1200 : nchan_transport = inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA2 ? 2 : 1;
8528 :
8529 : /*-----------------------------------------------------------------*
8530 : * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
8531 : *-----------------------------------------------------------------*/
8532 :
8533 1200 : ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
8534 :
8535 1200 : if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
8536 : {
8537 : /* Copy from ivas_ls_custom_setup */
8538 180 : hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
8539 180 : hDirACRend->hOutSetup.ls_azimuth = inputMasa->base.ctx.pCustomLsOut->ls_azimuth;
8540 180 : hDirACRend->hOutSetup.ls_elevation = inputMasa->base.ctx.pCustomLsOut->ls_elevation;
8541 :
8542 180 : hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
8543 180 : hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
8544 :
8545 180 : hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
8546 180 : hDirACRend->hOutSetup.is_planar_setup = (int8_t) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
8547 : }
8548 :
8549 1200 : nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
8550 :
8551 1200 : if ( hDirACRend->hOutSetup.ls_azimuth != NULL && hDirACRend->hOutSetup.ls_elevation != NULL )
8552 : {
8553 780 : mvr2r( hDirACRend->hOutSetup.ls_azimuth, ls_azimuth, nchan_out_woLFE );
8554 780 : mvr2r( hDirACRend->hOutSetup.ls_elevation, ls_elevation, nchan_out_woLFE );
8555 : }
8556 :
8557 1200 : if ( hDirACRend->hOutSetup.ambisonics_order == -1 )
8558 : {
8559 840 : hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
8560 840 : if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_MONO || hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_STEREO )
8561 : {
8562 60 : hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
8563 : }
8564 : }
8565 360 : else if ( hDirACRend->hOutSetup.ambisonics_order >= SBA_FOA_ORDER )
8566 : {
8567 360 : mvr2r( ls_azimuth_4d4, ls_azimuth, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
8568 360 : mvr2r( ls_elevation_4d4, ls_elevation, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
8569 : }
8570 :
8571 : /*-----------------------------------------------------------------*
8572 : * set input parameters
8573 : *-----------------------------------------------------------------*/
8574 :
8575 1200 : if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_MONO )
8576 : {
8577 60 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
8578 60 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
8579 60 : nchan_out_woLFE = 1;
8580 : }
8581 1140 : else if ( hDirACRend->hOutSetup.is_loudspeaker_setup )
8582 : {
8583 780 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
8584 780 : hDirACRend->panningConf = DIRAC_PANNING_VBAP;
8585 : }
8586 360 : else if ( !hDirACRend->hOutSetup.is_loudspeaker_setup && nchan_transport > 1 )
8587 : {
8588 180 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
8589 180 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
8590 : }
8591 : else
8592 : {
8593 180 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
8594 180 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
8595 : }
8596 :
8597 1200 : if ( ( hDirACRend->frequency_axis = (float *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( float ) ) ) == NULL )
8598 : {
8599 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8600 : }
8601 1200 : set_f( hDirACRend->frequency_axis, 0.0f, hSpatParamRendCom->num_freq_bands );
8602 :
8603 1200 : ivas_dirac_dec_get_frequency_axis( hDirACRend->frequency_axis, output_Fs, hSpatParamRendCom->num_freq_bands );
8604 :
8605 1200 : if ( hDirACRend->panningConf == DIRAC_PANNING_HOA3 && nchan_transport == 2 )
8606 : {
8607 240 : if ( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
8608 : {
8609 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8610 : }
8611 240 : ivas_masa_init_stereotype_detection( hDirACRend->masa_stereo_type_detect );
8612 : }
8613 : else
8614 : {
8615 960 : hDirACRend->masa_stereo_type_detect = NULL;
8616 : }
8617 :
8618 1200 : hSpatParamRendCom->numIsmDirections = 0;
8619 :
8620 : /*-----------------------------------------------------------------*
8621 : * (re)configure sub-modules
8622 : *-----------------------------------------------------------------*/
8623 :
8624 : /* prototype signal computation */
8625 : /* allocate output setup related arrays */
8626 1200 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_LS )
8627 : {
8628 : /* Directional and diffuses components in output LS format */
8629 780 : hDirACRend->num_outputs_diff = nchan_out_woLFE;
8630 780 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
8631 : }
8632 420 : else if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8633 : {
8634 : /* Directional and diffuses components in SHD */
8635 : /* Diffuseness components up to 1st order */
8636 180 : hDirACRend->num_outputs_diff = ( min( hDirACRend->hOutSetup.ambisonics_order, 1 ) + 1 ) * ( min( hDirACRend->hOutSetup.ambisonics_order, 1 ) + 1 );
8637 180 : hDirACRend->num_outputs_dir = ivas_sba_get_nchan( hDirACRend->hOutSetup.ambisonics_order, 0 );
8638 : }
8639 240 : else if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD )
8640 : {
8641 180 : hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
8642 180 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
8643 : }
8644 60 : else if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_MONO )
8645 : {
8646 60 : hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
8647 60 : hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
8648 : }
8649 : else
8650 : {
8651 0 : assert( 0 && "DirAC: not existing synthesis methods!" );
8652 : }
8653 :
8654 1200 : if ( ( hDirACRend->proto_index_dir = (int16_t *) malloc( sizeof( int16_t ) * hDirACRend->num_outputs_dir ) ) == NULL )
8655 : {
8656 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8657 : }
8658 :
8659 1200 : if ( ( hDirACRend->proto_index_diff = (int16_t *) malloc( sizeof( int16_t ) * hDirACRend->num_outputs_diff ) ) == NULL )
8660 : {
8661 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8662 : }
8663 :
8664 1200 : set_s( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
8665 1200 : set_s( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
8666 :
8667 1200 : hDirACRend->sba_map_tc = sba_map_tc;
8668 :
8669 1200 : if ( nchan_transport == 1 )
8670 : {
8671 570 : hDirACRend->num_protos_ambi = 1;
8672 570 : hDirACRend->num_protos_dir = 1;
8673 570 : hDirACRend->num_protos_diff = 1;
8674 : }
8675 630 : else if ( nchan_transport == 2 )
8676 : {
8677 630 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8678 : {
8679 0 : hDirACRend->num_protos_ambi = 2;
8680 0 : hDirACRend->num_protos_diff = 1;
8681 0 : hDirACRend->num_protos_dir = 2;
8682 0 : hDirACRend->proto_index_dir[1] = 1;
8683 : }
8684 630 : else if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_MONO )
8685 : {
8686 : /* Following the foa rendering for code compatibility */
8687 60 : hDirACRend->num_protos_ambi = 2;
8688 60 : hDirACRend->num_protos_dir = 2;
8689 60 : hDirACRend->num_protos_diff = 3;
8690 60 : hDirACRend->proto_index_dir[0] = 0;
8691 60 : hDirACRend->proto_index_diff[0] = 0;
8692 : }
8693 : else
8694 : {
8695 570 : hDirACRend->num_protos_ambi = 2;
8696 570 : hDirACRend->num_protos_diff = 3;
8697 :
8698 5430 : for ( k = 0; k < hDirACRend->num_outputs_diff; k++ )
8699 : {
8700 4860 : if ( ls_azimuth[k] > 0.0f )
8701 : {
8702 2280 : hDirACRend->proto_index_diff[k] = 1;
8703 : }
8704 2580 : else if ( ls_azimuth[k] < 0.0f )
8705 : {
8706 2190 : hDirACRend->proto_index_diff[k] = 2;
8707 : }
8708 : else
8709 : {
8710 390 : hDirACRend->proto_index_diff[k] = 0;
8711 : }
8712 : }
8713 :
8714 570 : if ( hDirACRend->hOutSetup.is_loudspeaker_setup )
8715 : {
8716 390 : hDirACRend->num_protos_dir = 3;
8717 390 : mvs2s( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
8718 : }
8719 : else
8720 : {
8721 180 : hDirACRend->num_protos_dir = 2;
8722 180 : hDirACRend->proto_index_dir[1] = 1;
8723 : }
8724 : }
8725 : }
8726 :
8727 : /* direct/diffuse responses */
8728 1200 : if ( ( hDirACRend->diffuse_response_function = (float *) malloc( sizeof( float ) * hDirACRend->num_outputs_dir ) ) == NULL )
8729 : {
8730 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8731 : }
8732 :
8733 1200 : if ( ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_LS ) || ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD ) || ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_MONO ) )
8734 : {
8735 1020 : initDiffuseResponses( hDirACRend->diffuse_response_function, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
8736 1020 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
8737 : }
8738 : else
8739 : {
8740 180 : initDiffuseResponses( hDirACRend->diffuse_response_function, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
8741 180 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
8742 : }
8743 :
8744 1200 : hDirACRend->hoa_encoder = NULL;
8745 1200 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD )
8746 : {
8747 180 : if ( ( hDirACRend->hoa_encoder = (float *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( float ) ) ) == NULL )
8748 : {
8749 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8750 : }
8751 :
8752 180 : set_f( hDirACRend->hoa_encoder, 0.0f, nchan_out_woLFE * hDirACRend->num_outputs_diff );
8753 180 : compute_hoa_encoder_mtx( ls_azimuth, ls_elevation, hDirACRend->hoa_encoder, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
8754 : }
8755 :
8756 : /* VBAP */
8757 1200 : inputMasa->hMasaExtRend->hVBAPdata = NULL;
8758 :
8759 1200 : if ( hDirACRend->panningConf == DIRAC_PANNING_VBAP )
8760 : {
8761 780 : if ( ( error = vbap_init_data( &( inputMasa->hMasaExtRend->hVBAPdata ), ls_azimuth, ls_elevation, nchan_out_woLFE, MASA_FORMAT ) ) != IVAS_ERR_OK )
8762 : {
8763 0 : return error;
8764 : }
8765 : }
8766 :
8767 : /* HOA panning/dec */
8768 1200 : hDirACRend->hoa_decoder = NULL;
8769 1200 : if ( hDirACRend->panningConf == DIRAC_PANNING_HOA3 )
8770 : {
8771 420 : if ( hDirACRend->hOutSetup.is_loudspeaker_setup )
8772 : {
8773 60 : if ( ( error = ivas_sba_get_hoa_dec_matrix( hDirACRend->hOutSetup, &inputMasa->hMasaExtRend->hoa_dec_mtx, hDirACRend->hOutSetup.ambisonics_order ) ) != IVAS_ERR_OK )
8774 : {
8775 0 : return error;
8776 : }
8777 :
8778 60 : hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
8779 : }
8780 : }
8781 :
8782 : /* decorrelation */
8783 1200 : hDirACRend->proto_signal_decorr_on = 1;
8784 1200 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_MONO )
8785 : {
8786 60 : hDirACRend->proto_signal_decorr_on = 0;
8787 : }
8788 :
8789 1200 : if ( hDirACRend->proto_signal_decorr_on )
8790 : {
8791 1140 : if ( ( error = ivas_dirac_dec_decorr_open( &( hDirACRend->h_freq_domain_decorr_ap_params ),
8792 1140 : &( hDirACRend->h_freq_domain_decorr_ap_state ),
8793 1140 : hSpatParamRendCom->num_freq_bands,
8794 1140 : hDirACRend->num_outputs_diff,
8795 1140 : hDirACRend->num_protos_diff,
8796 : hDirACRend->synthesisConf,
8797 : hDirACRend->frequency_axis,
8798 : nchan_transport,
8799 : output_Fs ) ) != IVAS_ERR_OK )
8800 : {
8801 0 : return error;
8802 : }
8803 : }
8804 :
8805 : /* output synthesis */
8806 1200 : if ( ( ivas_dirac_dec_output_synthesis_open( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ) != IVAS_ERR_OK )
8807 : {
8808 0 : return error;
8809 : }
8810 1200 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
8811 :
8812 1200 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD || hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8813 : {
8814 360 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
8815 : }
8816 :
8817 : /*-----------------------------------------------------------------*
8818 : * memory allocation
8819 : *-----------------------------------------------------------------*/
8820 :
8821 1200 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8822 : {
8823 180 : hDirACRend->proto_frame_f = NULL;
8824 : }
8825 : else
8826 : {
8827 1020 : if ( ( hDirACRend->proto_frame_f = (float *) malloc( sizeof( float ) * 2 * hDirACRend->num_protos_diff * hSpatParamRendCom->num_freq_bands ) ) == NULL )
8828 : {
8829 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8830 : }
8831 : }
8832 :
8833 :
8834 1200 : hDirACRend->buffer_energy = NULL;
8835 :
8836 4800 : for ( i = 0; i < DIRAC_NUM_DIMS; i++ )
8837 : {
8838 118800 : for ( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
8839 : {
8840 115200 : hDirACRend->buffer_intensity_real[i][j] = NULL;
8841 : }
8842 : }
8843 :
8844 : /* output synthesis */
8845 1200 : ivas_dirac_dec_output_synthesis_init( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
8846 :
8847 : /* Allocate stack memory */
8848 1200 : if ( ( error = ivas_dirac_alloc_mem( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ) != IVAS_ERR_OK )
8849 : {
8850 0 : return error;
8851 : }
8852 :
8853 1200 : inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
8854 :
8855 1200 : return error;
8856 : }
8857 :
8858 1336 : static ivas_error ivas_masa_ext_rend_parambin_init(
8859 : input_masa *inputMasa, /* i/o: MASA external renderer structure */
8860 : const RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration data handle */
8861 : HRTFS_STATISTICS_HANDLE hHrtfStatistics /* i : HRTF statistics */
8862 : )
8863 : {
8864 : DIRAC_DEC_BIN_HANDLE hDiracDecBin;
8865 : HRTFS_PARAMBIN_HANDLE *phHrtfParambin;
8866 : int16_t nBins;
8867 : int32_t output_Fs;
8868 : RENDERER_TYPE renderer_type;
8869 : int16_t j, k, bin;
8870 : int16_t num_poses;
8871 : float binCenterFreq, tmpFloat;
8872 : ivas_error error;
8873 : float frequency_axis[CLDFB_NO_CHANNELS_MAX];
8874 : int16_t pos_idx;
8875 : const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics;
8876 :
8877 1336 : error = IVAS_ERR_OK;
8878 :
8879 1336 : phHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
8880 :
8881 : /* Set common variables and defaults */
8882 1336 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
8883 1336 : nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
8884 1336 : renderer_type = inputMasa->hMasaExtRend->renderer_type;
8885 :
8886 1336 : num_poses = 1;
8887 1336 : if ( inputMasa->base.ctx.pSplitRendWrapper != NULL )
8888 : {
8889 136 : num_poses = inputMasa->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
8890 : }
8891 :
8892 3088 : for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
8893 : {
8894 1752 : hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin[pos_idx];
8895 :
8896 : /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
8897 1752 : if ( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
8898 : {
8899 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
8900 : }
8901 :
8902 1752 : hDiracDecBin->hTdDecorr = NULL;
8903 1752 : hDiracDecBin->hReverb = NULL;
8904 1752 : hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
8905 1752 : hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
8906 1752 : hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
8907 1752 : hDiracDecBin->useTdDecorr = 0; /* Always use frequency domain decorrelator in external renderer */
8908 :
8909 5256 : for ( j = 0; j < BINAURAL_CHANNELS; j++ )
8910 : {
8911 24528 : for ( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
8912 : {
8913 21024 : set_zero( hDiracDecBin->processMtxRe[j][k], nBins );
8914 21024 : set_zero( hDiracDecBin->processMtxIm[j][k], nBins );
8915 : }
8916 :
8917 10512 : for ( k = 0; k < BINAURAL_CHANNELS; k++ )
8918 : {
8919 7008 : set_zero( hDiracDecBin->processMtxDecRe[j][k], nBins );
8920 7008 : set_zero( hDiracDecBin->processMtxDecIm[j][k], nBins );
8921 : }
8922 3504 : set_zero( hDiracDecBin->ChEnePrev[j], nBins );
8923 3504 : set_zero( hDiracDecBin->ChEneOutPrev[j], nBins );
8924 : }
8925 1752 : set_zero( hDiracDecBin->ChCrossRePrev, nBins );
8926 1752 : set_zero( hDiracDecBin->ChCrossImPrev, nBins );
8927 1752 : set_zero( hDiracDecBin->ChCrossReOutPrev, nBins );
8928 1752 : set_zero( hDiracDecBin->ChCrossImOutPrev, nBins );
8929 1752 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
8930 :
8931 82872 : for ( bin = 0; bin < nBins; bin++ )
8932 : {
8933 81120 : binCenterFreq = ( (float) bin + 0.5f ) / (float) nBins * ( (float) output_Fs / 2.0f );
8934 : /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
8935 81120 : tmpFloat = max( 0.0f, 1.0f - binCenterFreq / 2700.0f );
8936 81120 : hDiracDecBin->diffuseFieldCoherence[bin] = tmpFloat * sinf( binCenterFreq * EVS_PI / 550.0f ) / ( binCenterFreq * EVS_PI / 550.0f );
8937 : }
8938 :
8939 : /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
8940 1752 : set_zero( hDiracDecBin->diffuseFieldCoherenceX, BINAURAL_COHERENCE_DIFFERENCE_BINS );
8941 1752 : set_zero( hDiracDecBin->diffuseFieldCoherenceY, BINAURAL_COHERENCE_DIFFERENCE_BINS );
8942 1752 : set_zero( hDiracDecBin->diffuseFieldCoherenceZ, BINAURAL_COHERENCE_DIFFERENCE_BINS );
8943 :
8944 1752 : if ( renderer_type == RENDERER_BINAURAL_PARAMETRIC ) /* Indication of binaural rendering without room effect */
8945 : {
8946 792 : set_f( hDiracDecBin->earlyPartEneCorrection, 1.0f, CLDFB_NO_CHANNELS_MAX );
8947 792 : hDiracDecBin->hReverb = NULL;
8948 : }
8949 960 : else if ( renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM ) /* Indication of binaural rendering with room effect */
8950 : {
8951 840 : if ( *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
8952 : {
8953 240 : mvr2r( ( *phHrtfParambin )->parametricEarlyPartEneCorrection, hDiracDecBin->earlyPartEneCorrection, nBins );
8954 240 : pRoomAcoustics = NULL;
8955 : }
8956 : else
8957 : {
8958 600 : set_f( hDiracDecBin->earlyPartEneCorrection, 1.0f, CLDFB_NO_CHANNELS_MAX );
8959 600 : pRoomAcoustics = &( hRendCfg->roomAcoustics );
8960 : }
8961 :
8962 840 : if ( hDiracDecBin->hReverb == NULL && pos_idx == 0 ) /* open reverb only for the main direction */
8963 : {
8964 840 : if ( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb,
8965 : hHrtfStatistics,
8966 : nBins,
8967 : CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
8968 : pRoomAcoustics,
8969 : output_Fs,
8970 840 : ( *phHrtfParambin )->parametricReverberationTimes,
8971 840 : ( *phHrtfParambin )->parametricReverberationEneCorrections,
8972 840 : hDiracDecBin->earlyPartEneCorrection ) ) != IVAS_ERR_OK )
8973 : {
8974 0 : return error;
8975 : }
8976 : }
8977 : }
8978 120 : else if ( renderer_type == RENDERER_STEREO_PARAMETRIC )
8979 : {
8980 120 : set_f( hDiracDecBin->earlyPartEneCorrection, 1.0f, CLDFB_NO_CHANNELS_MAX );
8981 120 : hDiracDecBin->hReverb = NULL;
8982 120 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
8983 : }
8984 : else /* Not valid renderer type for this renderer */
8985 : {
8986 0 : assert( false );
8987 : }
8988 :
8989 1752 : if ( pos_idx == 0 ) /* open decorrelator only for the main direction */
8990 : {
8991 : /* Always open frequency domain decorrelator */
8992 1336 : ivas_dirac_dec_get_frequency_axis( frequency_axis, output_Fs, nBins );
8993 1336 : if ( ( error = ivas_dirac_dec_decorr_open( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
8994 1336 : &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
8995 : nBins,
8996 : BINAURAL_CHANNELS,
8997 : BINAURAL_CHANNELS,
8998 : DIRAC_SYNTHESIS_PSD_LS,
8999 : frequency_axis,
9000 : BINAURAL_CHANNELS,
9001 : output_Fs ) ) != IVAS_ERR_OK )
9002 : {
9003 0 : return error;
9004 : }
9005 : }
9006 :
9007 : /* External renderer uses constant regularization factor */
9008 1752 : hDiracDecBin->reqularizationFactor = 0.4f;
9009 :
9010 1752 : hDiracDecBin->phHrtfParambin = phHrtfParambin;
9011 :
9012 1752 : inputMasa->hMasaExtRend->hDiracDecBin[pos_idx] = hDiracDecBin;
9013 : }
9014 :
9015 1336 : return error;
9016 : }
9017 :
9018 2596 : static ivas_error initMasaExtRenderer(
9019 : input_masa *inputMasa,
9020 : const AUDIO_CONFIG outConfig,
9021 : const RENDER_CONFIG_DATA *hRendCfg,
9022 : hrtf_handles *hrtfs )
9023 : {
9024 : int16_t i;
9025 : ivas_error error;
9026 : MASA_EXT_REND_HANDLE hMasaExtRend;
9027 :
9028 2596 : error = IVAS_ERR_OK;
9029 :
9030 2596 : if ( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
9031 : {
9032 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
9033 : }
9034 :
9035 2596 : inputMasa->hMasaExtRend = hMasaExtRend;
9036 :
9037 : /* Default init */
9038 2596 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
9039 2596 : hMasaExtRend->hDirACRend = NULL;
9040 2596 : hMasaExtRend->hSpatParamRendCom = NULL;
9041 23364 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
9042 : {
9043 20768 : hMasaExtRend->hDiracDecBin[i] = NULL;
9044 : }
9045 2596 : hMasaExtRend->hReverb = NULL;
9046 2596 : hMasaExtRend->hHrtfParambin = &hrtfs->hHrtfParambin;
9047 2596 : hMasaExtRend->hVBAPdata = NULL;
9048 2596 : hMasaExtRend->hoa_dec_mtx = NULL;
9049 :
9050 2596 : if ( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ) != IVAS_ERR_OK )
9051 : {
9052 0 : return error;
9053 : }
9054 :
9055 2596 : if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
9056 : {
9057 180 : hMasaExtRend->nchan_output = inputMasa->base.ctx.pCustomLsOut->num_spk + inputMasa->base.ctx.pCustomLsOut->num_lfe;
9058 : }
9059 2416 : else if ( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ) != IVAS_ERR_OK )
9060 : {
9061 0 : return error;
9062 : }
9063 :
9064 2596 : switch ( outConfig )
9065 : {
9066 120 : case IVAS_AUDIO_CONFIG_MONO:
9067 120 : if ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA2 )
9068 : {
9069 60 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
9070 : }
9071 : else
9072 : {
9073 : /* 1TC MASA to mono does not need rendering. */
9074 60 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
9075 : }
9076 120 : break;
9077 :
9078 120 : case IVAS_AUDIO_CONFIG_STEREO:
9079 120 : hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
9080 120 : break;
9081 :
9082 1140 : case IVAS_AUDIO_CONFIG_5_1:
9083 : case IVAS_AUDIO_CONFIG_7_1:
9084 : case IVAS_AUDIO_CONFIG_5_1_2:
9085 : case IVAS_AUDIO_CONFIG_5_1_4:
9086 : case IVAS_AUDIO_CONFIG_7_1_4:
9087 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
9088 : case IVAS_AUDIO_CONFIG_FOA:
9089 : case IVAS_AUDIO_CONFIG_HOA2:
9090 : case IVAS_AUDIO_CONFIG_HOA3:
9091 1140 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
9092 1140 : break;
9093 :
9094 376 : case IVAS_AUDIO_CONFIG_BINAURAL:
9095 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
9096 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
9097 376 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
9098 376 : break;
9099 :
9100 840 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
9101 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
9102 840 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
9103 840 : break;
9104 :
9105 0 : default:
9106 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
9107 : }
9108 :
9109 2596 : if ( hMasaExtRend->renderer_type != RENDERER_DISABLE )
9110 : {
9111 : int16_t subframe;
9112 :
9113 2536 : if ( ( error = ivas_spat_hSpatParamRendCom_config( &hMasaExtRend->hSpatParamRendCom, DIRAC_OPEN, 0, MASA_FORMAT, MC_MODE_NONE, *( inputMasa->base.ctx.pOutSampleRate ), 0, 1 ) ) != IVAS_ERR_OK )
9114 : {
9115 0 : return error;
9116 : }
9117 :
9118 : /* Simple population of the metadata index map as no adaptation is present */
9119 2536 : set_s( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
9120 12680 : for ( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
9121 : {
9122 10144 : hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
9123 : }
9124 2536 : hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
9125 : }
9126 :
9127 2596 : if ( hMasaExtRend->renderer_type == RENDERER_DIRAC )
9128 : {
9129 1200 : if ( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ) != IVAS_ERR_OK )
9130 : {
9131 0 : return error;
9132 : }
9133 : }
9134 :
9135 2596 : if ( hMasaExtRend->renderer_type == RENDERER_BINAURAL_PARAMETRIC || hMasaExtRend->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || hMasaExtRend->renderer_type == RENDERER_STEREO_PARAMETRIC )
9136 : {
9137 1336 : if ( hMasaExtRend->renderer_type != RENDERER_STEREO_PARAMETRIC )
9138 : {
9139 1216 : if ( ( error = ivas_dirac_dec_binaural_copy_hrtfs( inputMasa->hMasaExtRend->hHrtfParambin ) ) != IVAS_ERR_OK )
9140 : {
9141 0 : return error;
9142 : }
9143 : }
9144 :
9145 1336 : if ( ( error = ivas_masa_ext_rend_parambin_init( inputMasa, hRendCfg, hrtfs->hHrtfStatistics ) ) != IVAS_ERR_OK )
9146 : {
9147 0 : return error;
9148 : }
9149 : }
9150 :
9151 : /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
9152 7788 : for ( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
9153 : {
9154 5192 : hMasaExtRend->cldfbAnaRend[i] = NULL;
9155 : }
9156 :
9157 44132 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
9158 : {
9159 41536 : hMasaExtRend->cldfbSynRend[i] = NULL;
9160 : }
9161 :
9162 2596 : if ( hMasaExtRend->renderer_type != RENDERER_DISABLE )
9163 : {
9164 6370 : for ( i = 0; i < hMasaExtRend->nchan_input; i++ )
9165 : {
9166 3834 : if ( ( error = openCldfb( &( hMasaExtRend->cldfbAnaRend[i] ), CLDFB_ANALYSIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
9167 : {
9168 0 : return error;
9169 : }
9170 : }
9171 :
9172 16188 : for ( i = 0; i < hMasaExtRend->nchan_output; i++ )
9173 : {
9174 13652 : if ( ( error = openCldfb( &( hMasaExtRend->cldfbSynRend[i] ), CLDFB_SYNTHESIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
9175 : {
9176 0 : return error;
9177 : }
9178 : }
9179 : }
9180 :
9181 2596 : inputMasa->hMasaExtRend = hMasaExtRend;
9182 :
9183 2596 : return IVAS_ERR_OK;
9184 : }
9185 :
9186 :
9187 10354 : static void freeMasaExtRenderer(
9188 : MASA_EXT_REND_HANDLE *hMasaExtRendOut )
9189 : {
9190 : MASA_EXT_REND_HANDLE hMasaExtRend;
9191 : int16_t i;
9192 :
9193 10354 : if ( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
9194 : {
9195 7758 : return;
9196 : }
9197 :
9198 2596 : hMasaExtRend = *hMasaExtRendOut;
9199 :
9200 2596 : if ( hMasaExtRend->hDirACRend != NULL )
9201 : {
9202 1200 : ivas_dirac_rend_close( &hMasaExtRend->hDirACRend );
9203 : }
9204 :
9205 2596 : if ( hMasaExtRend->hSpatParamRendCom != NULL )
9206 : {
9207 2536 : ivas_spat_hSpatParamRendCom_close( &hMasaExtRend->hSpatParamRendCom );
9208 : }
9209 :
9210 23364 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
9211 : {
9212 20768 : if ( hMasaExtRend->hDiracDecBin[i] != NULL )
9213 : {
9214 1336 : ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin[i] );
9215 : }
9216 : }
9217 :
9218 :
9219 2596 : if ( hMasaExtRend->hReverb != NULL )
9220 : {
9221 0 : ivas_binaural_reverb_close( &hMasaExtRend->hReverb );
9222 : }
9223 :
9224 2596 : if ( hMasaExtRend->hHrtfParambin != NULL )
9225 : {
9226 2596 : ivas_HRTF_parambin_binary_close( hMasaExtRend->hHrtfParambin );
9227 : }
9228 :
9229 2596 : if ( hMasaExtRend->hVBAPdata != NULL )
9230 : {
9231 780 : vbap_free_data( &hMasaExtRend->hVBAPdata );
9232 : }
9233 :
9234 2596 : if ( hMasaExtRend->hoa_dec_mtx != NULL )
9235 : {
9236 60 : free( hMasaExtRend->hoa_dec_mtx );
9237 : }
9238 :
9239 7788 : for ( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
9240 : {
9241 5192 : if ( hMasaExtRend->cldfbAnaRend[i] != NULL )
9242 : {
9243 3834 : deleteCldfb( &hMasaExtRend->cldfbAnaRend[i] );
9244 : }
9245 : }
9246 :
9247 44132 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
9248 : {
9249 41536 : if ( hMasaExtRend->cldfbSynRend[i] != NULL )
9250 : {
9251 13652 : deleteCldfb( &hMasaExtRend->cldfbSynRend[i] );
9252 : }
9253 : }
9254 :
9255 2596 : free( hMasaExtRend );
9256 2596 : *hMasaExtRendOut = NULL;
9257 :
9258 2596 : return;
9259 : }
9260 :
9261 :
9262 10354 : static ivas_error printConfigInfo_rend(
9263 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
9264 : )
9265 : {
9266 : ivas_error error;
9267 : char config_str[50];
9268 :
9269 : /*-----------------------------------------------------------------*
9270 : * Print output audio configuration
9271 : *-----------------------------------------------------------------*/
9272 :
9273 10354 : if ( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ) != IVAS_ERR_OK )
9274 : {
9275 0 : return error;
9276 : }
9277 :
9278 10354 : fprintf( stdout, "Output configuration: %s\n", config_str );
9279 :
9280 : /*-----------------------------------------------------------------*
9281 : * Print renderer configurations
9282 : *-----------------------------------------------------------------*/
9283 :
9284 10354 : fprintf( stdout, "Output sampling rate: %d Hz\n", hIvasRend->sampleRateOut );
9285 :
9286 10354 : if ( hIvasRend->headRotData.headRotEnabled == 1 )
9287 : {
9288 1966 : fprintf( stdout, "Head-tracking: ON\n" );
9289 : }
9290 :
9291 10354 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL ||
9292 9406 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ||
9293 8458 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ||
9294 6286 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ||
9295 5820 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
9296 : {
9297 4540 : fprintf( stdout, "Render framesize: %dms\n", hIvasRend->num_subframes * 5 );
9298 : }
9299 :
9300 10354 : return IVAS_ERR_OK;
9301 : }
9302 :
9303 :
9304 : /*---------------------------------------------------------------------*
9305 : * IVAS_REND_PrintInputConfig()
9306 : *
9307 : *
9308 : *---------------------------------------------------------------------*/
9309 :
9310 15974 : void IVAS_REND_PrintInputConfig(
9311 : const IVAS_AUDIO_CONFIG inputConfig /* i : input audio configuration */
9312 : )
9313 : {
9314 : char config_str[50];
9315 :
9316 15974 : get_channel_config( inputConfig, &config_str[0] );
9317 15974 : fprintf( stdout, "Input configuration: %s\n", config_str );
9318 :
9319 15974 : return;
9320 : }
9321 :
9322 :
9323 : /*---------------------------------------------------------------------*
9324 : * IVAS_REND_PrintConfig()
9325 : *
9326 : *
9327 : *---------------------------------------------------------------------*/
9328 :
9329 10354 : ivas_error IVAS_REND_PrintConfig(
9330 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
9331 : )
9332 : {
9333 10354 : if ( hIvasRend == NULL )
9334 : {
9335 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
9336 : }
9337 :
9338 10354 : return printConfigInfo_rend( hIvasRend );
9339 : }
9340 :
9341 :
9342 : /*---------------------------------------------------------------------*
9343 : * IVAS_REND_PrintDisclaimer()
9344 : *
9345 : * Print IVAS disclaimer to console
9346 : *---------------------------------------------------------------------*/
9347 :
9348 10354 : void IVAS_REND_PrintDisclaimer( void )
9349 : {
9350 10354 : print_disclaimer( stderr );
9351 :
9352 10354 : return;
9353 : }
|