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