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 12477 : static ivas_error allocateInputBaseBufferData(
249 : float **data,
250 : const int16_t data_size )
251 : {
252 12477 : *data = (float *) malloc( data_size * sizeof( float ) );
253 12477 : 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 12477 : return IVAS_ERR_OK;
259 : }
260 :
261 36057 : static void freeInputBaseBufferData(
262 : float **data )
263 : {
264 36057 : if ( *data != NULL )
265 : {
266 12477 : free( *data );
267 12477 : *data = NULL;
268 : }
269 :
270 36057 : return;
271 : }
272 :
273 225966654 : static int16_t latencyNsToSamples(
274 : int32_t sampleRate,
275 : int32_t latency_ns )
276 : {
277 225966654 : return (int16_t) roundf( (float) ( latency_ns ) * ( sampleRate / 1000000000.f ) );
278 : }
279 :
280 1371 : static ivas_error allocateMcLfeDelayBuffer(
281 : float **lfeDelayBuffer,
282 : const int16_t data_size )
283 : {
284 1371 : *lfeDelayBuffer = (float *) malloc( data_size * sizeof( float ) );
285 1371 : if ( *lfeDelayBuffer == NULL )
286 : {
287 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" );
288 : }
289 :
290 1371 : return IVAS_ERR_OK;
291 : }
292 :
293 5151 : static void freeMcLfeDelayBuffer(
294 : float **lfeDelayBuffer )
295 : {
296 5151 : if ( *lfeDelayBuffer != NULL )
297 : {
298 1371 : free( *lfeDelayBuffer );
299 1371 : *lfeDelayBuffer = NULL;
300 : }
301 :
302 5151 : return;
303 : }
304 :
305 1929 : static IVAS_QUATERNION quaternionInit(
306 : void )
307 : {
308 : IVAS_QUATERNION q;
309 1929 : q.w = 1.0f;
310 1929 : q.x = q.y = q.z = 0.0f;
311 1929 : return q;
312 : }
313 :
314 24635557786 : static float *getSmplPtr(
315 : IVAS_REND_AudioBuffer buffer,
316 : const uint32_t chnlIdx,
317 : const uint32_t smplIdx )
318 : {
319 24635557786 : return buffer.data + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx;
320 : }
321 :
322 0 : static void convertBitsBufferToInternalBitsBuff(
323 : const IVAS_REND_BitstreamBuffer outBits,
324 : ISAR_SPLIT_REND_BITS_HANDLE hBits )
325 : {
326 0 : hBits->bits_buf = outBits.bits;
327 0 : hBits->bits_read = outBits.config.bitsRead;
328 0 : hBits->bits_written = outBits.config.bitsWritten;
329 0 : hBits->buf_len = outBits.config.bufLenInBytes;
330 0 : hBits->codec = outBits.config.codec;
331 0 : hBits->pose_correction = outBits.config.poseCorrection;
332 0 : hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
333 :
334 0 : return;
335 : }
336 :
337 0 : static void convertInternalBitsBuffToBitsBuffer(
338 : IVAS_REND_BitstreamBuffer *hOutBits,
339 : const ISAR_SPLIT_REND_BITS_DATA bits )
340 : {
341 0 : hOutBits->bits = bits.bits_buf;
342 0 : hOutBits->config.bitsRead = bits.bits_read;
343 0 : hOutBits->config.bitsWritten = bits.bits_written;
344 0 : hOutBits->config.bufLenInBytes = bits.buf_len;
345 0 : hOutBits->config.codec = bits.codec;
346 0 : hOutBits->config.poseCorrection = bits.pose_correction;
347 0 : hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
348 :
349 0 : return;
350 : }
351 :
352 0 : 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 0 : assert( ( buffer.config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
363 0 : readPtr = buffer.data;
364 0 : numCldfbSamples = ( (uint32_t) buffer.config.numSamplesPerChannel ) >> 1;
365 0 : num_bands = numCldfbSamples / CLDFB_NO_COL_MAX;
366 0 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
367 : {
368 0 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
369 : {
370 0 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
371 : {
372 0 : re[chnlIdx][slotIdx][smplIdx] = *readPtr++;
373 : }
374 0 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
375 : {
376 0 : im[chnlIdx][slotIdx][smplIdx] = *readPtr++;
377 : }
378 : }
379 : }
380 :
381 0 : return;
382 : }
383 :
384 0 : 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 0 : assert( ( buffer->config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
395 0 : writePtr = buffer->data;
396 0 : numCldfbSamples = ( (uint32_t) buffer->config.numSamplesPerChannel ) >> 1;
397 0 : num_bands = numCldfbSamples / CLDFB_NO_COL_MAX;
398 0 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer->config.numChannels; ++chnlIdx )
399 : {
400 0 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
401 : {
402 0 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
403 : {
404 0 : *writePtr++ += re[chnlIdx][slotIdx][smplIdx];
405 : }
406 0 : for ( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
407 : {
408 0 : *writePtr++ += im[chnlIdx][slotIdx][smplIdx];
409 : }
410 : }
411 : }
412 :
413 0 : return;
414 : }
415 :
416 109281741 : 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 109281741 : assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
425 109281741 : readPtr = buffer.data;
426 :
427 641137706 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
428 : {
429 >13655*10^7 : for ( smplIdx = 0; smplIdx < (uint32_t) buffer.config.numSamplesPerChannel; ++smplIdx )
430 : {
431 >13602*10^7 : array[chnlIdx][smplIdx] = *readPtr++;
432 : }
433 : }
434 :
435 109281741 : return;
436 : }
437 :
438 109281741 : 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 109281741 : writePtr = buffer->data;
446 385612149 : for ( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
447 : {
448 73732069608 : for ( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
449 : {
450 73455739200 : *writePtr++ += array[chnlIdx][smplIdx];
451 : }
452 : }
453 :
454 109281741 : 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 93743181 : 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 93743181 : int32_t numClipping = 0;
476 :
477 : /* return early if given bad parameters */
478 93743181 : if ( hLimiter == NULL || output == NULL || output_frame <= 0 )
479 : {
480 0 : return 0;
481 : }
482 :
483 93743181 : channels = hLimiter->channel_ptrs;
484 93743181 : num_channels = hLimiter->num_channels;
485 :
486 559379262 : for ( i = 0; i < num_channels; ++i )
487 : {
488 465636081 : channels[i] = output + i * output_frame;
489 : }
490 :
491 93743181 : 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 >13188*10^7 : 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 >13179*10^7 : output[i] = min( max( INT16_MIN, output[i] ), INT16_MAX );
504 : }
505 :
506 93743181 : return numClipping;
507 : }
508 : #endif
509 :
510 : /*-------------------------------------------------------------------*
511 : * validateOutputAudioConfig()
512 : *
513 : *
514 : *-------------------------------------------------------------------*/
515 :
516 5151 : static ivas_error validateOutputAudioConfig(
517 : const AUDIO_CONFIG outConfig )
518 : {
519 5151 : switch ( outConfig )
520 : {
521 5151 : 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 5151 : 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 897532532 : IVAS_REND_AudioConfigType getAudioConfigType(
555 : const AUDIO_CONFIG config )
556 : {
557 : IVAS_REND_AudioConfigType type;
558 :
559 897532532 : switch ( config )
560 : {
561 339950475 : 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 339950475 : type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
570 339950475 : break;
571 142176801 : case IVAS_AUDIO_CONFIG_FOA:
572 : case IVAS_AUDIO_CONFIG_HOA2:
573 : case IVAS_AUDIO_CONFIG_HOA3:
574 142176801 : type = IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS;
575 142176801 : break;
576 47748165 : case IVAS_AUDIO_CONFIG_OBA:
577 47748165 : type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
578 47748165 : break;
579 357585190 : 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 357585190 : type = IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL;
585 357585190 : break;
586 10071901 : case IVAS_AUDIO_CONFIG_MASA1:
587 : case IVAS_AUDIO_CONFIG_MASA2:
588 10071901 : type = IVAS_REND_AUDIO_CONFIG_TYPE_MASA;
589 10071901 : break;
590 0 : default:
591 0 : type = IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
592 0 : break;
593 : }
594 :
595 897532532 : return type;
596 : }
597 :
598 :
599 : /*-------------------------------------------------------------------*
600 : * validateOutputSampleRate()
601 : *
602 : *
603 : *-------------------------------------------------------------------*/
604 :
605 5151 : static ivas_error validateOutputSampleRate(
606 : const int32_t sampleRate,
607 : const AUDIO_CONFIG outConfig )
608 : {
609 5151 : if ( getAudioConfigType( outConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
610 : {
611 : /* If no binaural rendering, any sampling rate is supported */
612 2907 : return IVAS_ERR_OK;
613 : }
614 2244 : 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 2244 : switch ( sampleRate )
622 : {
623 2244 : case 16000:
624 : case 32000:
625 : case 48000:
626 2244 : 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 663149556 : ivas_error getAudioConfigNumChannels(
641 : const AUDIO_CONFIG config,
642 : int16_t *numChannels )
643 : {
644 663149556 : switch ( config )
645 : {
646 162836360 : case IVAS_AUDIO_CONFIG_MONO:
647 : case IVAS_AUDIO_CONFIG_OBA:
648 : case IVAS_AUDIO_CONFIG_MASA1:
649 162836360 : *numChannels = 1;
650 162836360 : break;
651 185450155 : 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 185450155 : *numChannels = 2;
659 185450155 : break;
660 50143079 : case IVAS_AUDIO_CONFIG_FOA:
661 50143079 : *numChannels = 4;
662 50143079 : break;
663 15556713 : case IVAS_AUDIO_CONFIG_5_1:
664 15556713 : *numChannels = 6;
665 15556713 : break;
666 28505184 : case IVAS_AUDIO_CONFIG_7_1:
667 : case IVAS_AUDIO_CONFIG_5_1_2:
668 28505184 : *numChannels = 8;
669 28505184 : break;
670 49441586 : case IVAS_AUDIO_CONFIG_HOA2:
671 49441586 : *numChannels = 9;
672 49441586 : break;
673 15290848 : case IVAS_AUDIO_CONFIG_5_1_4:
674 15290848 : *numChannels = 10;
675 15290848 : break;
676 106281382 : case IVAS_AUDIO_CONFIG_7_1_4:
677 106281382 : *numChannels = 12;
678 106281382 : break;
679 49644249 : case IVAS_AUDIO_CONFIG_HOA3:
680 49644249 : *numChannels = 16;
681 49644249 : break;
682 0 : default:
683 0 : return IVAS_ERR_NUM_CHANNELS_UNKNOWN;
684 : }
685 :
686 663149556 : return IVAS_ERR_OK;
687 : }
688 :
689 :
690 : /*-------------------------------------------------------------------*
691 : * Local functions
692 : *-------------------------------------------------------------------*/
693 :
694 5502 : 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 5502 : 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 5502 : if ( *phLimiter != NULL )
709 : {
710 351 : ivas_limiter_close( phLimiter );
711 : }
712 :
713 5502 : if ( ( error = ivas_limiter_open( phLimiter, numChannels, sampleRate ) ) != IVAS_ERR_OK )
714 : {
715 0 : return error;
716 : }
717 :
718 5502 : return IVAS_ERR_OK;
719 : }
720 :
721 :
722 6522 : 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 6522 : ls.is_planar_setup = 1;
730 6522 : ls.num_spk = 1;
731 6522 : set_zero( ls.ls_azimuth, MAX_OUTPUT_CHANNELS );
732 6522 : set_zero( ls.ls_elevation, MAX_OUTPUT_CHANNELS );
733 6522 : ls.num_lfe = 0;
734 6522 : set_s( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
735 6522 : ls.separate_ch_found = 0;
736 6522 : set_f( ls.separate_ch_gains, 0, MAX_OUTPUT_CHANNELS );
737 :
738 6522 : return ls;
739 : }
740 :
741 :
742 2052425 : static ivas_error getSpeakerAzimuths(
743 : AUDIO_CONFIG config,
744 : const float **azimuths )
745 : {
746 2052425 : switch ( config )
747 : {
748 291 : case IVAS_AUDIO_CONFIG_MONO:
749 291 : *azimuths = ls_azimuth_CICP1;
750 291 : break;
751 285 : case IVAS_AUDIO_CONFIG_STEREO:
752 285 : *azimuths = ls_azimuth_CICP2;
753 285 : break;
754 187377 : case IVAS_AUDIO_CONFIG_5_1:
755 187377 : *azimuths = ls_azimuth_CICP6;
756 187377 : break;
757 187377 : case IVAS_AUDIO_CONFIG_7_1:
758 187377 : *azimuths = ls_azimuth_CICP12;
759 187377 : break;
760 550704 : case IVAS_AUDIO_CONFIG_5_1_2:
761 550704 : *azimuths = ls_azimuth_CICP14;
762 550704 : break;
763 560382 : case IVAS_AUDIO_CONFIG_5_1_4:
764 560382 : *azimuths = ls_azimuth_CICP16;
765 560382 : break;
766 566009 : case IVAS_AUDIO_CONFIG_7_1_4:
767 566009 : *azimuths = ls_azimuth_CICP19;
768 566009 : break;
769 0 : default:
770 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
771 : }
772 :
773 2052425 : return IVAS_ERR_OK;
774 : }
775 :
776 :
777 2052425 : static ivas_error getSpeakerElevations(
778 : AUDIO_CONFIG config,
779 : const float **elevations )
780 : {
781 2052425 : switch ( config )
782 : {
783 291 : case IVAS_AUDIO_CONFIG_MONO:
784 291 : *elevations = ls_elevation_CICP1;
785 291 : break;
786 285 : case IVAS_AUDIO_CONFIG_STEREO:
787 285 : *elevations = ls_elevation_CICP2;
788 285 : break;
789 187377 : case IVAS_AUDIO_CONFIG_5_1:
790 187377 : *elevations = ls_elevation_CICP6;
791 187377 : break;
792 187377 : case IVAS_AUDIO_CONFIG_7_1:
793 187377 : *elevations = ls_elevation_CICP12;
794 187377 : break;
795 550704 : case IVAS_AUDIO_CONFIG_5_1_2:
796 550704 : *elevations = ls_elevation_CICP14;
797 550704 : break;
798 560382 : case IVAS_AUDIO_CONFIG_5_1_4:
799 560382 : *elevations = ls_elevation_CICP16;
800 560382 : break;
801 566009 : case IVAS_AUDIO_CONFIG_7_1_4:
802 566009 : *elevations = ls_elevation_CICP19;
803 566009 : break;
804 0 : default:
805 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
806 : }
807 :
808 2052425 : return IVAS_ERR_OK;
809 : }
810 :
811 :
812 28699842 : static ivas_error getAmbisonicsOrder(
813 : AUDIO_CONFIG config,
814 : int16_t *order )
815 : {
816 28699842 : switch ( config )
817 : {
818 9606260 : case IVAS_AUDIO_CONFIG_FOA:
819 9606260 : *order = 1;
820 9606260 : break;
821 9546791 : case IVAS_AUDIO_CONFIG_HOA2:
822 9546791 : *order = 2;
823 9546791 : break;
824 9546791 : case IVAS_AUDIO_CONFIG_HOA3:
825 9546791 : *order = 3;
826 9546791 : break;
827 0 : default:
828 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" );
829 : }
830 :
831 28699842 : 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 3791 : static ivas_error getNumNonLfeChannelsInSpeakerLayout(
856 : AUDIO_CONFIG config,
857 : int16_t *numNonLfeChannels )
858 : {
859 3791 : switch ( config )
860 : {
861 291 : case IVAS_AUDIO_CONFIG_MONO:
862 291 : *numNonLfeChannels = 1;
863 291 : break;
864 285 : case IVAS_AUDIO_CONFIG_STEREO:
865 285 : *numNonLfeChannels = 2;
866 285 : break;
867 297 : case IVAS_AUDIO_CONFIG_5_1:
868 297 : *numNonLfeChannels = 5;
869 297 : break;
870 594 : case IVAS_AUDIO_CONFIG_5_1_2:
871 : case IVAS_AUDIO_CONFIG_7_1:
872 594 : *numNonLfeChannels = 7;
873 594 : break;
874 315 : case IVAS_AUDIO_CONFIG_5_1_4:
875 315 : *numNonLfeChannels = 9;
876 315 : break;
877 2009 : case IVAS_AUDIO_CONFIG_7_1_4:
878 2009 : *numNonLfeChannels = 11;
879 2009 : break;
880 0 : default:
881 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
882 : }
883 :
884 3791 : return IVAS_ERR_OK;
885 : }
886 :
887 2777184 : 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 2777184 : *lfe_idx = -1;
899 2777184 : *is_planar = 1;
900 2777184 : switch ( inConfig )
901 : {
902 728550 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
903 728550 : *azimuth = (const float *) &pInCustomLs->ls_azimuth;
904 728550 : *elevation = (const float *) &pInCustomLs->ls_elevation;
905 728550 : if ( pInCustomLs->num_lfe > 0 )
906 : {
907 0 : *lfe_idx = pInCustomLs->lfe_idx[0];
908 : }
909 3619110 : for ( i = 0; i < pInCustomLs->num_spk; i++ )
910 : {
911 3619110 : if ( pInCustomLs->ls_elevation[i] != 0 )
912 : {
913 728550 : *is_planar = 0;
914 728550 : break;
915 : }
916 : }
917 728550 : 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 2048634 : 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 2048634 : if ( ( error = getSpeakerAzimuths( inConfig, azimuth ) ) != IVAS_ERR_OK )
935 : {
936 0 : return error;
937 : }
938 2048634 : if ( ( error = getSpeakerElevations( inConfig, elevation ) ) != IVAS_ERR_OK )
939 : {
940 0 : return error;
941 : }
942 2048634 : *lfe_idx = LFE_CHANNEL;
943 2048634 : *is_planar = ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ? 1 : 0;
944 2048634 : break;
945 0 : default:
946 0 : assert( !"Invalid speaker config" );
947 : return IVAS_ERR_WRONG_PARAMS;
948 : }
949 :
950 2777184 : return IVAS_ERR_OK;
951 : }
952 :
953 :
954 5937 : 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 5937 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
965 : {
966 1712 : pEfapWrapper->speakerConfig = IVAS_AUDIO_CONFIG_7_1_4;
967 : }
968 : else
969 : {
970 4225 : pEfapWrapper->speakerConfig = outConfig;
971 : }
972 5937 : pEfapWrapper->pCustomLsSetup = pCustomLsOut;
973 :
974 : /* If re-initializing, free existing EFAP handle. */
975 5937 : if ( pEfapWrapper->hEfap != NULL )
976 : {
977 351 : efap_free_data( &pEfapWrapper->hEfap );
978 : }
979 :
980 : /* Only initialize EFAP handle if output config is channel-based */
981 5937 : if ( getAudioConfigType( pEfapWrapper->speakerConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
982 : {
983 1336 : pEfapWrapper->hEfap = NULL;
984 1336 : return IVAS_ERR_OK;
985 : }
986 :
987 4601 : if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
988 : {
989 1017 : 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 3584 : if ( ( error = getSpeakerAzimuths( pEfapWrapper->speakerConfig, &azimuths ) ) != IVAS_ERR_OK )
997 : {
998 0 : return error;
999 : }
1000 :
1001 3584 : if ( ( error = getSpeakerElevations( pEfapWrapper->speakerConfig, &elevations ) ) != IVAS_ERR_OK )
1002 : {
1003 0 : return error;
1004 : }
1005 :
1006 3584 : if ( ( error = getNumNonLfeChannelsInSpeakerLayout( pEfapWrapper->speakerConfig, &numNonLfeChannels ) ) != IVAS_ERR_OK )
1007 : {
1008 0 : return error;
1009 : }
1010 :
1011 3584 : 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 4601 : return IVAS_ERR_OK;
1018 : }
1019 :
1020 :
1021 26440984 : 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 26440984 : efap_determine_gains( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
1036 :
1037 : /* Now copy to buffer that includes LFE channels */
1038 26440984 : if ( efapWrapper.speakerConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
1039 : {
1040 1807740 : numChannels = efapWrapper.pCustomLsSetup->num_spk + efapWrapper.pCustomLsSetup->num_lfe;
1041 1807740 : readPtr = tmpPanGains;
1042 :
1043 23500524 : for ( i = 0, lfeCount = 0; i < numChannels; ++i )
1044 : {
1045 21692784 : 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 21692784 : panGains[i] = *readPtr;
1053 21692784 : ++readPtr;
1054 : }
1055 : }
1056 : }
1057 : else
1058 : {
1059 24633244 : if ( ( error = getAudioConfigNumChannels( efapWrapper.speakerConfig, &numChannels ) ) != IVAS_ERR_OK )
1060 : {
1061 0 : return error;
1062 : }
1063 :
1064 24633244 : readPtr = tmpPanGains;
1065 :
1066 287693920 : for ( i = 0; i < numChannels; ++i )
1067 : {
1068 263060676 : if ( i == LFE_CHANNEL )
1069 : {
1070 23427976 : panGains[i] = 0.0f;
1071 : }
1072 : else
1073 : {
1074 239632700 : panGains[i] = *readPtr;
1075 239632700 : ++readPtr;
1076 : }
1077 : }
1078 : }
1079 :
1080 26440984 : return IVAS_ERR_OK;
1081 : }
1082 :
1083 :
1084 876 : 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 876 : hIvasRend->headRotData.headRotEnabled = 1;
1093 :
1094 : /* Initialize 5ms crossfade */
1095 876 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
1096 876 : tmp = 1.f / ( crossfade_len - 1 );
1097 211116 : for ( i = 0; i < crossfade_len; i++ )
1098 : {
1099 210240 : hIvasRend->headRotData.crossfade[i] = i * tmp;
1100 : }
1101 :
1102 : /* Initialize with unit quaternions */
1103 2805 : for ( i = 0; i < hIvasRend->num_subframes; ++i )
1104 : {
1105 1929 : hIvasRend->headRotData.headPositions[i] = quaternionInit();
1106 : }
1107 :
1108 876 : hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
1109 :
1110 876 : 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 876 : if ( ( error = ivas_orient_trk_Init( hIvasRend->headRotData.hOrientationTracker ) ) != IVAS_ERR_OK )
1116 : {
1117 0 : return error;
1118 : }
1119 :
1120 876 : return IVAS_ERR_OK;
1121 : }
1122 :
1123 5151 : static void closeHeadRotation(
1124 : IVAS_REND_HANDLE hIvasRend )
1125 : {
1126 5151 : if ( hIvasRend != NULL && hIvasRend->headRotData.headRotEnabled && hIvasRend->headRotData.hOrientationTracker != NULL )
1127 : {
1128 876 : free( hIvasRend->headRotData.hOrientationTracker );
1129 : }
1130 :
1131 5151 : return;
1132 : }
1133 :
1134 :
1135 7761 : static void initRotMatrix(
1136 : rotation_matrix rot_mat )
1137 : {
1138 : int16_t i;
1139 :
1140 : /* Initialize rotation matrices */
1141 31044 : for ( i = 0; i < 3; i++ )
1142 : {
1143 23283 : set_zero( rot_mat[i], 3 );
1144 23283 : rot_mat[i][i] = 1.f;
1145 : }
1146 :
1147 7761 : return;
1148 : }
1149 :
1150 :
1151 27360 : static void initRotGains(
1152 : rotation_gains rot_gains )
1153 : {
1154 : int16_t i;
1155 :
1156 : /* Set gains to passthrough */
1157 465120 : for ( i = 0; i < MAX_INPUT_CHANNELS; i++ )
1158 : {
1159 437760 : set_zero( rot_gains[i], MAX_INPUT_CHANNELS );
1160 437760 : rot_gains[i][i] = 1.f;
1161 : }
1162 :
1163 27360 : return;
1164 : }
1165 :
1166 :
1167 84591 : 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 84591 : inputBase->inConfig = inConfig;
1176 84591 : inputBase->id = id;
1177 84591 : inputBase->gain = 1.0f;
1178 84591 : inputBase->ctx = rendCtx;
1179 84591 : inputBase->numNewSamplesPerChannel = 0;
1180 84591 : inputBase->delayNumSamples = 0;
1181 84591 : inputBase->delayBuffer = NULL;
1182 :
1183 84591 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
1184 84591 : inputBase->inputBuffer.config.numChannels = 0;
1185 84591 : inputBase->inputBuffer.data = dataBuf;
1186 84591 : if ( inputBase->inputBuffer.data != NULL )
1187 : {
1188 12477 : set_zero( inputBase->inputBuffer.data, dataBufSize );
1189 : }
1190 :
1191 84591 : return;
1192 : }
1193 :
1194 :
1195 27847930 : static IVAS_ISM_METADATA defaultObjectPosition(
1196 : void )
1197 : {
1198 : IVAS_ISM_METADATA pos;
1199 :
1200 27847930 : pos.azimuth = 0.0f;
1201 27847930 : pos.elevation = 0.0f;
1202 27847930 : pos.radius = 1.0f;
1203 27847930 : pos.spread = 0.0f;
1204 27847930 : pos.gainFactor = 1.0f;
1205 27847930 : pos.yaw = 0.0f;
1206 27847930 : pos.pitch = 0.0f;
1207 27847930 : pos.non_diegetic_flag = 0;
1208 :
1209 27847930 : return pos;
1210 : }
1211 :
1212 :
1213 84284298 : static int8_t checkObjectPositionChanged(
1214 : IVAS_ISM_METADATA *currentPos,
1215 : IVAS_ISM_METADATA *previousPos )
1216 : {
1217 153566883 : return !( fabs( currentPos->azimuth - previousPos->azimuth ) < EPSILON &&
1218 69282585 : fabs( currentPos->elevation - previousPos->elevation ) < EPSILON );
1219 : }
1220 :
1221 :
1222 36057 : 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 36057 : ctx.pMaxGlobalDelayNs = &hIvasRend->maxGlobalDelayNs;
1231 36057 : ctx.pOutConfig = &hIvasRend->outputConfig;
1232 36057 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
1233 36057 : ctx.pCustomLsOut = &hIvasRend->customLsOut;
1234 36057 : ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
1235 36057 : ctx.pHeadRotData = &hIvasRend->headRotData;
1236 36057 : ctx.hhRendererConfig = &hIvasRend->hRendererConfig;
1237 36057 : ctx.pSplitRendWrapper = hIvasRend->splitRendWrapper;
1238 36057 : ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
1239 36057 : ctx.pSelectedRoomReverbSize = &hIvasRend->selectedRoomReverbSize;
1240 :
1241 36057 : return ctx;
1242 : }
1243 :
1244 :
1245 73056 : static TDREND_WRAPPER defaultTdRendWrapper(
1246 : void )
1247 : {
1248 : TDREND_WRAPPER w;
1249 :
1250 73056 : w.binaural_latency_ns = 0;
1251 73056 : w.hBinRendererTd = NULL;
1252 73056 : w.hHrtfTD = NULL;
1253 :
1254 73056 : return w;
1255 : }
1256 :
1257 :
1258 12477 : static bool isIoConfigPairSupported(
1259 : const AUDIO_CONFIG inConfig,
1260 : const AUDIO_CONFIG outConfig )
1261 : {
1262 : /* input config cannot be binaural */
1263 12477 : 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 12477 : 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 12477 : return true;
1277 : }
1278 :
1279 :
1280 29436 : static int32_t getRendInputDelayIsm(
1281 : const input_ism *inputIsm,
1282 : bool splitPreRendCldfb )
1283 : {
1284 : int32_t latency_ns;
1285 29436 : latency_ns = 0;
1286 : (void) ( splitPreRendCldfb ); /* unused */
1287 :
1288 : /* set the rendering delay in InputBase */
1289 29436 : latency_ns = max( latency_ns,
1290 : inputIsm->tdRendWrapper.binaural_latency_ns );
1291 29436 : if ( inputIsm->crendWrapper != NULL )
1292 : {
1293 2820 : latency_ns = max( latency_ns,
1294 : inputIsm->crendWrapper->binaural_latency_ns );
1295 : }
1296 :
1297 29436 : return latency_ns;
1298 : }
1299 :
1300 :
1301 7761 : static void setRendInputDelayIsm(
1302 : void *input,
1303 : bool splitPreRendCldfb )
1304 : {
1305 : input_ism *inputIsm;
1306 7761 : inputIsm = (input_ism *) input;
1307 :
1308 7761 : inputIsm->base.delayNumSamples = latencyNsToSamples( *inputIsm->base.ctx.pOutSampleRate,
1309 : getRendInputDelayIsm( inputIsm, splitPreRendCldfb ) );
1310 7761 : }
1311 :
1312 :
1313 3096 : static int32_t getRendInputDelayMc(
1314 : const input_mc *inputMc,
1315 : bool splitPreRendCldfb )
1316 : {
1317 : int32_t latency_ns;
1318 3096 : latency_ns = 0;
1319 : (void) ( splitPreRendCldfb ); /* unused */
1320 :
1321 3096 : latency_ns = max( latency_ns,
1322 : inputMc->tdRendWrapper.binaural_latency_ns );
1323 3096 : if ( inputMc->crendWrapper != NULL )
1324 : {
1325 680 : latency_ns = max( latency_ns,
1326 : inputMc->crendWrapper->binaural_latency_ns );
1327 : }
1328 :
1329 3096 : return latency_ns;
1330 : }
1331 :
1332 :
1333 1371 : static void setRendInputDelayMc(
1334 : void *input,
1335 : bool splitPreRendCldfb )
1336 : {
1337 : input_mc *inputMc;
1338 1371 : inputMc = (input_mc *) input;
1339 :
1340 1371 : inputMc->base.delayNumSamples = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate,
1341 : getRendInputDelayMc( inputMc, splitPreRendCldfb ) );
1342 1371 : }
1343 :
1344 :
1345 4116 : static int32_t getRendInputDelaySba(
1346 : const input_sba *inputSba,
1347 : bool splitPreRendCldfb )
1348 : {
1349 : int32_t latency_ns;
1350 4116 : latency_ns = 0;
1351 :
1352 4116 : if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
1353 : {
1354 0 : latency_ns = max( latency_ns,
1355 : inputSba->cldfbRendWrapper.binaural_latency_ns +
1356 : ( splitPreRendCldfb ? 0 : IVAS_FB_DEC_DELAY_NS ) );
1357 : }
1358 4116 : if ( inputSba->crendWrapper != NULL )
1359 : {
1360 1872 : latency_ns = max( latency_ns,
1361 : inputSba->crendWrapper->binaural_latency_ns );
1362 : }
1363 :
1364 4116 : return latency_ns;
1365 : }
1366 :
1367 :
1368 2049 : static void setRendInputDelaySba(
1369 : void *input,
1370 : bool splitPreRendCldfb )
1371 : {
1372 : input_sba *inputSba;
1373 2049 : inputSba = (input_sba *) input;
1374 :
1375 2049 : inputSba->base.delayNumSamples = latencyNsToSamples( *inputSba->base.ctx.pOutSampleRate,
1376 : getRendInputDelaySba( inputSba, splitPreRendCldfb ) );
1377 2049 : }
1378 :
1379 :
1380 2592 : static int32_t getRendInputDelayMasa(
1381 : const input_masa *inputMasa,
1382 : bool splitPreRendCldfb )
1383 : {
1384 : int32_t latency_ns;
1385 :
1386 2592 : latency_ns = 0;
1387 :
1388 5124 : if ( ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA1 && *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_MONO ) ||
1389 2532 : ( getAudioConfigType( *inputMasa->base.ctx.pOutConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
1390 : {
1391 192 : return 0; /* no delay */
1392 : }
1393 : else
1394 : {
1395 : /* no delay applied for split rendering */
1396 2400 : latency_ns = max( latency_ns,
1397 : (int32_t) ( ( splitPreRendCldfb ? 0 : (float) IVAS_FB_DEC_DELAY_NS + 0.5f ) ) );
1398 : }
1399 2400 : return latency_ns;
1400 : }
1401 :
1402 :
1403 1296 : static void setRendInputDelayMasa(
1404 : void *input,
1405 : bool splitPreRendCldfb )
1406 : {
1407 : input_masa *inputMasa;
1408 1296 : inputMasa = (input_masa *) input;
1409 :
1410 1296 : inputMasa->base.delayNumSamples = latencyNsToSamples( *inputMasa->base.ctx.pOutSampleRate,
1411 : getRendInputDelayMasa( inputMasa, splitPreRendCldfb ) );
1412 1296 : }
1413 :
1414 :
1415 12477 : 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 12477 : 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 12477 : if ( hIvasRend->hRendererConfig != NULL )
1425 : {
1426 5304 : splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD );
1427 : }
1428 : else
1429 : {
1430 7173 : splitPreRendCldfb = false;
1431 : }
1432 :
1433 : /* Compute the maximum delay across all inputs */
1434 62385 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
1435 : {
1436 49908 : if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1437 : {
1438 21675 : latency_ns = getRendInputDelayIsm( &hIvasRend->inputsIsm[i], splitPreRendCldfb );
1439 21675 : max_latency_ns = max( max_latency_ns, latency_ns );
1440 : }
1441 : }
1442 :
1443 24954 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
1444 : {
1445 12477 : if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1446 : {
1447 1725 : latency_ns = getRendInputDelayMc( &hIvasRend->inputsMc[i], splitPreRendCldfb );
1448 1725 : max_latency_ns = max( max_latency_ns, latency_ns );
1449 : }
1450 : }
1451 :
1452 24954 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
1453 : {
1454 12477 : if ( hIvasRend->inputsSba[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1455 : {
1456 2067 : latency_ns = getRendInputDelaySba( &hIvasRend->inputsSba[i], splitPreRendCldfb );
1457 2067 : max_latency_ns = max( max_latency_ns, latency_ns );
1458 : }
1459 : }
1460 :
1461 24954 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
1462 : {
1463 12477 : if ( hIvasRend->inputsMasa[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
1464 : {
1465 1296 : latency_ns = getRendInputDelayMasa( &hIvasRend->inputsMasa[i], splitPreRendCldfb );
1466 1296 : max_latency_ns = max( max_latency_ns, latency_ns );
1467 : }
1468 : }
1469 :
1470 12477 : return max_latency_ns;
1471 : }
1472 :
1473 :
1474 12477 : static void setMaxGlobalDelayNs( IVAS_REND_HANDLE hIvasRend )
1475 : {
1476 12477 : hIvasRend->maxGlobalDelayNs = getMaxGlobalDelayNs( (IVAS_REND_CONST_HANDLE) hIvasRend );
1477 12477 : }
1478 :
1479 215572434 : 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 215572434 : maxGlobalDelaySamples = latencyNsToSamples( sampleRateOut, maxGlobalDelayNs );
1496 215572434 : maxGlobalDelaySamples *= cldfb2tdSampleFact;
1497 :
1498 : /* check if we need to open the delay buffer */
1499 215572434 : if ( inputBase->delayBuffer == NULL )
1500 : {
1501 : /* buffer has to accomodate maxGlobalDelaySamples + 2 * frameSize */
1502 168698430 : ringBufferSize = maxGlobalDelaySamples + 2 * inputAudio.config.numSamplesPerChannel;
1503 :
1504 : /* pre delay for this input is maximum delay - input delay */
1505 168698430 : preDelay = maxGlobalDelaySamples - inputBase->delayNumSamples * cldfb2tdSampleFact;
1506 :
1507 168698430 : if ( preDelay > 0 )
1508 : {
1509 3200 : 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 3200 : ivas_TD_RINGBUF_PushConstant( inputBase->delayBuffer, 0, preDelay );
1517 :
1518 : /* for ISM inputs, ensure the metadata sync delay is updated */
1519 3200 : if ( getAudioConfigType( inputBase->inConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
1520 : {
1521 2400 : inputIsm = (input_ism *) inputBase;
1522 2400 : inputIsm->ism_metadata_delay_ms = (int16_t) roundf( inputIsm->ism_metadata_delay_ms + maxGlobalDelayNs / 1e6f );
1523 : }
1524 : }
1525 : }
1526 :
1527 215572434 : 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 46877204 : numSamplesToPush = flushInputs ? 0 : inputAudio.config.numSamplesPerChannel;
1532 46877204 : numSamplesToPop = flushInputs ? ivas_TD_RINGBUF_Size( inputBase->delayBuffer ) : inputAudio.config.numSamplesPerChannel;
1533 :
1534 187025908 : for ( i = 0; i < inputAudio.config.numChannels; ++i )
1535 : {
1536 140148704 : p_read_channels[i] = inputAudio.data + i * numSamplesToPush;
1537 : }
1538 46877204 : ivas_TD_RINGBUF_PushChannels( inputBase->delayBuffer, p_read_channels, (int16_t) numSamplesToPush );
1539 :
1540 187025908 : for ( i = 0; i < inputAudio.config.numChannels; ++i )
1541 : {
1542 140148704 : p_write_channels[i] = inputBase->inputBuffer.data + i * numSamplesToPop;
1543 : }
1544 46877204 : 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 168695230 : mvr2r( inputAudio.data,
1550 : inputBase->inputBuffer.data,
1551 168695230 : inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
1552 : }
1553 :
1554 215572434 : return IVAS_ERR_OK;
1555 : }
1556 :
1557 66 : static ivas_error initIsmMasaRendering(
1558 : input_ism *inputIsm,
1559 : const int32_t inSampleRate )
1560 : {
1561 : ivas_error error;
1562 :
1563 66 : if ( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1564 : {
1565 0 : ivas_td_binaural_close( &inputIsm->tdRendWrapper.hBinRendererTd );
1566 : }
1567 :
1568 66 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1569 :
1570 66 : ivas_reverb_close( &inputIsm->hReverb );
1571 :
1572 66 : if ( ( error = ivas_omasa_ana_open( &inputIsm->hOMasa, inSampleRate, inputIsm->total_num_objects ) ) != IVAS_ERR_OK )
1573 : {
1574 0 : return error;
1575 : }
1576 :
1577 66 : return IVAS_ERR_OK;
1578 : }
1579 :
1580 :
1581 7761 : 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 7761 : inputIsm = (input_ism *) input;
1595 7761 : rendCtx = inputIsm->base.ctx;
1596 7761 : outConfig = *rendCtx.pOutConfig;
1597 :
1598 7761 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
1599 : {
1600 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
1601 : }
1602 :
1603 7761 : if ( ( error = allocateInputBaseBufferData( &inputIsm->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
1604 : {
1605 0 : return error;
1606 : }
1607 7761 : initRendInputBase( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData, MAX_BUFFER_LENGTH );
1608 :
1609 7761 : inputIsm->firstFrameRendered = FALSE;
1610 :
1611 7761 : inputIsm->currentPos = defaultObjectPosition();
1612 7761 : inputIsm->previousPos = defaultObjectPosition();
1613 7761 : inputIsm->crendWrapper = NULL;
1614 7761 : inputIsm->hReverb = NULL;
1615 7761 : inputIsm->tdRendWrapper = defaultTdRendWrapper();
1616 7761 : initRotMatrix( inputIsm->rot_mat_prev );
1617 7761 : set_zero( inputIsm->prev_pan_gains, MAX_OUTPUT_CHANNELS );
1618 :
1619 62088 : for ( i = 0; i < (int16_t) ( sizeof( inputIsm->splitTdRendWrappers ) / sizeof( *inputIsm->splitTdRendWrappers ) ); ++i )
1620 : {
1621 54327 : inputIsm->splitTdRendWrappers[i] = defaultTdRendWrapper();
1622 54327 : inputIsm->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
1623 : }
1624 :
1625 7761 : inputIsm->hOMasa = NULL;
1626 :
1627 7761 : error = IVAS_ERR_OK;
1628 7761 : inputIsm->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
1629 :
1630 7761 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
1631 : {
1632 740 : 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 5920 : for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
1639 : {
1640 5180 : 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 5180 : assert( inputIsm->splitTdRendWrappers[i].binaural_latency_ns == inputIsm->tdRendWrapper.binaural_latency_ns );
1647 : }
1648 : }
1649 7021 : else if ( outConfig == IVAS_AUDIO_CONFIG_MASA1 || outConfig == IVAS_AUDIO_CONFIG_MASA2 )
1650 : {
1651 66 : if ( ( error = initIsmMasaRendering( inputIsm, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
1652 : {
1653 0 : return error;
1654 : }
1655 : }
1656 : else
1657 : {
1658 6955 : 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 6955 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
1664 : {
1665 1820 : if ( ( error = ivas_reverb_open( &( inputIsm->hReverb ), hrtfs->hHrtfStatistics, hRendCfg, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
1666 : {
1667 0 : return error;
1668 : }
1669 : }
1670 5135 : else if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
1671 : {
1672 740 : 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 7761 : return IVAS_ERR_OK;
1680 : }
1681 :
1682 :
1683 20604 : static void clearInputIsm(
1684 : input_ism *inputIsm )
1685 : {
1686 : rendering_context rendCtx;
1687 : int16_t i;
1688 :
1689 20604 : rendCtx = inputIsm->base.ctx;
1690 :
1691 20604 : freeInputBaseBufferData( &inputIsm->base.inputBuffer.data );
1692 20604 : ivas_TD_RINGBUF_Close( &inputIsm->base.delayBuffer );
1693 :
1694 20604 : initRendInputBase( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
1695 :
1696 : /* Free input's internal handles */
1697 20604 : ivas_rend_closeCrend( &inputIsm->crendWrapper );
1698 :
1699 20604 : ivas_reverb_close( &inputIsm->hReverb );
1700 :
1701 20604 : if ( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
1702 : {
1703 7695 : ivas_td_binaural_close( &inputIsm->tdRendWrapper.hBinRendererTd );
1704 : }
1705 :
1706 164832 : for ( i = 0; i < (int16_t) ( sizeof( inputIsm->splitTdRendWrappers ) / sizeof( *inputIsm->splitTdRendWrappers ) ); ++i )
1707 : {
1708 144228 : ivas_td_binaural_close( &inputIsm->splitTdRendWrappers[i].hBinRendererTd );
1709 : }
1710 :
1711 20604 : ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
1712 :
1713 20604 : return;
1714 : }
1715 :
1716 :
1717 252 : 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 252 : numNonZeroGains = lsConvMatrix[0].index;
1728 252 : numColumns = (int16_t) lsConvMatrix[0].value;
1729 :
1730 2600 : for ( i = 1; i < numNonZeroGains + 1; ++i )
1731 : {
1732 2348 : inCh = lsConvMatrix[i].index / numColumns;
1733 2348 : outCh = lsConvMatrix[i].index % numColumns;
1734 :
1735 2348 : panMatrix[inCh][outCh] = lsConvMatrix[i].value;
1736 : }
1737 :
1738 252 : return;
1739 : }
1740 :
1741 :
1742 7329 : static void setZeroPanMatrix(
1743 : pan_matrix panMatrix )
1744 : {
1745 : int16_t i;
1746 :
1747 124593 : for ( i = 0; i < MAX_INPUT_CHANNELS; ++i )
1748 : {
1749 117264 : set_zero( panMatrix[i], MAX_OUTPUT_CHANNELS );
1750 : }
1751 :
1752 7329 : return;
1753 : }
1754 :
1755 :
1756 : /* Note: this only sets non-zero elements, call setZeroPanMatrix() to init first. */
1757 533 : static void fillIdentityPanMatrix(
1758 : pan_matrix panMatrix )
1759 : {
1760 : int16_t i;
1761 :
1762 9061 : for ( i = 0; i < min( MAX_INPUT_CHANNELS, MAX_OUTPUT_CHANNELS ); ++i )
1763 : {
1764 8528 : panMatrix[i][i] = 1.0f;
1765 : }
1766 :
1767 533 : return;
1768 : }
1769 :
1770 :
1771 109 : static ivas_error initMcPanGainsWithIdentMatrix(
1772 : input_mc *inputMc )
1773 : {
1774 109 : fillIdentityPanMatrix( inputMc->panGains );
1775 :
1776 109 : return IVAS_ERR_OK;
1777 : }
1778 :
1779 :
1780 388 : 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 388 : ivasConfigIn = inputMc->base.inConfig;
1788 388 : 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 12538 : for ( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; ++i )
1793 : {
1794 12538 : if ( ls_conversion_mapping[i].input_config == ivasConfigIn && ls_conversion_mapping[i].output_config == ivasConfigOut )
1795 : {
1796 : /* Mapping found with valid matrix - copy */
1797 388 : if ( ls_conversion_mapping[i].conversion_matrix != NULL )
1798 : {
1799 252 : copyLsConversionMatrixToPanMatrix( ls_conversion_mapping[i].conversion_matrix, inputMc->panGains );
1800 : }
1801 : /* Mapping found with NULL matrix - use identity matrix */
1802 : else
1803 : {
1804 136 : fillIdentityPanMatrix( inputMc->panGains );
1805 : }
1806 :
1807 388 : return IVAS_ERR_OK;
1808 : }
1809 : }
1810 :
1811 0 : return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" );
1812 : }
1813 :
1814 :
1815 540 : 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 540 : if ( inputMc->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
1826 : {
1827 99 : if ( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK )
1828 : {
1829 0 : return error;
1830 : }
1831 :
1832 99 : if ( ( error = getSpeakerAzimuths( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK )
1833 : {
1834 0 : return error;
1835 : }
1836 :
1837 99 : if ( ( error = getSpeakerElevations( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK )
1838 : {
1839 0 : return error;
1840 : }
1841 :
1842 99 : inLfeChIdx = LFE_CHANNEL;
1843 : }
1844 : else
1845 : {
1846 441 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
1847 441 : spkAzi = inputMc->customLsInput.ls_azimuth;
1848 441 : spkEle = inputMc->customLsInput.ls_elevation;
1849 441 : inLfeChIdx = -1;
1850 441 : if ( inputMc->customLsInput.num_lfe > 0 )
1851 : {
1852 0 : inLfeChIdx = inputMc->customLsInput.lfe_idx[0];
1853 : }
1854 : }
1855 :
1856 3771 : for ( i = 0, outChIdx = 0; i < numNonLfeInChannels; ++i, ++outChIdx )
1857 : {
1858 3231 : if ( i == inLfeChIdx )
1859 : {
1860 45 : ++outChIdx;
1861 : }
1862 :
1863 3231 : 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 540 : if ( outConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inLfeChIdx >= 0 )
1870 : {
1871 36 : inputMc->panGains[inLfeChIdx][LFE_CHANNEL] = 1;
1872 : }
1873 504 : 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 540 : return IVAS_ERR_OK;
1879 : }
1880 :
1881 :
1882 298866723 : 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 298866723 : pInputBase = (const input_base *) rendInput;
1894 :
1895 298866723 : if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
1896 : {
1897 12094299 : pInputMc = (const input_mc *) rendInput;
1898 12094299 : *numInChannels = pInputMc->customLsInput.num_spk + pInputMc->customLsInput.num_lfe;
1899 : }
1900 : else
1901 : {
1902 286772424 : if ( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ) != IVAS_ERR_OK )
1903 : {
1904 0 : return error;
1905 : }
1906 : }
1907 :
1908 298866723 : return IVAS_ERR_OK;
1909 : }
1910 :
1911 :
1912 48 : 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 48 : if ( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ) != IVAS_ERR_OK )
1923 : {
1924 0 : return error;
1925 : }
1926 :
1927 48 : 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 48 : else if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_STEREO )
1937 : {
1938 : /* Special case for STEREO to MONO: Passive downmix (L+R)/2 */
1939 12 : inputMc->panGains[0][0] = 0.5;
1940 12 : 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 36 : skipSideSpeakers = false;
1947 36 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_2 || inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_4 )
1948 : {
1949 18 : skipSideSpeakers = true;
1950 : }
1951 360 : for ( readIdx = 0, writeIdx = 0; writeIdx < numInChannels; ++readIdx, ++writeIdx )
1952 : {
1953 324 : if ( skipSideSpeakers && readIdx == 4 )
1954 : {
1955 : /* Skip gains for side speakers in lookup table */
1956 18 : readIdx += 2;
1957 : }
1958 :
1959 324 : inputMc->panGains[writeIdx][0] = ls_conversion_cicpX_mono[readIdx][0];
1960 : }
1961 : }
1962 :
1963 48 : return IVAS_ERR_OK;
1964 : }
1965 :
1966 :
1967 36 : 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 36 : 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 36 : skipSideSpeakers = false;
1988 36 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_2 || inputMc->base.inConfig == IVAS_AUDIO_CONFIG_5_1_4 )
1989 : {
1990 18 : skipSideSpeakers = true;
1991 : }
1992 :
1993 36 : if ( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ) != IVAS_ERR_OK )
1994 : {
1995 0 : return error;
1996 : }
1997 :
1998 360 : for ( readIdx = 0, writeIdx = 0; writeIdx < numInChannels; ++readIdx, ++writeIdx )
1999 : {
2000 324 : if ( skipSideSpeakers && readIdx == 4 )
2001 : {
2002 : /* Skip gains for side speakers in lookup table */
2003 18 : readIdx += 2;
2004 : }
2005 :
2006 324 : inputMc->panGains[writeIdx][0] = ls_conversion_cicpX_stereo[readIdx][0];
2007 324 : inputMc->panGains[writeIdx][1] = ls_conversion_cicpX_stereo[readIdx][1];
2008 : }
2009 :
2010 36 : 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 1136 : 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 1136 : if ( configA == IVAS_AUDIO_CONFIG_LS_CUSTOM && configB == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2026 : {
2027 54 : if ( customLsA.num_spk != customLsB.num_spk )
2028 : {
2029 45 : return false;
2030 : }
2031 :
2032 9 : if ( customLsA.num_lfe != customLsB.num_lfe )
2033 : {
2034 0 : return false;
2035 : }
2036 :
2037 9 : if ( customLsA.is_planar_setup != customLsB.is_planar_setup )
2038 : {
2039 0 : return false;
2040 : }
2041 :
2042 117 : for ( i = 0; i < customLsA.num_spk; ++i )
2043 : {
2044 : /* Compare to nearest degree (hence the int16_t cast) */
2045 108 : if ( (int16_t) customLsA.ls_azimuth[i] != (int16_t) customLsB.ls_azimuth[i] ||
2046 108 : (int16_t) customLsA.ls_elevation[i] != (int16_t) customLsB.ls_elevation[i] )
2047 : {
2048 0 : return false;
2049 : }
2050 : }
2051 9 : 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 9 : return true;
2060 : }
2061 :
2062 : /* Otherwise it's enough to compare config enums */
2063 1082 : return configA == configB;
2064 : }
2065 :
2066 :
2067 1136 : 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 1136 : error = IVAS_ERR_OK;
2074 :
2075 : /* If panning is not required, simply return */
2076 1136 : if ( !inputMc->lfeRouting.pan_lfe )
2077 : {
2078 1136 : 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 216 : 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 216 : error = IVAS_ERR_OK;
2119 :
2120 : /* If panning is not required, simply return */
2121 216 : if ( !inputMc->lfeRouting.pan_lfe )
2122 : {
2123 216 : 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 1136 : 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 1136 : if ( configsAreEqual( inputMc->base.inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ) )
2165 : {
2166 109 : error = initMcPanGainsWithIdentMatrix( inputMc );
2167 : }
2168 1027 : else if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ||
2169 919 : inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO ||
2170 868 : inputMc->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2171 : {
2172 555 : if ( ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO ) && ( inputMc->nonDiegeticPan ) )
2173 : {
2174 15 : inputMc->panGains[0][0] = ( inputMc->nonDiegeticPanGain + 1.f ) * 0.5f;
2175 15 : inputMc->panGains[0][1] = 1.f - inputMc->panGains[0][0];
2176 15 : error = IVAS_ERR_OK;
2177 : }
2178 : else
2179 : {
2180 540 : error = initMcPanGainsWithEfap( inputMc, outConfig );
2181 : }
2182 : }
2183 472 : else if ( outConfig == IVAS_AUDIO_CONFIG_MONO )
2184 : {
2185 48 : error = initMcPanGainsWithMonoOut( inputMc );
2186 : }
2187 424 : else if ( outConfig == IVAS_AUDIO_CONFIG_STEREO )
2188 : {
2189 36 : error = initMcPanGainsWithStereoLookup( inputMc );
2190 : }
2191 : else /* default */
2192 : {
2193 388 : error = initMcPanGainsWithConversionMapping( inputMc, outConfig );
2194 : }
2195 :
2196 : /* check for errors from above block */
2197 1136 : if ( error != IVAS_ERR_OK )
2198 : {
2199 0 : return error;
2200 : }
2201 :
2202 : /* update LFE panning */
2203 1136 : error = updateLfePanGainsForMcOut( inputMc, outConfig );
2204 :
2205 1136 : return error;
2206 : }
2207 :
2208 :
2209 270 : 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 270 : inConfig = inputMc->base.inConfig;
2220 :
2221 270 : if ( ( error = getAmbisonicsOrder( outConfig, &outAmbiOrder ) ) != IVAS_ERR_OK )
2222 : {
2223 0 : return error;
2224 : }
2225 :
2226 270 : if ( inConfig == IVAS_AUDIO_CONFIG_MONO ||
2227 : inConfig == IVAS_AUDIO_CONFIG_STEREO )
2228 : {
2229 54 : setZeroPanMatrix( inputMc->panGains );
2230 54 : if ( inConfig == IVAS_AUDIO_CONFIG_MONO )
2231 : {
2232 : /* W = Mono */
2233 18 : inputMc->panGains[0][0] = 1.f;
2234 : }
2235 : else
2236 : {
2237 : /* W = 0.5 * ( L + R ) */
2238 36 : inputMc->panGains[0][0] = 0.5f;
2239 36 : inputMc->panGains[0][1] = 0.5f;
2240 : /* Y = 0.5 * ( L - R ) */
2241 36 : inputMc->panGains[1][0] = 0.5f;
2242 36 : inputMc->panGains[1][1] = -0.5f;
2243 : }
2244 :
2245 54 : return IVAS_ERR_OK;
2246 : }
2247 216 : else if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
2248 : {
2249 108 : if ( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ) != IVAS_ERR_OK )
2250 : {
2251 0 : return error;
2252 : }
2253 :
2254 108 : if ( ( error = getSpeakerAzimuths( inputMc->base.inConfig, &spkAzi ) ) != IVAS_ERR_OK )
2255 : {
2256 0 : return error;
2257 : }
2258 :
2259 108 : if ( ( error = getSpeakerElevations( inputMc->base.inConfig, &spkEle ) ) != IVAS_ERR_OK )
2260 : {
2261 0 : return error;
2262 : }
2263 :
2264 972 : for ( ch_in = 0, ch_out = 0; ch_in < numNonLfeInChannels; ++ch_in, ++ch_out )
2265 : {
2266 864 : if ( ch_in == LFE_CHANNEL )
2267 : {
2268 108 : ++ch_out;
2269 : }
2270 864 : 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 108 : numNonLfeInChannels = inputMc->customLsInput.num_spk;
2276 108 : spkAzi = inputMc->customLsInput.ls_azimuth;
2277 108 : spkEle = inputMc->customLsInput.ls_elevation;
2278 :
2279 810 : for ( ch_in = 0, ch_out = 0; ch_in < numNonLfeInChannels; ++ch_in, ++ch_out )
2280 : {
2281 702 : 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 702 : 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 216 : if ( ( error = updateLfePanGainsForAmbiOut( inputMc, outConfig ) ) != IVAS_ERR_OK )
2296 : {
2297 0 : return error;
2298 : }
2299 :
2300 216 : return IVAS_ERR_OK;
2301 : }
2302 :
2303 120 : static ivas_error updateMcPanGainsForBinauralOut(
2304 : input_mc *inputMc )
2305 : {
2306 120 : setZeroPanMatrix( inputMc->panGains );
2307 120 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO )
2308 : {
2309 60 : inputMc->panGains[0][0] = ( inputMc->nonDiegeticPanGain + 1.f ) * 0.5f;
2310 60 : inputMc->panGains[0][1] = 1.f - inputMc->panGains[0][0];
2311 : }
2312 : else
2313 : {
2314 : /* stereo passthrough */
2315 60 : inputMc->panGains[0][0] = 1.f;
2316 60 : inputMc->panGains[1][1] = 1.f;
2317 : }
2318 :
2319 120 : return IVAS_ERR_OK;
2320 : }
2321 :
2322 1686 : 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 1686 : setZeroPanMatrix( inputMc->panGains );
2331 :
2332 1686 : error = IVAS_ERR_OK;
2333 1686 : switch ( getAudioConfigType( outConfig ) )
2334 : {
2335 762 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2336 762 : error = updateMcPanGainsForMcOut( inputMc, outConfig );
2337 762 : break;
2338 270 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2339 270 : error = updateMcPanGainsForAmbiOut( inputMc, outConfig );
2340 270 : break;
2341 636 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2342 636 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO || inputMc->base.inConfig == IVAS_AUDIO_CONFIG_STEREO )
2343 : {
2344 120 : error = updateMcPanGainsForBinauralOut( inputMc );
2345 120 : break;
2346 : }
2347 :
2348 : /* not mono or stereo */
2349 : switch ( outConfig )
2350 : {
2351 142 : case IVAS_AUDIO_CONFIG_BINAURAL:
2352 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
2353 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
2354 142 : break; /* Do nothing */
2355 374 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2356 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2357 : /* Prepare rendering to intermediate format */
2358 374 : error = updateMcPanGainsForMcOut( inputMc, IVAS_AUDIO_CONFIG_7_1_4 );
2359 374 : break;
2360 0 : default:
2361 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2362 : }
2363 516 : break;
2364 18 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2365 18 : 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 1686 : if ( error != IVAS_ERR_OK )
2371 : {
2372 0 : return error;
2373 : }
2374 :
2375 : /* Copy LFE routing to pan gains array */
2376 1686 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
2377 : {
2378 630 : 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 1056 : mvr2r( inputMc->lfeRouting.lfePanMtx[0], inputMc->panGains[LFE_CHANNEL], RENDERER_MAX_OUTPUT_CHANNELS );
2387 : }
2388 :
2389 1686 : return IVAS_ERR_OK;
2390 : }
2391 :
2392 :
2393 14225070 : 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 14225070 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_MONO || inputMc->base.inConfig == IVAS_AUDIO_CONFIG_STEREO )
2409 : {
2410 3843327 : 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 10381743 : useTDRend = FALSE;
2416 10381743 : if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
2417 : {
2418 7529232 : if ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
2419 : {
2420 947214 : useTDRend = TRUE;
2421 : }
2422 6582018 : else if ( ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) &&
2423 2261372 : ( inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2424 : {
2425 1041212 : useTDRend = TRUE;
2426 : }
2427 : }
2428 :
2429 : /* if TD renderer was open and we need to use CREND, close it */
2430 10381743 : if ( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) )
2431 : {
2432 516 : ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
2433 : }
2434 :
2435 10381743 : if ( !reconfigureFlag || !useTDRend )
2436 : {
2437 67147368 : for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2438 : {
2439 58753947 : 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 10381743 : if ( useTDRend )
2448 : {
2449 1988426 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2450 : }
2451 :
2452 10381743 : if ( !reconfigureFlag || ( !useTDRend && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB && inputMc->hReverb != NULL ) )
2453 : {
2454 516 : ivas_reverb_close( &inputMc->hReverb );
2455 : }
2456 :
2457 10381743 : if ( !reconfigureFlag || ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM && !inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
2458 : {
2459 1093341 : if ( inputMc->efapInWrapper.hEfap != NULL )
2460 : {
2461 108 : efap_free_data( &inputMc->efapInWrapper.hEfap );
2462 : }
2463 : }
2464 :
2465 10381743 : outSampleRate = *inputMc->base.ctx.pOutSampleRate;
2466 :
2467 10381743 : if ( useTDRend && inputMc->tdRendWrapper.hBinRendererTd == NULL )
2468 : {
2469 104 : 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 104 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
2475 : {
2476 : /* Open TD renderer wrappers */
2477 0 : for ( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
2478 : {
2479 0 : 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 0 : assert( inputMc->splitTdRendWrappers[i].binaural_latency_ns == inputMc->tdRendWrapper.binaural_latency_ns );
2486 : }
2487 : }
2488 :
2489 104 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB && inputMc->hReverb == NULL )
2490 : {
2491 16 : if ( ( error = ivas_reverb_open( &( inputMc->hReverb ), hHrtfStatistics, hRendCfg, outSampleRate ) ) != IVAS_ERR_OK )
2492 : {
2493 0 : return error;
2494 : }
2495 : }
2496 : }
2497 10381639 : else if ( !useTDRend && inputMc->crendWrapper == NULL )
2498 : {
2499 : /* open CREND */
2500 680 : 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 340 : 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 10381743 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inputMc->base.ctx.pHeadRotData->headRotEnabled && inputMc->efapInWrapper.hEfap == NULL )
2509 : {
2510 120 : 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 10381743 : binauralDelayNs = max( ( inputMc->crendWrapper != NULL ) ? inputMc->crendWrapper->binaural_latency_ns : 0, inputMc->tdRendWrapper.binaural_latency_ns );
2518 10381743 : inputMc->binauralDelaySmp = latencyNsToSamples( *inputMc->base.ctx.pOutSampleRate, binauralDelayNs );
2519 :
2520 10381743 : 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 10381743 : return IVAS_ERR_OK;
2526 : }
2527 :
2528 :
2529 18 : 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 18 : if ( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2537 : {
2538 0 : ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
2539 : }
2540 :
2541 18 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2542 :
2543 18 : ivas_reverb_close( &inputMc->hReverb );
2544 :
2545 18 : if ( inputMc->efapInWrapper.hEfap != NULL )
2546 : {
2547 0 : efap_free_data( &inputMc->efapInWrapper.hEfap );
2548 : }
2549 :
2550 18 : if ( ( error = ivas_mcmasa_ana_open( &inputMc->hMcMasa, inConfig, inSampleRate ) ) != IVAS_ERR_OK )
2551 : {
2552 0 : return error;
2553 : }
2554 :
2555 18 : return IVAS_ERR_OK;
2556 : }
2557 :
2558 :
2559 1686 : 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 8430 : for ( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i )
2571 : {
2572 6744 : set_zero( routing.lfePanMtx[i], RENDERER_MAX_OUTPUT_CHANNELS );
2573 : }
2574 :
2575 1686 : routing.pan_lfe = false;
2576 1686 : routing.lfeInputGain = 1.0f;
2577 :
2578 1686 : switch ( inConfig )
2579 : {
2580 723 : 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 723 : routing.numLfeChannels = 1;
2586 723 : break;
2587 630 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2588 630 : routing.numLfeChannels = customLsIn.num_lfe;
2589 630 : break;
2590 333 : default:
2591 333 : routing.numLfeChannels = 0;
2592 : }
2593 :
2594 1686 : switch ( outConfig )
2595 : {
2596 450 : 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 450 : routing.lfePanMtx[0][LFE_CHANNEL] = 1.0f;
2602 450 : break;
2603 117 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2604 117 : 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 117 : break;
2609 1119 : default:
2610 : /* Do nothing */
2611 1119 : break;
2612 : }
2613 :
2614 1686 : return routing;
2615 : }
2616 :
2617 :
2618 1371 : 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 1371 : inputMc = (input_mc *) input;
2633 1371 : rendCtx = inputMc->base.ctx;
2634 1371 : outConfig = *rendCtx.pOutConfig;
2635 :
2636 1371 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
2637 : {
2638 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2639 : }
2640 :
2641 1371 : if ( ( error = allocateMcLfeDelayBuffer( &inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES ) ) != IVAS_ERR_OK )
2642 : {
2643 0 : return error;
2644 : }
2645 :
2646 1371 : if ( ( error = allocateInputBaseBufferData( &inputMc->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
2647 : {
2648 0 : return error;
2649 : }
2650 1371 : initRendInputBase( &inputMc->base, inConfig, id, rendCtx, inputMc->bufferData, MAX_BUFFER_LENGTH );
2651 :
2652 1371 : setZeroPanMatrix( inputMc->panGains );
2653 1371 : inputMc->customLsInput = defaultCustomLs();
2654 1371 : inputMc->tdRendWrapper = defaultTdRendWrapper();
2655 :
2656 1371 : if ( hrtfs->hHrtfTD )
2657 : {
2658 0 : inputMc->tdRendWrapper.binaural_latency_ns = (int32_t) ( hrtfs->hHrtfTD->latency_s * 1000000000.f );
2659 : }
2660 1371 : inputMc->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
2661 1371 : inputMc->crendWrapper = NULL;
2662 1371 : inputMc->hReverb = NULL;
2663 1371 : inputMc->hMcMasa = NULL;
2664 :
2665 12339 : for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
2666 : {
2667 10968 : initRotGains( inputMc->rot_gains_prev[pos_idx] );
2668 : }
2669 1371 : inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut );
2670 1371 : set_zero( inputMc->lfeDelayBuffer, MAX_BIN_DELAY_SAMPLES );
2671 1371 : inputMc->binauralDelaySmp = 0;
2672 :
2673 10968 : for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i )
2674 : {
2675 9597 : inputMc->splitTdRendWrappers[i] = defaultTdRendWrapper();
2676 9597 : if ( hrtfs->hHrtfTD )
2677 : {
2678 0 : inputMc->splitTdRendWrappers[i].binaural_latency_ns = (int32_t) ( hrtfs->hHrtfTD->latency_s * 1000000000.f );
2679 : }
2680 9597 : inputMc->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
2681 : }
2682 :
2683 1371 : if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
2684 : {
2685 528 : if ( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics, FALSE ) ) != IVAS_ERR_OK )
2686 : {
2687 0 : return error;
2688 : }
2689 : }
2690 :
2691 1371 : if ( outConfig == IVAS_AUDIO_CONFIG_MASA1 || outConfig == IVAS_AUDIO_CONFIG_MASA2 )
2692 : {
2693 18 : if ( ( error = initMcMasaRendering( inputMc, inConfig, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2694 : {
2695 0 : return error;
2696 : }
2697 : }
2698 :
2699 1371 : if ( ( error = updateMcPanGains( inputMc, outConfig ) ) != IVAS_ERR_OK )
2700 : {
2701 0 : return error;
2702 : }
2703 :
2704 1371 : return IVAS_ERR_OK;
2705 : }
2706 :
2707 :
2708 5151 : static void clearInputMc(
2709 : input_mc *inputMc )
2710 : {
2711 : int16_t i;
2712 : rendering_context rendCtx;
2713 :
2714 5151 : rendCtx = inputMc->base.ctx;
2715 :
2716 5151 : freeMcLfeDelayBuffer( &inputMc->lfeDelayBuffer );
2717 5151 : freeInputBaseBufferData( &inputMc->bufferData );
2718 5151 : ivas_TD_RINGBUF_Close( &inputMc->base.delayBuffer );
2719 :
2720 5151 : initRendInputBase( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
2721 :
2722 : /* Free input's internal handles */
2723 5151 : if ( inputMc->efapInWrapper.hEfap != NULL )
2724 : {
2725 327 : efap_free_data( &inputMc->efapInWrapper.hEfap );
2726 : }
2727 :
2728 5151 : ivas_rend_closeCrend( &inputMc->crendWrapper );
2729 :
2730 5151 : ivas_reverb_close( &inputMc->hReverb );
2731 :
2732 5151 : if ( inputMc->tdRendWrapper.hBinRendererTd != NULL )
2733 : {
2734 68 : ivas_td_binaural_close( &inputMc->tdRendWrapper.hBinRendererTd );
2735 : }
2736 :
2737 41208 : for ( i = 0; i < (int16_t) ( sizeof( inputMc->splitTdRendWrappers ) / sizeof( *inputMc->splitTdRendWrappers ) ); ++i )
2738 : {
2739 36057 : if ( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
2740 : {
2741 0 : ivas_td_binaural_close( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
2742 : }
2743 : }
2744 :
2745 5151 : ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
2746 :
2747 5151 : return;
2748 : }
2749 :
2750 :
2751 1029 : 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 1029 : if ( ( error = getAmbisonicsOrder( inputSba->base.inConfig, &ambiOrderIn ) ) != IVAS_ERR_OK )
2763 : {
2764 0 : return error;
2765 : }
2766 :
2767 1029 : 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 1029 : switch ( outConfig )
2774 : {
2775 96 : case IVAS_AUDIO_CONFIG_MONO:
2776 96 : hOutSetup.ls_azimuth = ls_azimuth_CICP1;
2777 96 : hOutSetup.ls_elevation = ls_elevation_CICP1;
2778 96 : ivas_output_init( &hOutSetup, outConfig );
2779 96 : break;
2780 798 : 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 798 : ivas_output_init( &hOutSetup, outConfig );
2787 798 : break;
2788 135 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
2789 135 : ivas_ls_custom_setup( &hOutSetup, outSetupCustom );
2790 135 : 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 1029 : tmpDecMtx = NULL;
2798 1029 : if ( ( error = ivas_sba_get_hoa_dec_matrix( hOutSetup, &tmpDecMtx, ambiOrderIn ) ) != IVAS_ERR_OK )
2799 : {
2800 0 : return error;
2801 : }
2802 :
2803 1029 : readPtr = &tmpDecMtx[0];
2804 9825 : for ( chOutIdx = 0; chOutIdx < hOutSetup.nchan_out_woLFE + hOutSetup.num_lfe; ++chOutIdx )
2805 : {
2806 149532 : for ( chInIdx = 0; chInIdx < SBA_NHARM_HOA3; ++chInIdx )
2807 : {
2808 140736 : if ( hOutSetup.num_lfe > 0 && chOutIdx == hOutSetup.index_lfe[0] )
2809 : {
2810 11232 : continue; /* nothing to be rendered to LFE */
2811 : }
2812 129504 : inputSba->hoaDecMtx[chInIdx][chOutIdx] = *readPtr++;
2813 : }
2814 : }
2815 :
2816 1029 : free( tmpDecMtx );
2817 :
2818 1029 : return IVAS_ERR_OK;
2819 : }
2820 :
2821 :
2822 288 : static ivas_error initSbaPanGainsForSbaOut(
2823 : input_sba *inputSba,
2824 : const AUDIO_CONFIG outConfig )
2825 : {
2826 : ivas_error error;
2827 288 : error = IVAS_ERR_OK;
2828 :
2829 288 : if ( getAudioConfigType( outConfig ) != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
2830 : {
2831 0 : assert( !"Invalid configuration" );
2832 : return IVAS_ERR_WRONG_PARAMS;
2833 : }
2834 :
2835 288 : fillIdentityPanMatrix( inputSba->hoaDecMtx );
2836 :
2837 288 : return error;
2838 : }
2839 :
2840 :
2841 2049 : 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 2049 : setZeroPanMatrix( inputSba->hoaDecMtx );
2854 :
2855 2049 : inConfig = inputSba->base.inConfig;
2856 2049 : rendCtx = inputSba->base.ctx;
2857 :
2858 2049 : switch ( getAudioConfigType( outConfig ) )
2859 : {
2860 807 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
2861 807 : error = initSbaPanGainsForMcOut( inputSba, outConfig, inputSba->base.ctx.pCustomLsOut );
2862 807 : break;
2863 288 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
2864 288 : error = initSbaPanGainsForSbaOut( inputSba, outConfig );
2865 288 : break;
2866 936 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
2867 : switch ( outConfig )
2868 : {
2869 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
2870 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
2871 : {
2872 0 : if ( hRendCfg->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
2873 : {
2874 0 : assert( *rendCtx.pOutSampleRate == 48000 && "split binaural fast conv mode is currently supported with 48k sampling rate only" );
2875 0 : 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 0 : assert( ( *rendCtx.pOutSampleRate == 48000 ) && "split binaural crend mode is currently supported with 48k sampling rate only" );
2883 0 : 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 0 : break;
2889 : }
2890 714 : case IVAS_AUDIO_CONFIG_BINAURAL:
2891 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
2892 714 : 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 714 : 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 714 : break;
2907 222 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
2908 222 : if ( ( error = initSbaPanGainsForMcOut( inputSba, IVAS_AUDIO_CONFIG_7_1_4, NULL ) ) != IVAS_ERR_OK )
2909 : {
2910 0 : return error;
2911 : }
2912 :
2913 222 : 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 222 : break;
2918 0 : default:
2919 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
2920 : }
2921 936 : break;
2922 18 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
2923 18 : error = IVAS_ERR_OK;
2924 18 : 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 2049 : if ( error != IVAS_ERR_OK )
2931 : {
2932 0 : return error;
2933 : }
2934 :
2935 2049 : return IVAS_ERR_OK;
2936 : }
2937 :
2938 :
2939 18 : static ivas_error initSbaMasaRendering(
2940 : input_sba *inputSba,
2941 : int32_t inSampleRate )
2942 : {
2943 : ivas_error error;
2944 :
2945 18 : ivas_rend_closeCrend( &inputSba->crendWrapper );
2946 :
2947 18 : if ( ( error = ivas_dirac_ana_open( &inputSba->hDirAC, inSampleRate ) ) != IVAS_ERR_OK )
2948 : {
2949 0 : return error;
2950 : }
2951 :
2952 18 : return IVAS_ERR_OK;
2953 : }
2954 :
2955 :
2956 2049 : 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 2049 : inputSba = (input_sba *) input;
2970 2049 : rendCtx = inputSba->base.ctx;
2971 2049 : outConfig = *rendCtx.pOutConfig;
2972 :
2973 2049 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
2974 : {
2975 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
2976 : }
2977 :
2978 2049 : if ( ( error = allocateInputBaseBufferData( &inputSba->bufferData, MAX_CLDFB_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
2979 : {
2980 0 : return error;
2981 : }
2982 :
2983 2049 : initRendInputBase( &inputSba->base, inConfig, id, rendCtx, inputSba->bufferData, MAX_CLDFB_BUFFER_LENGTH );
2984 :
2985 2049 : setZeroPanMatrix( inputSba->hoaDecMtx );
2986 :
2987 2049 : inputSba->crendWrapper = NULL;
2988 18441 : for ( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
2989 : {
2990 16392 : initRotGains( inputSba->rot_gains_prev[pos_idx] );
2991 : }
2992 2049 : inputSba->cldfbRendWrapper.hHrtfFastConv = hrtfs->hHrtfFastConv;
2993 :
2994 2049 : if ( outConfig == IVAS_AUDIO_CONFIG_MASA1 || outConfig == IVAS_AUDIO_CONFIG_MASA2 )
2995 : {
2996 18 : if ( ( error = initSbaMasaRendering( inputSba, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
2997 : {
2998 0 : return error;
2999 : }
3000 : }
3001 :
3002 2049 : if ( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg, hrtfs->hHrtfCrend, hrtfs->hHrtfStatistics ) ) != IVAS_ERR_OK )
3003 : {
3004 0 : return error;
3005 : }
3006 :
3007 2049 : return IVAS_ERR_OK;
3008 : }
3009 :
3010 :
3011 5151 : static void clearInputSba(
3012 : input_sba *inputSba )
3013 : {
3014 : rendering_context rendCtx;
3015 :
3016 5151 : rendCtx = inputSba->base.ctx;
3017 :
3018 5151 : freeInputBaseBufferData( &inputSba->bufferData );
3019 5151 : ivas_TD_RINGBUF_Close( &inputSba->base.delayBuffer );
3020 :
3021 5151 : initRendInputBase( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3022 :
3023 : /* Free input's internal handles */
3024 5151 : ivas_rend_closeCrend( &inputSba->crendWrapper );
3025 :
3026 5151 : if ( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
3027 : {
3028 0 : ivas_rend_closeCldfbRend( &inputSba->cldfbRendWrapper );
3029 : }
3030 :
3031 5151 : ivas_dirac_ana_close( &( inputSba->hDirAC ) );
3032 :
3033 5151 : return;
3034 : }
3035 :
3036 :
3037 1296 : 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 1296 : inputMasa = (input_masa *) input;
3051 1296 : rendCtx = inputMasa->base.ctx;
3052 1296 : outConfig = *rendCtx.pOutConfig;
3053 :
3054 1296 : if ( !isIoConfigPairSupported( inConfig, outConfig ) )
3055 : {
3056 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
3057 : }
3058 :
3059 1296 : if ( ( error = allocateInputBaseBufferData( &inputMasa->bufferData, MAX_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
3060 : {
3061 0 : return error;
3062 : }
3063 1296 : initRendInputBase( &inputMasa->base, inConfig, id, rendCtx, inputMasa->bufferData, MAX_BUFFER_LENGTH );
3064 :
3065 1296 : if ( ( error = getAudioConfigNumChannels( inConfig, &numInChannels ) ) != IVAS_ERR_OK )
3066 : {
3067 0 : return error;
3068 : }
3069 :
3070 1296 : if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
3071 : {
3072 66 : inputMasa->metadataHasBeenFed = false;
3073 66 : 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 1230 : if ( ( error = initMasaExtRenderer( inputMasa, outConfig, hRendCfg, hrtfs ) ) != IVAS_ERR_OK )
3081 : {
3082 0 : return error;
3083 : }
3084 1230 : inputMasa->metadataHasBeenFed = false;
3085 : }
3086 :
3087 1296 : return IVAS_ERR_OK;
3088 : }
3089 :
3090 :
3091 5151 : static void clearInputMasa(
3092 : input_masa *inputMasa )
3093 : {
3094 : rendering_context rendCtx;
3095 :
3096 5151 : rendCtx = inputMasa->base.ctx;
3097 :
3098 5151 : freeInputBaseBufferData( &inputMasa->bufferData );
3099 5151 : ivas_TD_RINGBUF_Close( &inputMasa->base.delayBuffer );
3100 :
3101 5151 : masaPrerendClose( &inputMasa->hMasaPrerend );
3102 5151 : freeMasaExtRenderer( &inputMasa->hMasaExtRend );
3103 :
3104 5151 : initRendInputBase( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
3105 :
3106 5151 : return;
3107 : }
3108 :
3109 :
3110 : /*-------------------------------------------------------------------------
3111 : * IVAS_REND_Open()
3112 : *
3113 : *
3114 : *------------------------------------------------------------------------*/
3115 :
3116 5151 : 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 5151 : if ( phIvasRend == NULL )
3136 : {
3137 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3138 : }
3139 :
3140 5151 : if ( ( error = validateOutputAudioConfig( outConfig ) ) != IVAS_ERR_OK )
3141 : {
3142 0 : return error;
3143 : }
3144 :
3145 5151 : if ( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ) != IVAS_ERR_OK )
3146 : {
3147 0 : return error;
3148 : }
3149 :
3150 5151 : *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
3151 5151 : if ( *phIvasRend == NULL )
3152 : {
3153 0 : return IVAS_ERR_FAILED_ALLOC;
3154 : }
3155 :
3156 5151 : hIvasRend = *phIvasRend;
3157 5151 : hIvasRend->sampleRateOut = outputSampleRate;
3158 5151 : hIvasRend->outputConfig = outConfig;
3159 5151 : hIvasRend->customLsOut = defaultCustomLs();
3160 5151 : hIvasRend->hLimiter = NULL;
3161 5151 : hIvasRend->efapOutWrapper.hEfap = NULL;
3162 5151 : hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
3163 5151 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_UNSET;
3164 : #ifdef DEBUGGING
3165 : hIvasRend->numClipping = 0;
3166 : #endif
3167 5151 : hIvasRend->num_subframes = num_subframes;
3168 :
3169 : /* Initialize limiter */
3170 5151 : if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
3171 : {
3172 0 : return error;
3173 : }
3174 :
3175 5151 : if ( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ) != IVAS_ERR_OK )
3176 : {
3177 0 : return error;
3178 : }
3179 :
3180 : /* Initialize headrotation data */
3181 5151 : hIvasRend->headRotData.headRotEnabled = 0;
3182 5151 : if ( Opt_Headrotation )
3183 : {
3184 876 : if ( ( error = initHeadRotation( hIvasRend ) ) != IVAS_ERR_OK )
3185 : {
3186 0 : return error;
3187 : }
3188 : }
3189 :
3190 : /* Initialize external orientation data */
3191 5151 : hIvasRend->hExternalOrientationData = NULL;
3192 5151 : 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 5151 : hIvasRend->hCombinedOrientationData = NULL;
3202 5151 : if ( Opt_Headrotation || Opt_ExternalOrientation )
3203 : {
3204 876 : 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 5151 : if ( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ) != IVAS_ERR_OK )
3212 : {
3213 0 : return error;
3214 : }
3215 :
3216 : /* Initialize inputs */
3217 :
3218 5151 : hIvasRend->splitRendWrapper = NULL;
3219 5151 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
3220 : {
3221 0 : 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 0 : isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
3227 : }
3228 5151 : hIvasRend->splitRendEncBuffer.data = NULL;
3229 5151 : hIvasRend->splitRendEncBuffer.config.is_cldfb = 0;
3230 5151 : hIvasRend->splitRendEncBuffer.config.numChannels = 0;
3231 5151 : hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = 0;
3232 :
3233 25755 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
3234 : {
3235 20604 : initRendInputBase( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3236 :
3237 20604 : hIvasRend->inputsIsm[i].crendWrapper = NULL;
3238 20604 : hIvasRend->inputsIsm[i].hReverb = NULL;
3239 20604 : hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
3240 164832 : for ( j = 0; j < (int16_t) ( sizeof( hIvasRend->inputsIsm[i].splitTdRendWrappers ) / sizeof( *hIvasRend->inputsIsm[i].splitTdRendWrappers ) ); ++j )
3241 : {
3242 144228 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3243 144228 : hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3244 : }
3245 20604 : hIvasRend->inputsIsm[i].bufferData = NULL;
3246 20604 : hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
3247 20604 : hIvasRend->inputsIsm[i].nonDiegeticPanGain = nonDiegeticPanGain;
3248 20604 : hIvasRend->inputsIsm[i].hOMasa = NULL;
3249 : }
3250 :
3251 10302 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3252 : {
3253 5151 : initRendInputBase( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3254 :
3255 5151 : hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
3256 5151 : hIvasRend->inputsMc[i].crendWrapper = NULL;
3257 5151 : hIvasRend->inputsMc[i].hReverb = NULL;
3258 5151 : hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
3259 5151 : hIvasRend->inputsMc[i].bufferData = NULL;
3260 5151 : hIvasRend->inputsMc[i].lfeDelayBuffer = NULL;
3261 5151 : hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
3262 5151 : hIvasRend->inputsMc[i].nonDiegeticPanGain = nonDiegeticPanGain;
3263 5151 : hIvasRend->inputsMc[i].hMcMasa = NULL;
3264 41208 : for ( j = 0; j < (int16_t) ( sizeof( hIvasRend->inputsMc[i].splitTdRendWrappers ) / sizeof( *hIvasRend->inputsMc[i].splitTdRendWrappers ) ); ++j )
3265 : {
3266 36057 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
3267 36057 : hIvasRend->inputsMc[i].splitTdRendWrappers[j].hHrtfTD = NULL;
3268 : }
3269 : }
3270 :
3271 10302 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3272 : {
3273 5151 : initRendInputBase( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3274 :
3275 5151 : hIvasRend->inputsSba[i].crendWrapper = NULL;
3276 5151 : hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend = NULL;
3277 5151 : hIvasRend->inputsSba[i].cldfbRendWrapper.hHrtfFastConv = NULL;
3278 5151 : hIvasRend->inputsSba[i].bufferData = NULL;
3279 5151 : hIvasRend->inputsSba[i].hDirAC = NULL;
3280 : }
3281 :
3282 10302 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3283 : {
3284 5151 : initRendInputBase( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
3285 :
3286 5151 : hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
3287 5151 : hIvasRend->inputsMasa[i].bufferData = NULL;
3288 5151 : hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
3289 5151 : hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
3290 : }
3291 :
3292 :
3293 5151 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
3294 5151 : hIvasRend->hHrtfs.hHrtfParambin = NULL;
3295 5151 : hIvasRend->hHrtfs.hHrtfTD = NULL;
3296 5151 : hIvasRend->hHrtfs.hHrtfCrend = NULL;
3297 5151 : hIvasRend->hHrtfs.hHrtfStatistics = NULL;
3298 5151 : 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 5151 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB )
3323 : {
3324 1180 : if ( hIvasRend->hHrtfs.hHrtfStatistics == NULL )
3325 : {
3326 : /* Allocate and init HRTF statistics */
3327 1180 : if ( ( error = ivas_reverb_HRTF_statistics_open( &( hIvasRend->hHrtfs.hHrtfStatistics ), outputSampleRate ) ) != IVAS_ERR_OK )
3328 : {
3329 0 : return error;
3330 : }
3331 : }
3332 : }
3333 :
3334 5151 : return IVAS_ERR_OK;
3335 : }
3336 :
3337 :
3338 666 : 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 666 : customLs.num_spk = rendCustomLsLayout.num_spk;
3346 666 : mvr2r( rendCustomLsLayout.azimuth, customLs.ls_azimuth, rendCustomLsLayout.num_spk );
3347 666 : mvr2r( rendCustomLsLayout.elevation, customLs.ls_elevation, rendCustomLsLayout.num_spk );
3348 :
3349 666 : customLs.is_planar_setup = 1;
3350 3330 : for ( i = 0; i < rendCustomLsLayout.num_spk; ++i )
3351 : {
3352 3330 : if ( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
3353 : {
3354 666 : customLs.is_planar_setup = 0;
3355 666 : break;
3356 : }
3357 : }
3358 :
3359 666 : customLs.num_lfe = rendCustomLsLayout.num_lfe;
3360 666 : mvs2s( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
3361 :
3362 666 : return customLs;
3363 : }
3364 :
3365 :
3366 666 : 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 666 : 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 666 : 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 666 : 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 666 : return IVAS_ERR_OK;
3393 : }
3394 :
3395 :
3396 : /*-------------------------------------------------------------------*
3397 : * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
3398 : *
3399 : *
3400 : *-------------------------------------------------------------------*/
3401 :
3402 351 : 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 351 : if ( hIvasRend == NULL )
3413 : {
3414 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3415 : }
3416 :
3417 351 : 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 351 : if ( ( error = validateCustomLsLayout( layout ) ) != IVAS_ERR_OK )
3424 : {
3425 0 : return error;
3426 : }
3427 :
3428 351 : hIvasRend->customLsOut = makeCustomLsSetup( layout );
3429 :
3430 : /* Re-initialize limiter - number of output channels may have changed */
3431 351 : if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
3432 : {
3433 0 : return error;
3434 : }
3435 :
3436 351 : 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 351 : 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 702 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
3451 : {
3452 351 : inputMc = &hIvasRend->inputsMc[i];
3453 351 : if ( inputMc->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
3454 : {
3455 : /* Input inactive, skip. */
3456 351 : 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 702 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3469 : {
3470 351 : inputSba = &hIvasRend->inputsSba[i];
3471 :
3472 351 : if ( inputSba->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
3473 : {
3474 : /* Input inactive, skip. */
3475 351 : 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 351 : return IVAS_ERR_OK;
3485 : }
3486 :
3487 :
3488 : /*-------------------------------------------------------------------*
3489 : * IVAS_REND_GetNumOutChannels()
3490 : *
3491 : *
3492 : *-------------------------------------------------------------------*/
3493 :
3494 93753834 : 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 93753834 : 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 93753834 : switch ( hIvasRend->outputConfig )
3508 : {
3509 2693538 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
3510 2693538 : *numOutChannels = hIvasRend->customLsOut.num_spk + hIvasRend->customLsOut.num_lfe;
3511 2693538 : break;
3512 91060296 : default:
3513 91060296 : if ( ( error = getAudioConfigNumChannels( hIvasRend->outputConfig, numOutChannels ) ) != IVAS_ERR_OK )
3514 : {
3515 0 : return error;
3516 : }
3517 91060296 : break;
3518 : }
3519 :
3520 93753834 : return IVAS_ERR_OK;
3521 : }
3522 :
3523 :
3524 12477 : 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 12477 : return (IVAS_REND_InputId) ( ( ( (uint32_t) getAudioConfigType( config ) ) << 8 ) | ( inputIndex + 1 ) );
3532 : }
3533 :
3534 :
3535 355555371 : 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 355555371 : inputIndex = ( inputId & 0xFF ) - 1;
3546 355555371 : configType = ( inputId & 0xFF00 ) >> 8;
3547 :
3548 : /* Validate values derived from input ID */
3549 355555371 : if ( inputIndex < 0 )
3550 : {
3551 0 : return IVAS_ERR_INVALID_INPUT_ID;
3552 : }
3553 355555371 : switch ( configType )
3554 : {
3555 264294207 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3556 264294207 : if ( inputIndex > RENDERER_MAX_ISM_INPUTS )
3557 : {
3558 0 : return IVAS_ERR_INVALID_INPUT_ID;
3559 : }
3560 264294207 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3561 264294207 : break;
3562 25689819 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3563 25689819 : if ( inputIndex > RENDERER_MAX_MC_INPUTS )
3564 : {
3565 0 : return IVAS_ERR_INVALID_INPUT_ID;
3566 : }
3567 25689819 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3568 25689819 : break;
3569 38943558 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3570 38943558 : if ( inputIndex > RENDERER_MAX_SBA_INPUTS )
3571 : {
3572 0 : return IVAS_ERR_INVALID_INPUT_ID;
3573 : }
3574 38943558 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3575 38943558 : break;
3576 26627787 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3577 26627787 : if ( inputIndex > RENDERER_MAX_MASA_INPUTS )
3578 : {
3579 0 : return IVAS_ERR_INVALID_INPUT_ID;
3580 : }
3581 26627787 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3582 26627787 : 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 355555371 : 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 355555371 : *ppInput = pInputBase;
3595 :
3596 355555371 : return IVAS_ERR_OK;
3597 : }
3598 :
3599 :
3600 83294205 : 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 83294205 : inputIndex = ( inputId & 0xFF ) - 1;
3611 83294205 : configType = ( inputId & 0xFF00 ) >> 8;
3612 :
3613 : /* Validate values derived from input ID */
3614 83294205 : if ( inputIndex < 0 )
3615 : {
3616 0 : return IVAS_ERR_INVALID_INPUT_ID;
3617 : }
3618 83294205 : switch ( configType )
3619 : {
3620 7761 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3621 7761 : if ( inputIndex > RENDERER_MAX_ISM_INPUTS )
3622 : {
3623 0 : return IVAS_ERR_INVALID_INPUT_ID;
3624 : }
3625 7761 : pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
3626 7761 : break;
3627 25689504 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3628 25689504 : if ( inputIndex > RENDERER_MAX_MC_INPUTS )
3629 : {
3630 0 : return IVAS_ERR_INVALID_INPUT_ID;
3631 : }
3632 25689504 : pInputBase = &hIvasRend->inputsMc[inputIndex].base;
3633 25689504 : break;
3634 38943558 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3635 38943558 : if ( inputIndex > RENDERER_MAX_SBA_INPUTS )
3636 : {
3637 0 : return IVAS_ERR_INVALID_INPUT_ID;
3638 : }
3639 38943558 : pInputBase = &hIvasRend->inputsSba[inputIndex].base;
3640 38943558 : break;
3641 18653382 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3642 18653382 : if ( inputIndex > RENDERER_MAX_MASA_INPUTS )
3643 : {
3644 0 : return IVAS_ERR_INVALID_INPUT_ID;
3645 : }
3646 18653382 : pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
3647 18653382 : 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 83294205 : 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 83294205 : *ppInput = pInputBase;
3660 :
3661 83294205 : return IVAS_ERR_OK;
3662 : }
3663 :
3664 :
3665 44991 : static void *getInputByIndex(
3666 : void *inputsArray,
3667 : const size_t index,
3668 : const IVAS_REND_AudioConfigType inputType )
3669 : {
3670 44991 : switch ( inputType )
3671 : {
3672 4113 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3673 4113 : return (input_mc *) inputsArray + index;
3674 6147 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3675 6147 : return (input_sba *) inputsArray + index;
3676 30843 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3677 30843 : return (input_ism *) inputsArray + index;
3678 3888 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
3679 3888 : 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 12477 : 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 12477 : canAddInput = false;
3709 :
3710 : /* Find first unused input in array */
3711 20037 : for ( i = 0; i < maxInputs; ++i )
3712 : {
3713 20037 : pInputBase = (const input_base *) getInputByIndex( inputs, i, inputType );
3714 :
3715 20037 : if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
3716 : {
3717 12477 : *inputIndex = i;
3718 12477 : canAddInput = true;
3719 12477 : break;
3720 : }
3721 : }
3722 :
3723 12477 : if ( !canAddInput )
3724 : {
3725 0 : return IVAS_ERR_TOO_MANY_INPUTS;
3726 : }
3727 :
3728 12477 : return IVAS_ERR_OK;
3729 : }
3730 :
3731 :
3732 : /*-------------------------------------------------------------------------
3733 : * Function getCldfbRendFlag()
3734 : *
3735 : *
3736 : *------------------------------------------------------------------------*/
3737 :
3738 5304 : 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 5304 : int16_t numMasaInputs = 0, numSbaInputs = 0;
3744 : int16_t isCldfbRend;
3745 :
3746 5304 : 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 5304 : if ( hIvasRend->hRendererConfig != NULL )
3753 : {
3754 10608 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
3755 : {
3756 5304 : numMasaInputs += ( hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ? 0 : 1;
3757 : }
3758 10608 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
3759 : {
3760 5304 : numSbaInputs += ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1;
3761 : }
3762 5304 : if ( ( numMasaInputs > 0 ) || ( numSbaInputs > 0 && hIvasRend->hRendererConfig->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV ) )
3763 : {
3764 540 : isCldfbRend = 1;
3765 : }
3766 : }
3767 :
3768 5304 : return isCldfbRend;
3769 : }
3770 :
3771 : /*-------------------------------------------------------------------------
3772 : * Function isar_pre_rend_init()
3773 : *
3774 : *
3775 : *------------------------------------------------------------------------*/
3776 :
3777 5304 : 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 5304 : realloc = false;
3792 :
3793 : /* only perform init if split rendering output */
3794 5304 : if ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
3795 : {
3796 5304 : return IVAS_ERR_OK;
3797 : }
3798 :
3799 : /* these functions should only be called once during initial allocation */
3800 0 : if ( pSplitRendEncBuffer->data == NULL )
3801 : {
3802 0 : if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
3803 : {
3804 0 : ISAR_PRE_REND_GetMultiBinPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData, headRotData.sr_pose_pred_axis );
3805 : }
3806 0 : else if ( pSplit_rend_config->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
3807 : {
3808 0 : isar_renderSplitUpdateNoCorrectionPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData );
3809 : }
3810 :
3811 0 : if ( ( error = ISAR_PRE_REND_open( pSplitRendWrapper, pSplit_rend_config, outputSampleRate, cldfb_in_flag, outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM, num_subframes, 0 ) ) != IVAS_ERR_OK )
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 0 : if ( pSplitRendEncBuffer->data != NULL && ( cldfb_in_flag != pSplitRendEncBuffer->config.is_cldfb ) )
3820 : {
3821 0 : realloc = true;
3822 : }
3823 :
3824 0 : if ( pSplitRendEncBuffer->data == NULL || realloc )
3825 : {
3826 : /* set buffer config */
3827 0 : bufConfig.is_cldfb = cldfb_in_flag;
3828 0 : bufConfig.numSamplesPerChannel = cldfb_in_flag ? MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL : L_FRAME_MAX;
3829 0 : bufConfig.numChannels = BINAURAL_CHANNELS * pSplitRendWrapper->multiBinPoseData.num_poses;
3830 0 : pSplitRendEncBuffer->config = bufConfig;
3831 :
3832 : /* allocate memory */
3833 0 : if ( realloc )
3834 : {
3835 0 : free( pSplitRendEncBuffer->data );
3836 : }
3837 :
3838 0 : if ( ( pSplitRendEncBuffer->data = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL )
3839 : {
3840 0 : return IVAS_ERR_FAILED_ALLOC;
3841 : }
3842 : }
3843 :
3844 0 : return IVAS_ERR_OK;
3845 : }
3846 :
3847 :
3848 : /*-------------------------------------------------------------------------
3849 : * Function getDefaultReverbSize()
3850 : *
3851 : *
3852 : *------------------------------------------------------------------------*/
3853 :
3854 5151 : 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 5151 : selectedReverb = IVAS_ROOM_SIZE_MEDIUM;
3865 :
3866 5151 : combinedFormat = false;
3867 5151 : nActiveInputsIsm = 0;
3868 5151 : nActiveInputsMasa = 0;
3869 5151 : nActiveInputsMc = 0;
3870 5151 : nActiveInputsSba = 0;
3871 :
3872 25755 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
3873 : {
3874 20604 : if ( ismInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3875 : {
3876 3039 : nActiveInputsIsm++;
3877 : }
3878 : }
3879 10302 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
3880 : {
3881 5151 : if ( masaInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3882 : {
3883 246 : nActiveInputsMasa++;
3884 : }
3885 : }
3886 10302 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
3887 : {
3888 5151 : if ( mcInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3889 : {
3890 1371 : nActiveInputsMc++;
3891 : }
3892 : }
3893 10302 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
3894 : {
3895 5151 : if ( sbaInputs[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
3896 : {
3897 495 : nActiveInputsSba++;
3898 : }
3899 : }
3900 :
3901 : /* ISM present with MASA/SBA inputs; treat as combined format */
3902 5151 : if ( nActiveInputsIsm && ( nActiveInputsMasa || nActiveInputsSba ) )
3903 : {
3904 0 : combinedFormat = true;
3905 : }
3906 :
3907 5151 : if ( combinedFormat )
3908 : {
3909 0 : selectedReverb = IVAS_ROOM_SIZE_MEDIUM;
3910 : }
3911 : else
3912 : {
3913 : /* Only set large if ISM is present alone */
3914 5151 : if ( nActiveInputsIsm && !nActiveInputsMc )
3915 : {
3916 3039 : selectedReverb = IVAS_ROOM_SIZE_LARGE;
3917 : }
3918 : /* if only MC is present, set medium; Will not be overridden by the subsequent block */
3919 2112 : else if ( nActiveInputsMc )
3920 : {
3921 1371 : selectedReverb = IVAS_ROOM_SIZE_MEDIUM;
3922 : }
3923 741 : else if ( nActiveInputsMasa || nActiveInputsSba )
3924 : {
3925 741 : selectedReverb = IVAS_ROOM_SIZE_SMALL;
3926 : }
3927 : }
3928 :
3929 5151 : return selectedReverb;
3930 : }
3931 :
3932 :
3933 : /*-------------------------------------------------------------------*
3934 : * IVAS_REND_AddInput()
3935 : *
3936 : *
3937 : *-------------------------------------------------------------------*/
3938 :
3939 12477 : 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 12477 : splitPreRendCldfb = false;
3955 :
3956 : /* Validate function arguments */
3957 12477 : if ( hIvasRend == NULL || inputId == NULL )
3958 : {
3959 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
3960 : }
3961 :
3962 12477 : if ( hIvasRend->hRendererConfig != NULL )
3963 : {
3964 : int16_t cldfb_in_flag;
3965 5304 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) );
3966 :
3967 5304 : if ( ( error = isar_pre_rend_init( hIvasRend->splitRendWrapper,
3968 : &hIvasRend->splitRendEncBuffer,
3969 5304 : &hIvasRend->hRendererConfig->split_rend_config,
3970 : hIvasRend->headRotData,
3971 : hIvasRend->sampleRateOut,
3972 : hIvasRend->outputConfig,
3973 : cldfb_in_flag,
3974 5304 : 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 5304 : splitPreRendCldfb = ( hIvasRend->hRendererConfig->split_rend_config.codec == ISAR_SPLIT_REND_CODEC_LCLD );
3981 : }
3982 :
3983 12477 : inputType = getAudioConfigType( inConfig );
3984 12477 : switch ( inputType )
3985 : {
3986 7761 : case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
3987 7761 : maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
3988 7761 : inputsArray = hIvasRend->inputsIsm;
3989 7761 : activateInput = setRendInputActiveIsm;
3990 7761 : setInputDelay = setRendInputDelayIsm;
3991 7761 : break;
3992 1371 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
3993 1371 : maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
3994 1371 : inputsArray = hIvasRend->inputsMc;
3995 1371 : activateInput = setRendInputActiveMc;
3996 1371 : setInputDelay = setRendInputDelayMc;
3997 1371 : break;
3998 2049 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
3999 2049 : maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
4000 2049 : inputsArray = hIvasRend->inputsSba;
4001 2049 : activateInput = setRendInputActiveSba;
4002 2049 : setInputDelay = setRendInputDelaySba;
4003 2049 : break;
4004 1296 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
4005 1296 : maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
4006 1296 : inputsArray = hIvasRend->inputsMasa;
4007 1296 : activateInput = setRendInputActiveMasa;
4008 1296 : setInputDelay = setRendInputDelayMasa;
4009 1296 : 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 12477 : if ( ( error = findFreeInputSlot( inputsArray, inputType, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
4016 : {
4017 0 : return error;
4018 : }
4019 :
4020 12477 : *inputId = makeInputId( inConfig, inputIndex );
4021 12477 : if ( ( error = activateInput( getInputByIndex( inputsArray, inputIndex, inputType ), inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ) != IVAS_ERR_OK )
4022 : {
4023 0 : return error;
4024 : }
4025 :
4026 12477 : setInputDelay( getInputByIndex( inputsArray, inputIndex, inputType ), splitPreRendCldfb );
4027 :
4028 : /* set global maximum delay after adding an input */
4029 12477 : setMaxGlobalDelayNs( hIvasRend );
4030 :
4031 : /* select default reverb size after adding an input */
4032 12477 : if ( hIvasRend->selectedRoomReverbSize == DEFAULT_REVERB_UNSET )
4033 : {
4034 5151 : IVAS_REND_SetReverbRoomSize( hIvasRend,
4035 5151 : getDefaultReverbSize( hIvasRend->inputsIsm,
4036 5151 : hIvasRend->inputsMasa,
4037 5151 : hIvasRend->inputsMc,
4038 5151 : hIvasRend->inputsSba ) );
4039 : }
4040 :
4041 12477 : 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 315 : 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 315 : if ( hIvasRend == NULL )
4063 : {
4064 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4065 : }
4066 :
4067 315 : if ( ( error = validateCustomLsLayout( layout ) ) != IVAS_ERR_OK )
4068 : {
4069 0 : return error;
4070 : }
4071 :
4072 315 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputMc ) ) != IVAS_ERR_OK )
4073 : {
4074 0 : return error;
4075 : }
4076 :
4077 315 : 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 315 : inputMc->customLsInput = makeCustomLsSetup( layout );
4087 :
4088 315 : inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
4089 :
4090 315 : if ( ( error = initEfap( &inputMc->efapInWrapper, inputMc->base.inConfig, &inputMc->customLsInput ) ) != IVAS_ERR_OK )
4091 : {
4092 0 : return error;
4093 : }
4094 :
4095 315 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
4096 : {
4097 108 : if ( ( error = initMcBinauralRendering( inputMc,
4098 108 : 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 315 : if ( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ) != IVAS_ERR_OK )
4110 : {
4111 0 : return error;
4112 : }
4113 :
4114 315 : return IVAS_ERR_OK;
4115 : }
4116 :
4117 :
4118 : /*-------------------------------------------------------------------*
4119 : * IVAS_REND_SetObjectIDs()
4120 : *
4121 : *
4122 : *-------------------------------------------------------------------*/
4123 :
4124 5151 : 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 5151 : if ( hIvasRend == NULL )
4132 : {
4133 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4134 : }
4135 :
4136 25755 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
4137 : {
4138 20604 : hIvasRend->inputsIsm[i].object_id = i;
4139 : }
4140 :
4141 5151 : return IVAS_ERR_OK;
4142 : }
4143 :
4144 :
4145 : /*-------------------------------------------------------------------*
4146 : * IVAS_REND_SetInputGain()
4147 : *
4148 : *
4149 : *-------------------------------------------------------------------*/
4150 :
4151 12477 : 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 12477 : if ( hIvasRend == NULL )
4162 : {
4163 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4164 : }
4165 :
4166 12477 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4167 : {
4168 0 : return error;
4169 : }
4170 :
4171 12477 : inputBase->gain = gain;
4172 :
4173 12477 : 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 83294205 : 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 83294205 : if ( hIvasRend == NULL || numChannels == NULL )
4344 : {
4345 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4346 : }
4347 :
4348 83294205 : if ( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ) != IVAS_ERR_OK )
4349 : {
4350 0 : return error;
4351 : }
4352 :
4353 83294205 : if ( ( error = getRendInputNumChannels( pInput, numChannels ) ) != IVAS_ERR_OK )
4354 : {
4355 0 : return error;
4356 : }
4357 :
4358 83294205 : return IVAS_ERR_OK;
4359 : }
4360 :
4361 :
4362 : /*-------------------------------------------------------------------*
4363 : * IVAS_REND_GetNumAllObjects()
4364 : *
4365 : *
4366 : *-------------------------------------------------------------------*/
4367 :
4368 7761 : 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 7761 : if ( hIvasRend == NULL || numChannels == NULL )
4374 : {
4375 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4376 : }
4377 :
4378 7761 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA1 || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA2 )
4379 : {
4380 66 : *numChannels = (int16_t) hIvasRend->inputsIsm[0].total_num_objects;
4381 : }
4382 :
4383 7761 : return IVAS_ERR_OK;
4384 : }
4385 :
4386 :
4387 : /*-------------------------------------------------------------------*
4388 : * IVAS_REND_GetDelay()
4389 : *
4390 : *
4391 : *-------------------------------------------------------------------*/
4392 :
4393 0 : 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 0 : if ( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
4403 : {
4404 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4405 : }
4406 :
4407 0 : *nSamples = 0;
4408 0 : *timeScale = hIvasRend->sampleRateOut;
4409 :
4410 0 : max_latency_ns = getMaxGlobalDelayNs( hIvasRend );
4411 :
4412 0 : *nSamples = latencyNsToSamples( hIvasRend->sampleRateOut, max_latency_ns );
4413 :
4414 0 : return IVAS_ERR_OK;
4415 : }
4416 :
4417 : /*-------------------------------------------------------------------*
4418 : * IVAS_REND_FeedInputAudio()
4419 : *
4420 : *
4421 : *-------------------------------------------------------------------*/
4422 :
4423 215572434 : 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 215572434 : if ( hIvasRend == NULL || inputAudio.data == NULL )
4437 : {
4438 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4439 : }
4440 :
4441 215572434 : cldfb2tdSampleFact = ( inputAudio.config.is_cldfb ) ? 2 : 1;
4442 :
4443 215572434 : if ( inputAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
4444 215572434 : ( ( 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 215572434 : if ( inputAudio.config.numChannels <= 0 || MAX_INPUT_CHANNELS < inputAudio.config.numChannels )
4450 : {
4451 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4452 : }
4453 :
4454 215572434 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
4455 102035397 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
4456 102035397 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
4457 102035397 : ( 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 215572434 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4463 : {
4464 0 : return error;
4465 : }
4466 :
4467 215572434 : if ( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ) != IVAS_ERR_OK )
4468 : {
4469 0 : return error;
4470 : }
4471 :
4472 215572434 : if ( ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA1 || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA2 ) && inputBase->inConfig == IVAS_AUDIO_CONFIG_OBA )
4473 : {
4474 294966 : numInputChannels = (int16_t) hIvasRend->inputsIsm[0].total_num_objects;
4475 : }
4476 :
4477 215572434 : if ( numInputChannels != inputAudio.config.numChannels )
4478 : {
4479 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
4480 : }
4481 :
4482 215572434 : inputBase->inputBuffer.config = inputAudio.config;
4483 215572434 : 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 215572434 : inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact;
4494 :
4495 215572434 : return IVAS_ERR_OK;
4496 : }
4497 :
4498 :
4499 : /*-------------------------------------------------------------------*
4500 : * IVAS_REND_FeedInputObjectMetadata()
4501 : *
4502 : *
4503 : *-------------------------------------------------------------------*/
4504 :
4505 131995740 : 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 131995740 : if ( hIvasRend == NULL )
4517 : {
4518 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4519 : }
4520 :
4521 131995740 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4522 : {
4523 0 : return error;
4524 : }
4525 :
4526 131995740 : 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 131995740 : inputIsm = (input_ism *) inputBase;
4533 131995740 : inputIsm->previousPos = inputIsm->currentPos;
4534 131995740 : inputIsm->currentPos = objectPosition;
4535 :
4536 131995740 : return IVAS_ERR_OK;
4537 : }
4538 :
4539 :
4540 : /*-------------------------------------------------------------------*
4541 : * IVAS_REND_FeedInputObjectMetadataToOMasa()
4542 : *
4543 : *
4544 : *-------------------------------------------------------------------*/
4545 :
4546 747792 : 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 747792 : if ( hIvasRend == NULL )
4554 : {
4555 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4556 : }
4557 :
4558 : /* Set position to OMasa struct */
4559 747792 : hIvasRend->inputsIsm->hOMasa->ism_azimuth[inputIndex] = objectPosition.azimuth;
4560 747792 : hIvasRend->inputsIsm->hOMasa->ism_elevation[inputIndex] = objectPosition.elevation;
4561 :
4562 747792 : return IVAS_ERR_OK;
4563 : }
4564 :
4565 :
4566 : /*-------------------------------------------------------------------*
4567 : * IVAS_REND_FeedInputMasaMetadata()
4568 : *
4569 : *
4570 : *-------------------------------------------------------------------*/
4571 :
4572 7974405 : 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 7974405 : if ( hIvasRend == NULL )
4584 : {
4585 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4586 : }
4587 :
4588 7974405 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
4589 : {
4590 0 : return error;
4591 : }
4592 :
4593 7974405 : 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 7974405 : inputMasa = (input_masa *) inputBase;
4600 7974405 : inputMasa->masaMetadata = *masaMetadata;
4601 7974405 : inputMasa->metadataHasBeenFed = true;
4602 :
4603 7974405 : return IVAS_ERR_OK;
4604 : }
4605 :
4606 :
4607 : /*-------------------------------------------------------------------*
4608 : * IVAS_REND_InitConfig()
4609 : *
4610 : *
4611 : *-------------------------------------------------------------------*/
4612 :
4613 5151 : 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 5151 : rendererConfigEnabled = ( getAudioConfigType( outAudioConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
4622 :
4623 5151 : if ( rendererConfigEnabled )
4624 : {
4625 2244 : hIvasRend->rendererConfigEnabled = 1;
4626 : }
4627 : else
4628 : {
4629 2907 : hIvasRend->rendererConfigEnabled = 0;
4630 : }
4631 :
4632 5151 : if ( rendererConfigEnabled )
4633 : {
4634 2244 : if ( ( error = ivas_render_config_open( &( hIvasRend->hRendererConfig ) ) ) != IVAS_ERR_OK )
4635 : {
4636 0 : return error;
4637 : }
4638 2244 : if ( ( error = ivas_render_config_init_from_rom( &hIvasRend->hRendererConfig ) ) != IVAS_ERR_OK )
4639 : {
4640 0 : return error;
4641 : }
4642 : }
4643 : else
4644 : {
4645 2907 : hIvasRend->hRendererConfig = NULL;
4646 : }
4647 :
4648 5151 : return IVAS_ERR_OK;
4649 : }
4650 :
4651 :
4652 : /*-------------------------------------------------------------------*
4653 : * IVAS_REND_GetRenderConfig()
4654 : *
4655 : *
4656 : *-------------------------------------------------------------------*/
4657 :
4658 648 : 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 648 : if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL || hRCout == NULL )
4666 : {
4667 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4668 : }
4669 :
4670 648 : hRCin = hIvasRend->hRendererConfig;
4671 :
4672 648 : hRCout->roomAcoustics.aeID = hRCin->roomAcoustics.aeID;
4673 648 : hRCout->roomAcoustics.nBands = hRCin->roomAcoustics.nBands;
4674 648 : hRCout->roomAcoustics.acousticPreDelay = hRCin->roomAcoustics.acousticPreDelay;
4675 648 : hRCout->roomAcoustics.inputPreDelay = hRCin->roomAcoustics.inputPreDelay;
4676 648 : mvr2r( hRCin->directivity, hRCout->directivity, 3 * MAX_NUM_OBJECTS );
4677 :
4678 648 : mvr2r( hRCin->roomAcoustics.pFc_input, hRCout->roomAcoustics.pFc_input, CLDFB_NO_CHANNELS_MAX );
4679 648 : mvr2r( hRCin->roomAcoustics.pAcoustic_rt60, hRCout->roomAcoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX );
4680 648 : mvr2r( hRCin->roomAcoustics.pAcoustic_dsr, hRCout->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX );
4681 :
4682 648 : hRCout->split_rend_config.splitRendBitRate = ISAR_MAX_SPLIT_REND_BITRATE;
4683 648 : hRCout->split_rend_config.dof = 3;
4684 648 : hRCout->split_rend_config.hq_mode = 0;
4685 648 : hRCout->split_rend_config.codec_delay_ms = 0;
4686 648 : hRCout->split_rend_config.isar_frame_size_ms = 20;
4687 648 : hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
4688 648 : hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
4689 648 : hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
4690 648 : hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
4691 648 : hRCout->split_rend_config.lc3plus_highres = 0;
4692 :
4693 648 : hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er;
4694 648 : hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
4695 :
4696 648 : mvr2r( hRCin->distAtt, hRCout->distAtt, 3 );
4697 :
4698 648 : return IVAS_ERR_OK;
4699 : }
4700 :
4701 :
4702 : /*-------------------------------------------------------------------*
4703 : * IVAS_REND_FeedRenderConfig()
4704 : *
4705 : *
4706 : *-------------------------------------------------------------------*/
4707 :
4708 16068 : 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 16068 : if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
4722 : {
4723 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4724 : }
4725 16068 : hRenderConfig = hIvasRend->hRendererConfig;
4726 :
4727 16068 : hRenderConfig->roomAcoustics.aeID = renderConfig.roomAcoustics.aeID;
4728 16068 : hRenderConfig->roomAcoustics.nBands = renderConfig.roomAcoustics.nBands;
4729 16068 : hRenderConfig->roomAcoustics.acousticPreDelay = renderConfig.roomAcoustics.acousticPreDelay;
4730 16068 : hRenderConfig->roomAcoustics.inputPreDelay = renderConfig.roomAcoustics.inputPreDelay;
4731 16068 : mvr2r( renderConfig.roomAcoustics.pFc_input, hRenderConfig->roomAcoustics.pFc_input, CLDFB_NO_CHANNELS_MAX );
4732 16068 : mvr2r( renderConfig.roomAcoustics.pAcoustic_rt60, hRenderConfig->roomAcoustics.pAcoustic_rt60, CLDFB_NO_CHANNELS_MAX );
4733 16068 : mvr2r( renderConfig.roomAcoustics.pAcoustic_dsr, hRenderConfig->roomAcoustics.pAcoustic_dsr, CLDFB_NO_CHANNELS_MAX );
4734 16068 : mvr2r( renderConfig.directivity, hRenderConfig->directivity, 3 * MAX_NUM_OBJECTS );
4735 16068 : mvr2r( renderConfig.distAtt, hRenderConfig->distAtt, 3 );
4736 :
4737 16068 : hRenderConfig->roomAcoustics.use_er = 0;
4738 16068 : if ( renderConfig.roomAcoustics.use_er == 1 )
4739 : {
4740 10656 : hRenderConfig->roomAcoustics.use_er = renderConfig.roomAcoustics.use_er;
4741 10656 : hRenderConfig->roomAcoustics.lowComplexity = renderConfig.roomAcoustics.lowComplexity;
4742 10656 : hRenderConfig->roomAcoustics.dimensions = renderConfig.roomAcoustics.dimensions;
4743 10656 : hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.roomAcoustics.ListenerOrigin;
4744 :
4745 10656 : 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 80340 : for ( i = 0, pIsmInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pIsmInput )
4751 : {
4752 64272 : if ( pIsmInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4753 : {
4754 : /* Skip inactive inputs */
4755 39492 : continue;
4756 : }
4757 24780 : if ( pIsmInput->hReverb != NULL )
4758 : {
4759 24780 : 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 24780 : 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 32136 : for ( i = 0, pMasaInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pMasaInput )
4775 : {
4776 16068 : if ( pMasaInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4777 : {
4778 : /* Skip inactive inputs */
4779 12549 : continue;
4780 : }
4781 :
4782 3519 : if ( pMasaInput->hMasaExtRend != NULL )
4783 : {
4784 3519 : if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
4785 : {
4786 3519 : ivas_binaural_reverb_close( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
4787 :
4788 3519 : if ( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb,
4789 : hIvasRend->hHrtfs.hHrtfStatistics,
4790 3519 : pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands,
4791 : CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
4792 3519 : &( hRenderConfig->roomAcoustics ),
4793 3519 : *pMasaInput->base.ctx.pOutSampleRate,
4794 : NULL,
4795 : NULL,
4796 : NULL ) ) != IVAS_ERR_OK )
4797 : {
4798 0 : return error;
4799 : }
4800 : }
4801 :
4802 3519 : 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 32136 : for ( i = 0, pMcInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pMcInput )
4824 : {
4825 16068 : if ( pMcInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4826 : {
4827 : /* Skip inactive inputs */
4828 12642 : continue;
4829 : }
4830 :
4831 3426 : 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 3426 : if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
4840 : {
4841 2268 : 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 32136 : for ( i = 0, pSbaInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pSbaInput )
4850 : {
4851 16068 : if ( pSbaInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
4852 : {
4853 : /* Skip inactive inputs */
4854 9426 : continue;
4855 : }
4856 :
4857 6642 : if ( pSbaInput->crendWrapper != NULL && pSbaInput->crendWrapper->hCrend[0] != NULL && pSbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
4858 : {
4859 6642 : 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 16068 : hRenderConfig->split_rend_config = renderConfig.split_rend_config;
4867 : /* Overwrite any pose correction settings if 0 DOF (no pose correction) was selected */
4868 16068 : if ( hRenderConfig->split_rend_config.dof == 0 )
4869 : {
4870 0 : hRenderConfig->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
4871 : }
4872 :
4873 16068 : hRenderConfig->split_rend_config.codec = renderConfig.split_rend_config.codec;
4874 :
4875 16068 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
4876 : {
4877 0 : if ( ( error = isar_split_rend_validate_config( &hRenderConfig->split_rend_config, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0 ) ) != IVAS_ERR_OK )
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 16068 : 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 16068 : return IVAS_ERR_OK;
4904 : }
4905 :
4906 :
4907 : /*-------------------------------------------------------------------*
4908 : * IVAS_REND_SetHeadRotation()
4909 : *
4910 : *
4911 : *-------------------------------------------------------------------*/
4912 :
4913 27266277 : 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 27266277 : if ( hIvasRend == NULL )
4927 : {
4928 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4929 : }
4930 :
4931 27266277 : 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 27266277 : hIvasRend->headRotData.headRotEnabled = 1;
4938 :
4939 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
4940 54532554 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
4941 : {
4942 27266277 : if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
4943 : {
4944 7623771 : 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 27266277 : if ( headRot.w == -3.0f )
4959 : {
4960 0 : Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat );
4961 : }
4962 : else
4963 : {
4964 27266277 : rotQuat = headRot;
4965 : }
4966 :
4967 27266277 : 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 27266277 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
4973 :
4974 27266277 : hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
4975 :
4976 27266277 : return IVAS_ERR_OK;
4977 : }
4978 :
4979 :
4980 : /*-------------------------------------------------------------------*
4981 : * IVAS_REND_DisableHeadRotation()
4982 : *
4983 : *
4984 : *-------------------------------------------------------------------*/
4985 :
4986 74554359 : 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 74554359 : if ( hIvasRend == NULL )
4995 : {
4996 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
4997 : }
4998 :
4999 74554359 : hIvasRend->headRotData.headRotEnabled = 0;
5000 :
5001 : /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
5002 74554359 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL )
5003 : {
5004 52816986 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
5005 : {
5006 26408493 : if ( hIvasRend->inputsMc[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
5007 : {
5008 6600663 : 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 74554359 : return IVAS_ERR_OK;
5023 : }
5024 :
5025 :
5026 : /*-------------------------------------------------------------------*
5027 : * IVAS_REND_SetOrientationTrackingMode()
5028 : *
5029 : *
5030 : *-------------------------------------------------------------------*/
5031 :
5032 5151 : 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 5151 : if ( hIvasRend->headRotData.headRotEnabled == 0 )
5038 : {
5039 4275 : return IVAS_ERR_OK;
5040 : }
5041 :
5042 876 : return ivas_orient_trk_SetTrackingType( hIvasRend->headRotData.hOrientationTracker, orientation_tracking );
5043 : }
5044 :
5045 :
5046 : /*-------------------------------------------------------------------*
5047 : * IVAS_REND_SetReferenceRotation()
5048 : *
5049 : *
5050 : *-------------------------------------------------------------------*/
5051 :
5052 144864 : 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 144864 : if ( hIvasRend == NULL )
5061 : {
5062 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5063 : }
5064 :
5065 144864 : if ( ( error = ivas_orient_trk_SetReferenceRotation( hIvasRend->headRotData.hOrientationTracker, refRot ) ) != IVAS_ERR_OK )
5066 : {
5067 0 : return error;
5068 : }
5069 :
5070 144864 : 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 716004 : 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 716004 : if ( hIvasRend == NULL || hIvasRend->headRotData.hOrientationTracker == NULL )
5142 : {
5143 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5144 : }
5145 :
5146 716004 : 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 93743181 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
5197 : IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle */
5198 : )
5199 : {
5200 93743181 : if ( hIvasRend == NULL )
5201 : {
5202 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5203 : }
5204 :
5205 93743181 : 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 5151 : 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 5151 : switch ( reverbRoomSize )
5285 : {
5286 741 : case IVAS_ROOM_SIZE_SMALL:
5287 741 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_SMALL;
5288 741 : break;
5289 1371 : case IVAS_ROOM_SIZE_MEDIUM:
5290 1371 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_MEDIUM;
5291 1371 : break;
5292 3039 : case IVAS_ROOM_SIZE_LARGE:
5293 3039 : hIvasRend->selectedRoomReverbSize = DEFAULT_REVERB_LARGE;
5294 3039 : 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 5151 : if ( hIvasRend->hRendererConfig != NULL )
5302 : {
5303 2244 : 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 2907 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
5311 : }
5312 :
5313 2244 : 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 443889754 : 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 443889754 : lastInSmpl = getSmplPtr( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
5345 :
5346 4224049162 : for ( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
5347 : {
5348 3780159408 : currentGain = gainsCurrent[outChnlIdx];
5349 3780159408 : previousGain = gainsPrev == NULL ? 0.f : gainsPrev[outChnlIdx];
5350 :
5351 : /* Process current output channel only if applying non-zero gains */
5352 3780159408 : if ( fabsf( currentGain ) > EPSILON || ( gainsPrev != NULL && fabsf( previousGain ) > EPSILON ) )
5353 : {
5354 : /* Reset input pointer to the beginning of input channel */
5355 2145773649 : inSmpl = getSmplPtr( inAudio, inChannelIdx, 0 );
5356 :
5357 : /* Set output pointer to first output channel sample */
5358 2145773649 : outSmpl = getSmplPtr( outAudio, outChnlIdx, 0 );
5359 :
5360 2145773649 : if ( gainsPrev == NULL || fabsf( previousGain - currentGain ) <= EPSILON )
5361 : {
5362 : /* If no interpolation from previous frame, apply current gain */
5363 : do
5364 : {
5365 >56918*10^7 : *outSmpl += currentGain * ( *inSmpl );
5366 >56918*10^7 : ++outSmpl;
5367 >56918*10^7 : ++inSmpl;
5368 :
5369 >56918*10^7 : } while ( inSmpl != lastInSmpl );
5370 : }
5371 : else
5372 : {
5373 85560455 : i = 0;
5374 :
5375 : /* Otherwise use weighted average between previous and current gain */
5376 : do
5377 : {
5378 35652478560 : fadeIn = (float) i / ( outAudio.config.numSamplesPerChannel - 1 );
5379 35652478560 : fadeOut = 1.0f - fadeIn;
5380 :
5381 35652478560 : *outSmpl += ( fadeIn * currentGain + fadeOut * previousGain ) * ( *inSmpl );
5382 35652478560 : ++outSmpl;
5383 35652478560 : ++inSmpl;
5384 35652478560 : ++i;
5385 35652478560 : } while ( inSmpl != lastInSmpl );
5386 : }
5387 : }
5388 : }
5389 :
5390 443889754 : 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 359600321 : 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 359600321 : renderBufferChannelLerp( inAudio, inChannelIdx, outputGains, NULL, outAudio );
5403 :
5404 359600321 : return;
5405 : }
5406 :
5407 :
5408 11590956 : static ivas_error chooseCrossfade(
5409 : const IVAS_REND_HeadRotData *headRotData,
5410 : const float **pCrossfade )
5411 : {
5412 11590956 : *pCrossfade = headRotData->crossfade;
5413 :
5414 11590956 : return IVAS_ERR_OK;
5415 : }
5416 :
5417 2777184 : 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 2777184 : push_wmops( "rotateFrameMc" );
5446 2777184 : if ( ( error = chooseCrossfade( headRotData, &crossfade ) ) != IVAS_ERR_OK )
5447 : {
5448 0 : return error;
5449 : }
5450 2777184 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
5451 :
5452 2777184 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
5453 : {
5454 2048634 : if ( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ) != IVAS_ERR_OK )
5455 : {
5456 0 : return error;
5457 : }
5458 : }
5459 : else
5460 : {
5461 728550 : nchan = pInCustomLs->num_spk + pInCustomLs->num_lfe;
5462 : }
5463 :
5464 2777184 : 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 30891990 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
5471 : {
5472 28114806 : set_zero( gains[ch_in], nchan );
5473 28114806 : gains[ch_in][ch_in] = 1.f;
5474 : }
5475 :
5476 : /* subframe loop */
5477 :
5478 2777184 : subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
5479 6793299 : for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5480 : {
5481 16064460 : for ( i = 0; i < 3; i++ )
5482 : {
5483 12048345 : if ( hCombinedOrientationData != NULL )
5484 : {
5485 48193380 : for ( j = 0; j < 3; j++ )
5486 : {
5487 36145035 : 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 44954643 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
5499 : {
5500 : /* skip LFE */
5501 40938528 : if ( ch_in == lfe_idx )
5502 : {
5503 2850381 : continue;
5504 : }
5505 :
5506 : /* input channel index without LFE */
5507 38088147 : ch_in_woLFE = ( ( lfe_idx > 0 ) && ( ch_in >= lfe_idx ) ) ? ch_in - 1 : ch_in;
5508 :
5509 : /* gains for current subframe rotation */
5510 38088147 : rotateAziEle( ls_azimuth[ch_in_woLFE], ls_elevation[ch_in_woLFE], &azimuth, &elevation, Rmat, is_planar_setup );
5511 :
5512 38088147 : if ( hEFAPdata != NULL && ( ls_azimuth[ch_in_woLFE] != azimuth || ls_elevation[ch_in_woLFE] != elevation ) )
5513 : {
5514 24070321 : efap_determine_gains( hEFAPdata, tmp_gains, azimuth, elevation, EFAP_MODE_EFAP );
5515 :
5516 262470457 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
5517 : {
5518 : /* skip LFE */
5519 238400136 : if ( ch_out == lfe_idx )
5520 : {
5521 24070321 : continue;
5522 : }
5523 :
5524 : /* output channel index without LFE */
5525 214329815 : ch_out_woLFE = ( ( lfe_idx > 0 ) && ( ch_out >= lfe_idx ) ) ? ch_out - 1 : ch_out;
5526 :
5527 214329815 : gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE];
5528 : }
5529 : }
5530 : }
5531 :
5532 : /* apply panning gains by mtx multiplication */
5533 44954643 : for ( ch_out = 0; ch_out < nchan; ch_out++ )
5534 : {
5535 486421824 : for ( ch_in = 0; ch_in < nchan; ch_in++ )
5536 : {
5537 445483296 : writePtr = getSmplPtr( outAudio, ch_out, subframe_idx * subframe_len );
5538 445483296 : readPtr = getSmplPtr( inAudio, ch_in, subframe_idx * subframe_len );
5539 : /* crossfade with previous rotation gains */
5540 77041848096 : for ( i = 0; i < subframe_len; i++ )
5541 : {
5542 76596364800 : *writePtr++ +=
5543 76596364800 : ( *readPtr ) * ( ( 1 - crossfade[i] ) * gains_prev[ch_in][ch_out] ) +
5544 76596364800 : ( *readPtr ) * ( crossfade[i] * gains[ch_in][ch_out] );
5545 76596364800 : readPtr++;
5546 : }
5547 : }
5548 : }
5549 :
5550 : /* move gains to gains_prev */
5551 44954643 : for ( i = 0; i < nchan; i++ )
5552 : {
5553 40938528 : mvr2r( gains[i], gains_prev[i], nchan );
5554 : }
5555 : }
5556 :
5557 2777184 : pop_wmops();
5558 2777184 : return IVAS_ERR_OK;
5559 : }
5560 :
5561 :
5562 8813772 : 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 8813772 : push_wmops( "rotateFrameSba" );
5587 :
5588 8813772 : if ( ( error = chooseCrossfade( headRotData, &crossfade ) ) != IVAS_ERR_OK )
5589 : {
5590 0 : return error;
5591 : }
5592 8813772 : num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
5593 :
5594 8813772 : if ( ( error = getAmbisonicsOrder( inConfig, &shd_rot_max_order ) ) != IVAS_ERR_OK )
5595 : {
5596 0 : return error;
5597 : }
5598 :
5599 8813772 : subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
5600 20830203 : for ( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
5601 : {
5602 : /* initialize rotation matrices with zeros */
5603 204279327 : for ( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5604 : {
5605 192262896 : set_zero( gains[i], HEADROT_SHMAT_DIM );
5606 : }
5607 :
5608 48065724 : for ( i = 0; i < 3; i++ )
5609 : {
5610 36049293 : if ( hCombinedOrientationData != NULL )
5611 : {
5612 144197172 : for ( l = 0; l < 3; l++ )
5613 : {
5614 108147879 : 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 12016431 : SHrotmatgen( gains, Rmat, shd_rot_max_order );
5627 :
5628 2212775631 : for ( i = 0; i < subframe_len; i++ )
5629 : {
5630 2200759200 : idx = subframe_idx * subframe_len + i;
5631 2200759200 : cf = crossfade[i];
5632 2200759200 : 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 2200759200 : m1 = 1;
5638 2200759200 : m2 = 4;
5639 6587555040 : for ( l = 1; l <= shd_rot_max_order; l++ )
5640 : {
5641 : /* compute mtx-vector product for this l */
5642 23376614400 : for ( n = m1; n < m2; n++ )
5643 : {
5644 18989818560 : tmpRot[n - m1] = 0.f;
5645 :
5646 >11093*10^7 : for ( m = m1; m < m2; m++ )
5647 : {
5648 91946041920 : val = inAudio.data[m * inAudio.config.numSamplesPerChannel + idx];
5649 : /* crossfade with previous rotation gains */
5650 91946041920 : tmpRot[n - m1] += ( cf * gains[n][m] * val + oneminuscf * gains_prev[n][m] * val );
5651 : }
5652 : }
5653 : /* write back the result */
5654 23376614400 : for ( n = m1; n < m2; n++ )
5655 : {
5656 18989818560 : writePtr = getSmplPtr( outAudio, n, idx );
5657 18989818560 : ( *writePtr ) = tmpRot[n - m1];
5658 : }
5659 4386795840 : m1 = m2;
5660 4386795840 : m2 += 2 * ( l + 1 ) + 1;
5661 : }
5662 : }
5663 :
5664 : /* move SHrotmat to SHrotmat_prev */
5665 204279327 : for ( i = 0; i < HEADROT_SHMAT_DIM; i++ )
5666 : {
5667 192262896 : mvr2r( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
5668 : }
5669 : }
5670 :
5671 8813772 : pop_wmops();
5672 :
5673 8813772 : return IVAS_ERR_OK;
5674 : }
5675 :
5676 :
5677 13916204 : 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 13916204 : push_wmops( "renderIsmToBinaural" );
5686 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5687 13916204 : ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS );
5688 :
5689 13916204 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpTDRendBuffer );
5690 :
5691 13916204 : 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 13916204 : *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer ) ) != IVAS_ERR_OK )
5693 : {
5694 0 : return error;
5695 : }
5696 :
5697 13916204 : accumulate2dArrayToBuffer( tmpTDRendBuffer, &outAudio );
5698 :
5699 13916204 : pop_wmops();
5700 :
5701 13916204 : return IVAS_ERR_OK;
5702 : }
5703 :
5704 :
5705 0 : static int16_t getNumSubframesInBuffer(
5706 : const IVAS_REND_AudioBuffer *buffer,
5707 : const int32_t sampleRate )
5708 : {
5709 : int16_t cldfb2tdSampleFact;
5710 :
5711 0 : 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 0 : return (int16_t) ( buffer->config.numSamplesPerChannel / ( sampleRate / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES * cldfb2tdSampleFact ) );
5718 : }
5719 :
5720 :
5721 13916204 : 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 236575468 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
5742 : {
5743 222659264 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
5744 : }
5745 :
5746 13916204 : push_wmops( "renderIsmToBinauralRoom" );
5747 :
5748 13916204 : rotatedPosPrev = defaultObjectPosition();
5749 13916204 : rotatedPos = defaultObjectPosition();
5750 :
5751 13916204 : hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
5752 13916204 : combinedOrientationEnabled = 0;
5753 13916204 : if ( *hCombinedOrientationData != NULL )
5754 : {
5755 7291571 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
5756 : {
5757 :
5758 7291571 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
5759 : {
5760 7291571 : combinedOrientationEnabled = 1;
5761 7291571 : break;
5762 : }
5763 : }
5764 : }
5765 :
5766 13916204 : if ( combinedOrientationEnabled )
5767 : {
5768 14583142 : for ( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
5769 : {
5770 29166284 : for ( i = 0; i < 3; i++ )
5771 : {
5772 21874713 : if ( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
5773 : {
5774 87498852 : for ( j = 0; j < 3; j++ )
5775 : {
5776 65624139 : 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 13916204 : if ( combinedOrientationEnabled )
5791 : {
5792 7291571 : rotateAziEle( ismInput->previousPos.azimuth, ismInput->previousPos.elevation, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
5793 7291571 : rotatedPosPrev.azimuth = (float) azi_rot;
5794 7291571 : rotatedPosPrev.elevation = (float) ele_rot;
5795 : }
5796 : else
5797 : {
5798 6624633 : rotatedPosPrev.azimuth = ismInput->previousPos.azimuth;
5799 6624633 : rotatedPosPrev.elevation = ismInput->previousPos.elevation;
5800 : }
5801 :
5802 : /* get current position */
5803 13916204 : if ( combinedOrientationEnabled )
5804 : {
5805 7291571 : rotateAziEle( ismInput->currentPos.azimuth, ismInput->currentPos.elevation, &azi_rot, &ele_rot, Rmat, 0 );
5806 7291571 : rotatedPos.azimuth = (float) azi_rot;
5807 7291571 : rotatedPos.elevation = (float) ele_rot;
5808 : }
5809 : else
5810 : {
5811 6624633 : rotatedPos.azimuth = ismInput->currentPos.azimuth;
5812 6624633 : rotatedPos.elevation = ismInput->currentPos.elevation;
5813 : }
5814 :
5815 13916204 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged( &rotatedPos, &rotatedPosPrev );
5816 :
5817 : /* set previous gains if this is the first frame */
5818 13916204 : 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 13916204 : if ( position_changed )
5825 : {
5826 3485666 : 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 13916204 : tmpMcBuffer = ismInput->base.inputBuffer;
5837 :
5838 13916204 : if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK )
5839 : {
5840 0 : return error;
5841 : }
5842 :
5843 13916204 : tmpMcBuffer.config.numChannels = tmp;
5844 13916204 : tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) );
5845 13916204 : set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels );
5846 :
5847 13916204 : 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 13916204 : copyBufferTo2dArray( tmpMcBuffer, tmpRendBuffer );
5853 :
5854 : /* save gains for next frame */
5855 55664816 : for ( i = 0; i < 3; i++ )
5856 : {
5857 41748612 : mvr2r( Rmat[i], ismInput->rot_mat_prev[i], 3 );
5858 : }
5859 :
5860 13916204 : if ( position_changed )
5861 : {
5862 3485666 : mvr2r( currentPanGains, ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5863 : }
5864 :
5865 : /* render 7_1_4 with BRIRs */
5866 13916204 : if ( ( error = ivas_rend_crendProcessSubframe( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR, NULL, NULL,
5867 13916204 : 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 13916204 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
5873 :
5874 13916204 : free( tmpMcBuffer.data );
5875 13916204 : pop_wmops();
5876 :
5877 13916204 : return IVAS_ERR_OK;
5878 : }
5879 :
5880 :
5881 33790103 : 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 33790103 : push_wmops( "renderIsmToBinauralRoom" );
5890 :
5891 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
5892 33790103 : ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS );
5893 :
5894 33790103 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer );
5895 :
5896 33790103 : if ( ( error = ivas_td_binaural_renderer_ext( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb,
5897 33790103 : ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK )
5898 : {
5899 0 : return error;
5900 : }
5901 :
5902 33790103 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
5903 33790103 : pop_wmops();
5904 :
5905 33790103 : return IVAS_ERR_OK;
5906 : }
5907 :
5908 :
5909 50488458 : 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 50488458 : push_wmops( "renderIsmToMc" );
5918 :
5919 50488458 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged( &ismInput->currentPos, &ismInput->previousPos );
5920 50488458 : if ( *ismInput->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_STEREO )
5921 : {
5922 6743697 : if ( ismInput->nonDiegeticPan )
5923 : {
5924 115440 : ismInput->prev_pan_gains[0] = currentPanGains[0] = ( ismInput->nonDiegeticPanGain + 1.f ) * 0.5f;
5925 115440 : ismInput->prev_pan_gains[1] = currentPanGains[1] = 1.f - currentPanGains[0];
5926 : }
5927 : else
5928 : {
5929 6628257 : set_zero( currentPanGains, MAX_OUTPUT_CHANNELS );
5930 :
5931 6628257 : ivas_ism_get_stereo_gains( ismInput->currentPos.azimuth, ismInput->currentPos.elevation, ¤tPanGains[0], ¤tPanGains[1] );
5932 :
5933 6628257 : set_zero( ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5934 :
5935 6628257 : 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 43744761 : if ( position_changed )
5942 : {
5943 : // TODO tmu review when #215 is resolved
5944 9033039 : if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper,
5945 9033039 : (int16_t) floorf( ismInput->currentPos.azimuth + 0.5f ),
5946 9033039 : (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 43744761 : if ( !ismInput->firstFrameRendered )
5955 : {
5956 : // TODO tmu review when #215 is resolved
5957 2844 : if ( ( error = getEfapGains( *ismInput->base.ctx.pEfapOutWrapper,
5958 2844 : (int16_t) floorf( ismInput->previousPos.azimuth + 0.5f ),
5959 2844 : (int16_t) floorf( ismInput->previousPos.elevation + 0.5f ),
5960 2844 : 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 50488458 : 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 50488458 : if ( position_changed )
5975 : {
5976 10351074 : mvr2r( currentPanGains, ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
5977 : }
5978 :
5979 50488458 : pop_wmops();
5980 :
5981 50488458 : return IVAS_ERR_OK;
5982 : }
5983 :
5984 :
5985 19884771 : 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 19884771 : error = IVAS_ERR_OK;
5996 :
5997 19884771 : push_wmops( "renderIsmToSba" );
5998 :
5999 19884771 : set_zero( currentPanGains, MAX_OUTPUT_CHANNELS );
6000 :
6001 19884771 : if ( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ) != IVAS_ERR_OK )
6002 : {
6003 0 : return error;
6004 : }
6005 :
6006 19884771 : if ( ( error = getAmbisonicsOrder( outConfig, &ambiOrderOut ) ) != IVAS_ERR_OK )
6007 : {
6008 0 : return error;
6009 : }
6010 :
6011 19884771 : position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged( &ismInput->currentPos, &ismInput->previousPos );
6012 :
6013 : /* set previous gains if this is the first frame */
6014 19884771 : if ( !ismInput->firstFrameRendered )
6015 : {
6016 : // TODO tmu review when #215 is resolved
6017 1152 : ivas_dirac_dec_get_response( (int16_t) floorf( ismInput->previousPos.azimuth + 0.5f ),
6018 1152 : (int16_t) floorf( ismInput->previousPos.elevation + 0.5f ),
6019 1152 : ismInput->prev_pan_gains,
6020 : ambiOrderOut );
6021 : }
6022 :
6023 : /* compute gains only if position changed */
6024 19884771 : if ( position_changed )
6025 : {
6026 : // TODO tmu review when #215 is resolved
6027 3613230 : ivas_dirac_dec_get_response( (int16_t) floorf( ismInput->currentPos.azimuth + 0.5f ),
6028 3613230 : (int16_t) floorf( ismInput->currentPos.elevation + 0.5f ),
6029 : currentPanGains,
6030 : ambiOrderOut );
6031 : }
6032 :
6033 : /* Assume num channels in audio buffer to be 1.
6034 : * This should have been validated in IVAS_REND_FeedInputAudio() */
6035 19884771 : renderBufferChannelLerp( ismInput->base.inputBuffer, 0,
6036 : position_changed ? currentPanGains : ismInput->prev_pan_gains,
6037 : position_changed ? ismInput->prev_pan_gains : NULL,
6038 : outAudio );
6039 :
6040 19884771 : if ( position_changed )
6041 : {
6042 3613230 : mvr2r( currentPanGains, ismInput->prev_pan_gains, MAX_OUTPUT_CHANNELS );
6043 : }
6044 19884771 : pop_wmops();
6045 :
6046 19884771 : return error;
6047 : }
6048 :
6049 :
6050 0 : static ivas_error renderIsmToSplitBinaural(
6051 : input_ism *ismInput,
6052 : const IVAS_REND_AudioBuffer outAudio )
6053 : {
6054 : ivas_error error;
6055 : float tmpProcessing[MAX_NUM_OBJECTS][L_FRAME48k];
6056 : int16_t pos_idx;
6057 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
6058 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
6059 : IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
6060 : int16_t i, ch, slot_idx, num_bands;
6061 : float tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
6062 : float tmpBinaural_CldfbRe[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
6063 : float tmpBinaural_CldfbIm[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
6064 0 : int16_t output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
6065 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
6066 : int16_t ism_md_subframe_update_ext;
6067 :
6068 0 : push_wmops( "renderIsmToSplitBinaural" );
6069 :
6070 0 : pSplitRendWrapper = ismInput->base.ctx.pSplitRendWrapper;
6071 0 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
6072 :
6073 : /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
6074 0 : ism_md_subframe_update_ext = (int16_t) roundf( ismInput->ism_metadata_delay_ms / (float) BINAURAL_RENDERING_FRAME_SIZE_MS );
6075 :
6076 0 : pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData;
6077 :
6078 0 : if ( pMultiBinPoseData->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
6079 : {
6080 0 : for ( i = 1; i < pCombinedOrientationData->num_subframes; ++i )
6081 : {
6082 0 : pCombinedOrientationData->Quaternions[i] = pCombinedOrientationData->Quaternions[0];
6083 : }
6084 : }
6085 :
6086 : /* Save current head positions */
6087 0 : for ( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6088 : {
6089 0 : originalHeadRot[i] = pCombinedOrientationData->Quaternions[i];
6090 : }
6091 :
6092 : /* Copy input audio to a processing buffer. */
6093 0 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing );
6094 :
6095 0 : for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6096 : {
6097 : /* Update head positions */
6098 0 : if ( pos_idx != 0 )
6099 : {
6100 0 : for ( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6101 : {
6102 0 : if ( originalHeadRot[i].w == -3.0f )
6103 : {
6104 0 : pCombinedOrientationData->Quaternions[i].w = -3.0f;
6105 0 : pCombinedOrientationData->Quaternions[i].x = originalHeadRot[i].x + pMultiBinPoseData->relative_head_poses[pos_idx][0];
6106 0 : pCombinedOrientationData->Quaternions[i].y = originalHeadRot[i].y + pMultiBinPoseData->relative_head_poses[pos_idx][1];
6107 0 : pCombinedOrientationData->Quaternions[i].z = originalHeadRot[i].z + pMultiBinPoseData->relative_head_poses[pos_idx][2];
6108 : }
6109 : else
6110 : {
6111 0 : pCombinedOrientationData->Quaternions[i].w = -3.0f;
6112 0 : Quat2EulerDegree( originalHeadRot[i],
6113 0 : &pCombinedOrientationData->Quaternions[i].z,
6114 0 : &pCombinedOrientationData->Quaternions[i].y,
6115 0 : &pCombinedOrientationData->Quaternions[i].x );
6116 0 : pCombinedOrientationData->Quaternions[i].x += pMultiBinPoseData->relative_head_poses[pos_idx][0];
6117 0 : pCombinedOrientationData->Quaternions[i].y += pMultiBinPoseData->relative_head_poses[pos_idx][1];
6118 0 : pCombinedOrientationData->Quaternions[i].z += pMultiBinPoseData->relative_head_poses[pos_idx][2];
6119 : }
6120 : }
6121 : }
6122 :
6123 : /* Render */
6124 0 : 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,
6125 0 : NULL, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, output_frame, tmpProcessing ) ) != IVAS_ERR_OK )
6126 : {
6127 0 : return error;
6128 : }
6129 :
6130 0 : if ( outAudio.config.is_cldfb )
6131 : {
6132 : /* Perform CLDFB analysis on rendered audio, since the output buffer is CLDFB domain */
6133 0 : num_bands = (int16_t) ( ( BINAURAL_MAXBANDS * *ismInput->base.ctx.pOutSampleRate ) / 48000 );
6134 0 : for ( ch = 0; ch < BINAURAL_CHANNELS; ch++ )
6135 : {
6136 0 : for ( slot_idx = 0; slot_idx < IVAS_CLDFB_NO_COL_MAX; slot_idx++ )
6137 : {
6138 0 : cldfbAnalysis_ts( &tmpProcessing[ch][num_bands * slot_idx],
6139 0 : &tmpBinaural_CldfbRe[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0],
6140 0 : &tmpBinaural_CldfbIm[BINAURAL_CHANNELS * pos_idx + ch][slot_idx][0],
6141 : num_bands,
6142 0 : ismInput->base.ctx.pSplitRendWrapper->hCldfbHandles->cldfbAna[pos_idx + ch] );
6143 : }
6144 : }
6145 : }
6146 : else
6147 : {
6148 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
6149 : * overwrite original audio, which is still needed for rendering next head pose. */
6150 0 : mvr2r( tmpProcessing[0], tmpBinaural[BINAURAL_CHANNELS * pos_idx], output_frame );
6151 0 : mvr2r( tmpProcessing[1], tmpBinaural[BINAURAL_CHANNELS * pos_idx + 1], output_frame );
6152 : }
6153 :
6154 : /* Overwrite processing buffer with original input audio again */
6155 0 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpProcessing );
6156 : }
6157 :
6158 : /* Restore original head rotation */
6159 0 : for ( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
6160 : {
6161 0 : pCombinedOrientationData->Quaternions[i] = originalHeadRot[i];
6162 : }
6163 :
6164 0 : if ( outAudio.config.is_cldfb )
6165 : {
6166 0 : accumulateCLDFBArrayToBuffer( tmpBinaural_CldfbRe, tmpBinaural_CldfbIm, &outAudio );
6167 : }
6168 : else
6169 : {
6170 0 : accumulate2dArrayToBuffer( tmpBinaural, &outAudio );
6171 : }
6172 0 : pop_wmops();
6173 :
6174 : /* Encoding to split rendering bitstream done at a higher level */
6175 0 : return IVAS_ERR_OK;
6176 : }
6177 :
6178 :
6179 294966 : static void renderIsmToMasa(
6180 : input_ism *ismInput,
6181 : IVAS_REND_AudioBuffer outAudio )
6182 : {
6183 : float tmpRendBuffer[MAX_NUM_OBJECTS][L_FRAME48k];
6184 :
6185 294966 : push_wmops( "renderIsmToMasa" );
6186 :
6187 294966 : copyBufferTo2dArray( ismInput->base.inputBuffer, tmpRendBuffer );
6188 :
6189 294966 : ivas_omasa_ana( ismInput->hOMasa, tmpRendBuffer, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
6190 :
6191 294966 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6192 :
6193 294966 : pop_wmops();
6194 :
6195 294966 : return;
6196 : }
6197 :
6198 :
6199 132290706 : static ivas_error renderInputIsm(
6200 : input_ism *ismInput,
6201 : const AUDIO_CONFIG outConfig,
6202 : const IVAS_REND_AudioBuffer outAudio )
6203 : {
6204 : ivas_error error;
6205 : IVAS_REND_AudioBuffer inAudio;
6206 : int16_t cldfb2tdSampleFact;
6207 :
6208 132290706 : error = IVAS_ERR_OK;
6209 132290706 : inAudio = ismInput->base.inputBuffer;
6210 :
6211 132290706 : cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
6212 132290706 : if ( ismInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel )
6213 : {
6214 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" );
6215 : }
6216 132290706 : ismInput->base.numNewSamplesPerChannel = 0;
6217 :
6218 : /* Apply input gain to new audio */
6219 132290706 : v_multc( inAudio.data, ismInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
6220 :
6221 : /* set combined orientation subframe info to start info */
6222 132290706 : ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
6223 :
6224 132290706 : switch ( getAudioConfigType( outConfig ) )
6225 : {
6226 50488458 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6227 50488458 : error = renderIsmToMc( ismInput, outAudio );
6228 50488458 : break;
6229 19884771 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6230 19884771 : error = renderIsmToSba( ismInput, outConfig, outAudio );
6231 19884771 : break;
6232 61622511 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6233 : switch ( outConfig )
6234 : {
6235 13916204 : case IVAS_AUDIO_CONFIG_BINAURAL:
6236 13916204 : error = renderIsmToBinaural( ismInput, outAudio );
6237 13916204 : break;
6238 13916204 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6239 13916204 : error = renderIsmToBinauralRoom( ismInput, outAudio );
6240 13916204 : break;
6241 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
6242 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
6243 0 : error = renderIsmToSplitBinaural( ismInput, outAudio );
6244 0 : break;
6245 33790103 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6246 33790103 : error = renderIsmToBinauralReverb( ismInput, outAudio );
6247 33790103 : break;
6248 0 : default:
6249 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6250 : }
6251 61622511 : break;
6252 294966 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6253 294966 : renderIsmToMasa( ismInput, outAudio );
6254 294966 : break;
6255 0 : default:
6256 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6257 : }
6258 :
6259 : /* Check error here to keep switch statement more compact */
6260 132290706 : if ( error != IVAS_ERR_OK )
6261 : {
6262 0 : return error;
6263 : }
6264 :
6265 132290706 : ismInput->firstFrameRendered = TRUE;
6266 :
6267 132290706 : return error;
6268 : }
6269 :
6270 :
6271 93743181 : static ivas_error renderActiveInputsIsm(
6272 : IVAS_REND_HANDLE hIvasRend,
6273 : IVAS_REND_AudioBuffer outAudio )
6274 : {
6275 : int16_t i;
6276 : input_ism *pCurrentInput;
6277 : ivas_error error;
6278 :
6279 468715905 : for ( i = 0, pCurrentInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pCurrentInput )
6280 : {
6281 374972724 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
6282 : {
6283 : /* Skip inactive inputs */
6284 242682018 : continue;
6285 : }
6286 :
6287 132290706 : if ( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
6288 : {
6289 0 : return error;
6290 : }
6291 : }
6292 :
6293 93743181 : return IVAS_ERR_OK;
6294 : }
6295 :
6296 3285279 : static void renderMonoStereoToBinaural(
6297 : const input_mc *mcInput,
6298 : IVAS_REND_AudioBuffer outAudio )
6299 : {
6300 : int16_t i;
6301 : IVAS_REND_AudioBuffer inAudio;
6302 :
6303 3285279 : push_wmops( "renderMonoStereoToBinaural" );
6304 3285279 : inAudio = mcInput->base.inputBuffer;
6305 :
6306 8212386 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6307 : {
6308 4927107 : renderBufferChannel( inAudio, i, mcInput->panGains[i], outAudio );
6309 : }
6310 :
6311 3285279 : pop_wmops();
6312 :
6313 3285279 : return;
6314 : }
6315 :
6316 8630844 : static ivas_error renderLfeToBinaural(
6317 : const input_mc *mcInput,
6318 : const AUDIO_CONFIG outConfig,
6319 : IVAS_REND_AudioBuffer outAudio )
6320 : {
6321 : int16_t lfe_idx;
6322 : int16_t pose_idx, num_poses;
6323 : float gain;
6324 : int16_t ear_idx;
6325 : float tmpLfeBuffer[L_FRAME_MAX];
6326 : int16_t frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
6327 : const float *lfeInput;
6328 : float *writePtr;
6329 :
6330 8630844 : assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" );
6331 :
6332 8630844 : push_wmops( "renderLfeToBinaural" );
6333 :
6334 8630844 : gain = GAIN_LFE;
6335 :
6336 8630844 : if ( mcInput->base.inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM )
6337 : {
6338 6445194 : lfe_idx = LFE_CHANNEL;
6339 : }
6340 2185650 : else if ( mcInput->customLsInput.num_lfe > 0 )
6341 : {
6342 0 : lfe_idx = mcInput->customLsInput.lfe_idx[0];
6343 : }
6344 : else
6345 : {
6346 : /* no LFE to render */
6347 2185650 : return IVAS_ERR_OK;
6348 : }
6349 :
6350 : /* --- Prepare LFE signal to be added to binaural output --- */
6351 6445194 : lfeInput = getSmplPtr( mcInput->base.inputBuffer, lfe_idx, 0 );
6352 6445194 : frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
6353 6445194 : num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
6354 6445194 : num_cpy_smpl_cur_frame = frame_size - num_cpy_smpl_prev_frame;
6355 :
6356 6445194 : assert( mcInput->binauralDelaySmp <= MAX_BIN_DELAY_SAMPLES );
6357 :
6358 : /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
6359 6445194 : v_multc( mcInput->lfeDelayBuffer, gain, tmpLfeBuffer, num_cpy_smpl_prev_frame );
6360 :
6361 : /* Continue filling tmp buffer, now with LFE signal from current frame */
6362 6445194 : v_multc( lfeInput, gain, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame );
6363 :
6364 : /* Save remaining LFE samples of current frame for next frame */
6365 6445194 : mvr2r( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer, num_cpy_smpl_prev_frame );
6366 :
6367 : /* Copy LFE to left and right binaural channels for all poses */
6368 6445194 : if ( mcInput->base.ctx.pSplitRendWrapper != NULL )
6369 : {
6370 0 : num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
6371 : }
6372 : else
6373 : {
6374 6445194 : num_poses = 1;
6375 : }
6376 :
6377 12890388 : for ( pose_idx = 0; pose_idx < num_poses; ++pose_idx )
6378 : {
6379 19335582 : for ( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
6380 : {
6381 12890388 : writePtr = getSmplPtr( outAudio, pose_idx * BINAURAL_CHANNELS + ear_idx, 0 );
6382 12890388 : v_add( writePtr, tmpLfeBuffer, writePtr, frame_size );
6383 : }
6384 : }
6385 :
6386 6445194 : pop_wmops();
6387 :
6388 6445194 : return IVAS_ERR_OK;
6389 : }
6390 :
6391 :
6392 2268908 : static ivas_error renderMcToBinaural(
6393 : input_mc *mcInput,
6394 : const AUDIO_CONFIG outConfig,
6395 : IVAS_REND_AudioBuffer outAudio )
6396 : {
6397 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6398 : AUDIO_CONFIG inConfig;
6399 : ivas_error error;
6400 : IVAS_REND_AudioBuffer tmpRotBuffer;
6401 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6402 : int8_t combinedOrientationEnabled;
6403 : int16_t subframe_idx;
6404 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6405 : int16_t i;
6406 :
6407 38571436 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6408 : {
6409 36302528 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6410 : }
6411 :
6412 2268908 : push_wmops( "renderMcToBinaural" );
6413 2268908 : inConfig = mcInput->base.inConfig;
6414 :
6415 2268908 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6416 2268908 : combinedOrientationEnabled = 0;
6417 2268908 : if ( *hCombinedOrientationData != NULL )
6418 : {
6419 1296593 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6420 : {
6421 1296593 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6422 : {
6423 1296593 : combinedOrientationEnabled = 1;
6424 1296593 : break;
6425 : }
6426 : }
6427 : }
6428 :
6429 2268908 : if ( ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 ) ) )
6430 : {
6431 1102710 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6432 :
6433 1102710 : if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
6434 1102710 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK )
6435 : {
6436 0 : return error;
6437 : }
6438 : }
6439 : else
6440 : {
6441 : /* apply rotation */
6442 1166198 : if ( combinedOrientationEnabled )
6443 : {
6444 558158 : tmpRotBuffer = mcInput->base.inputBuffer;
6445 558158 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6446 558158 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6447 :
6448 558158 : 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 )
6449 : {
6450 0 : return error;
6451 : }
6452 :
6453 558158 : copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer );
6454 558158 : free( tmpRotBuffer.data );
6455 : }
6456 : else
6457 : {
6458 608040 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6459 : }
6460 :
6461 : /* call CREND */
6462 1166198 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL,
6463 1166198 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
6464 : {
6465 0 : return error;
6466 : }
6467 : }
6468 :
6469 2268908 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6470 :
6471 2268908 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6472 : {
6473 0 : return error;
6474 : }
6475 :
6476 2268908 : pop_wmops();
6477 2268908 : return IVAS_ERR_OK;
6478 : }
6479 :
6480 :
6481 4904836 : static ivas_error renderMcToBinauralRoom(
6482 : input_mc *mcInput,
6483 : const AUDIO_CONFIG outConfig,
6484 : IVAS_REND_AudioBuffer outAudio )
6485 : {
6486 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6487 : AUDIO_CONFIG inConfig;
6488 : ivas_error error;
6489 : IVAS_REND_AudioBuffer tmpRotBuffer;
6490 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6491 : int16_t i;
6492 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6493 : int8_t combinedOrientationEnabled;
6494 : int16_t subframe_idx;
6495 :
6496 83382212 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6497 : {
6498 78477376 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6499 : }
6500 :
6501 4904836 : push_wmops( "renderMcToBinauralRoom" );
6502 4904836 : inConfig = mcInput->base.inConfig;
6503 :
6504 4904836 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6505 4904836 : combinedOrientationEnabled = 0;
6506 4904836 : if ( *hCombinedOrientationData != NULL )
6507 : {
6508 1864636 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6509 : {
6510 1864636 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6511 : {
6512 1864636 : combinedOrientationEnabled = 1;
6513 1864636 : break;
6514 : }
6515 : }
6516 : }
6517 :
6518 4904836 : 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 ) ) ) )
6519 : {
6520 374160 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6521 :
6522 374160 : if ( ( error = ivas_td_binaural_renderer_ext( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
6523 374160 : 0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer ) ) != IVAS_ERR_OK )
6524 : {
6525 0 : return error;
6526 : }
6527 : }
6528 : else
6529 : {
6530 : /* apply rotation */
6531 4530676 : if ( combinedOrientationEnabled )
6532 : {
6533 1490476 : tmpRotBuffer = mcInput->base.inputBuffer;
6534 1490476 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6535 1490476 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6536 :
6537 1490476 : if ( ( error = rotateFrameMc( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
6538 : {
6539 0 : return error;
6540 : }
6541 :
6542 1490476 : copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer );
6543 1490476 : free( tmpRotBuffer.data );
6544 : }
6545 : else
6546 : {
6547 3040200 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6548 : }
6549 :
6550 : /* call CREND */
6551 4530676 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL,
6552 4530676 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
6553 : {
6554 0 : return error;
6555 : }
6556 : }
6557 :
6558 4904836 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6559 :
6560 4904836 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6561 : {
6562 0 : return error;
6563 : }
6564 :
6565 4904836 : pop_wmops();
6566 4904836 : return IVAS_ERR_OK;
6567 : }
6568 :
6569 :
6570 1457100 : static ivas_error renderMcCustomLsToBinauralRoom(
6571 : input_mc *mcInput,
6572 : const AUDIO_CONFIG outConfig,
6573 : IVAS_REND_AudioBuffer outAudio )
6574 : {
6575 : int16_t i;
6576 : int16_t tmp;
6577 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6578 : ivas_error error;
6579 : IVAS_REND_AudioBuffer tmpRotBuffer;
6580 : IVAS_REND_AudioBuffer tmpMcBuffer;
6581 : IVAS_REND_AudioBuffer *tmpBufPtr;
6582 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
6583 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
6584 : int8_t combinedOrientationEnabled;
6585 : int16_t subframe_idx;
6586 :
6587 1457100 : push_wmops( "renderMcCustomLsToBinauralRoom" );
6588 1457100 : tmpRotBuffer = outAudio; /* avoid compilation warning */
6589 :
6590 24770700 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
6591 : {
6592 23313600 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
6593 : }
6594 :
6595 1457100 : hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
6596 1457100 : combinedOrientationEnabled = 0;
6597 1457100 : if ( *hCombinedOrientationData != NULL )
6598 : {
6599 728550 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
6600 : {
6601 728550 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
6602 : {
6603 728550 : combinedOrientationEnabled = 1;
6604 728550 : break;
6605 : }
6606 : }
6607 : }
6608 :
6609 : /* apply rotation */
6610 1457100 : if ( combinedOrientationEnabled )
6611 : {
6612 728550 : tmpRotBuffer = mcInput->base.inputBuffer;
6613 728550 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6614 728550 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6615 :
6616 728550 : 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 )
6617 : {
6618 0 : return error;
6619 : }
6620 : }
6621 :
6622 : /* intermediate conversion to 7_1_4 */
6623 1457100 : tmpMcBuffer = mcInput->base.inputBuffer;
6624 :
6625 1457100 : if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK )
6626 : {
6627 0 : return error;
6628 : }
6629 :
6630 1457100 : tmpMcBuffer.config.numChannels = tmp;
6631 1457100 : tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) );
6632 1457100 : set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels );
6633 :
6634 1457100 : tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &mcInput->base.inputBuffer;
6635 18904620 : for ( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
6636 : {
6637 17447520 : renderBufferChannel( *tmpBufPtr, i, mcInput->panGains[i], tmpMcBuffer );
6638 : }
6639 1457100 : copyBufferTo2dArray( tmpMcBuffer, tmpCrendBuffer );
6640 :
6641 : /* call CREND */
6642 1457100 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL,
6643 1457100 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
6644 : {
6645 0 : return error;
6646 : }
6647 :
6648 1457100 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
6649 :
6650 1457100 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6651 : {
6652 0 : return error;
6653 : }
6654 :
6655 1457100 : if ( combinedOrientationEnabled )
6656 : {
6657 728550 : free( tmpRotBuffer.data );
6658 : }
6659 1457100 : free( tmpMcBuffer.data );
6660 :
6661 1457100 : pop_wmops();
6662 1457100 : return IVAS_ERR_OK;
6663 : }
6664 :
6665 :
6666 9912912 : static void renderMcToMc(
6667 : const input_mc *mcInput,
6668 : IVAS_REND_AudioBuffer outAudio )
6669 : {
6670 : int16_t i;
6671 : IVAS_REND_AudioBuffer inAudio;
6672 :
6673 9912912 : push_wmops( "renderMcToMc" );
6674 9912912 : inAudio = mcInput->base.inputBuffer;
6675 :
6676 87520059 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6677 : {
6678 77607147 : renderBufferChannel( inAudio, i, mcInput->panGains[i], outAudio );
6679 : }
6680 :
6681 9912912 : pop_wmops();
6682 9912912 : return;
6683 : }
6684 :
6685 :
6686 3852180 : static void renderMcToSba(
6687 : const input_mc *mcInput,
6688 : IVAS_REND_AudioBuffer outAudio )
6689 : {
6690 : int16_t i;
6691 : IVAS_REND_AudioBuffer inAudio;
6692 :
6693 3852180 : push_wmops( "renderMcToSba" );
6694 3852180 : inAudio = mcInput->base.inputBuffer;
6695 :
6696 34427655 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6697 : {
6698 30575475 : renderBufferChannel( inAudio, i, mcInput->panGains[i], outAudio );
6699 : }
6700 :
6701 3852180 : pop_wmops();
6702 3852180 : return;
6703 : }
6704 :
6705 :
6706 6918 : static void renderMcToMasa(
6707 : input_mc *mcInput,
6708 : IVAS_REND_AudioBuffer outAudio )
6709 : {
6710 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6711 :
6712 6918 : push_wmops( "renderMcToMasa" );
6713 6918 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6714 :
6715 6918 : ivas_mcmasa_ana( mcInput->hMcMasa, tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, mcInput->base.inputBuffer.config.numChannels );
6716 :
6717 6918 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
6718 :
6719 6918 : pop_wmops();
6720 6918 : return;
6721 : }
6722 :
6723 :
6724 0 : static ivas_error renderMcToSplitBinaural(
6725 : input_mc *mcInput,
6726 : const AUDIO_CONFIG outConfig,
6727 : IVAS_REND_AudioBuffer outAudio )
6728 : {
6729 : int16_t i, j, pos_idx;
6730 : int16_t sf;
6731 : int16_t output_frame;
6732 : ivas_error error;
6733 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
6734 : const SPLIT_REND_WRAPPER *pSplitRendWrapper;
6735 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
6736 : float *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
6737 : float tmpSplitBinauralBuffer[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
6738 : AUDIO_CONFIG inConfig;
6739 : IVAS_REND_AudioBuffer tmpRotBuffer;
6740 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
6741 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
6742 :
6743 0 : push_wmops( "renderMcToSplitBinaural" );
6744 0 : inConfig = mcInput->base.inConfig;
6745 0 : output_frame = mcInput->base.inputBuffer.config.numSamplesPerChannel;
6746 :
6747 0 : pSplitRendWrapper = mcInput->base.ctx.pSplitRendWrapper;
6748 0 : pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
6749 :
6750 0 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
6751 : {
6752 0 : p_tmpRendBuffer[i] = tmpRendBuffer[i];
6753 : }
6754 :
6755 : /* save current head positions */
6756 0 : pCombinedOrientationDataLocal = *mcInput->base.ctx.pCombinedOrientationData;
6757 0 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
6758 0 : if ( pMultiBinPoseData->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
6759 : {
6760 0 : for ( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
6761 : {
6762 0 : combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0];
6763 0 : for ( i = 0; i < 3; i++ )
6764 : {
6765 0 : for ( j = 0; j < 3; j++ )
6766 : {
6767 0 : combinedOrientationDataLocal.Rmat[sf][i][j] = combinedOrientationDataLocal.Rmat[0][i][j];
6768 : }
6769 : }
6770 : }
6771 : }
6772 :
6773 : /* temporary buffer for rotation in source format for CREND */
6774 0 : tmpRotBuffer = mcInput->base.inputBuffer;
6775 0 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inConfig != IVAS_AUDIO_CONFIG_5_1 && inConfig != IVAS_AUDIO_CONFIG_7_1 )
6776 : {
6777 0 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
6778 : }
6779 :
6780 0 : for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
6781 : {
6782 : /* Update head positions */
6783 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
6784 0 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
6785 : {
6786 0 : Quaternions_orig[i] = combinedOrientationDataLocal.Quaternions[i];
6787 0 : Quaternions_abs.w = -3.0f;
6788 0 : Quat2EulerDegree( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/
6789 :
6790 0 : Quaternions_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0];
6791 0 : Quaternions_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1];
6792 0 : Quaternions_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2];
6793 0 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs;
6794 0 : QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] );
6795 : }
6796 :
6797 0 : if ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM || inConfig == IVAS_AUDIO_CONFIG_5_1 || inConfig == IVAS_AUDIO_CONFIG_7_1 )
6798 : {
6799 : /* tdrend processing overview:
6800 : * 1. copy from inputBuffer to tmpRendBuffer
6801 : * 2. td_binaural_renderer_ext: inplace processing in tmpRendBuffer
6802 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
6803 : * 4. LFE mixing
6804 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
6805 :
6806 : /* copy input to tdrend input/output buffer */
6807 0 : copyBufferTo2dArray( mcInput->base.inputBuffer, tmpRendBuffer );
6808 :
6809 : /* perform rotation in source format to tmpRotBuffer */
6810 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
6811 :
6812 : /* Render */
6813 0 : 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 )
6814 : {
6815 0 : return error;
6816 : }
6817 :
6818 : /* Copy rendered audio to tmp storage buffer. Copying directly to output would
6819 : * overwrite original audio, which is still needed for rendering next head pose. */
6820 0 : mvr2r( tmpRendBuffer[0], tmpSplitBinauralBuffer[2 * pos_idx], output_frame );
6821 0 : mvr2r( tmpRendBuffer[1], tmpSplitBinauralBuffer[2 * pos_idx + 1], output_frame );
6822 : }
6823 : else
6824 : {
6825 : /* crend processing overview:
6826 : * 1. rotateFrameMc: inputBuffer to tmpRotBuffer
6827 : * 2. crend_process: tmpRotBuffer to tmpRendBuffer
6828 : * 3. copy from tmpRendBuffer to tmpSplitBinBuffer
6829 : * 4. LFE mixing
6830 : * 5. tmpSplitBinBuffer accumulated to outBuffer */
6831 :
6832 : /* copy input for in-place rotation */
6833 0 : set_zero( tmpRotBuffer.data, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
6834 :
6835 : /* perform rotation in source format to tmpRotBuffer */
6836 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
6837 0 : 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 )
6838 : {
6839 0 : return error;
6840 : }
6841 :
6842 0 : copyBufferTo2dArray( tmpRotBuffer, tmpRendBuffer );
6843 :
6844 : /* call CREND (rotation already performed) */
6845 0 : if ( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL,
6846 0 : NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, pos_idx ) ) != IVAS_ERR_OK )
6847 : {
6848 0 : return error;
6849 : }
6850 :
6851 : /* Copy rendererd audio to tmp storage buffer, Copying directly to output would
6852 : * overwrite original audio, which is still needed for rendering next head pose. */
6853 0 : mvr2r( tmpRendBuffer[0], tmpSplitBinauralBuffer[2 * pos_idx], output_frame );
6854 0 : mvr2r( tmpRendBuffer[1], tmpSplitBinauralBuffer[2 * pos_idx + 1], output_frame );
6855 : }
6856 :
6857 : /* restore original headrotation data */
6858 0 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
6859 : {
6860 0 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i];
6861 : }
6862 : }
6863 :
6864 0 : if ( inConfig != IVAS_AUDIO_CONFIG_LS_CUSTOM && inConfig != IVAS_AUDIO_CONFIG_5_1 && inConfig != IVAS_AUDIO_CONFIG_7_1 )
6865 : {
6866 : /* free temporary buffer for rotation in source format for CREND */
6867 0 : free( tmpRotBuffer.data );
6868 : }
6869 :
6870 0 : accumulate2dArrayToBuffer( tmpSplitBinauralBuffer, &outAudio );
6871 :
6872 0 : if ( ( error = renderLfeToBinaural( mcInput, outConfig, outAudio ) ) != IVAS_ERR_OK )
6873 : {
6874 0 : return error;
6875 : }
6876 :
6877 0 : pop_wmops();
6878 0 : return IVAS_ERR_OK;
6879 : }
6880 :
6881 :
6882 25688133 : static ivas_error renderInputMc(
6883 : input_mc *mcInput,
6884 : const AUDIO_CONFIG outConfig,
6885 : IVAS_REND_AudioBuffer outAudio )
6886 : {
6887 : ivas_error error;
6888 : IVAS_REND_AudioBuffer inAudio;
6889 :
6890 25688133 : error = IVAS_ERR_OK;
6891 :
6892 25688133 : inAudio = mcInput->base.inputBuffer;
6893 :
6894 25688133 : if ( mcInput->base.numNewSamplesPerChannel != outAudio.config.numSamplesPerChannel )
6895 : {
6896 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" );
6897 : }
6898 25688133 : mcInput->base.numNewSamplesPerChannel = 0;
6899 :
6900 : /* Apply input gain to new audio */
6901 25688133 : v_multc( inAudio.data, mcInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
6902 :
6903 : /* set combined orientation subframe info to start info */
6904 25688133 : ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
6905 :
6906 25688133 : switch ( getAudioConfigType( outConfig ) )
6907 : {
6908 9912912 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
6909 9912912 : renderMcToMc( mcInput, outAudio );
6910 9912912 : break;
6911 3852180 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
6912 3852180 : renderMcToSba( mcInput, outAudio );
6913 3852180 : break;
6914 11916123 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
6915 11916123 : if ( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_MONO || mcInput->base.inConfig == IVAS_AUDIO_CONFIG_STEREO )
6916 : {
6917 3285279 : renderMonoStereoToBinaural( mcInput, outAudio );
6918 3285279 : break;
6919 : }
6920 :
6921 : /* not mono or stereo */
6922 : switch ( outConfig )
6923 : {
6924 2268908 : case IVAS_AUDIO_CONFIG_BINAURAL:
6925 2268908 : error = renderMcToBinaural( mcInput, outConfig, outAudio );
6926 2268908 : break;
6927 6361936 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
6928 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
6929 6361936 : if ( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
6930 : {
6931 1457100 : error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
6932 : }
6933 : else
6934 : {
6935 4904836 : error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
6936 : }
6937 6361936 : break;
6938 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
6939 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
6940 0 : error = renderMcToSplitBinaural( mcInput, outConfig, outAudio );
6941 0 : break;
6942 0 : default:
6943 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6944 : }
6945 8630844 : break;
6946 6918 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
6947 6918 : renderMcToMasa( mcInput, outAudio );
6948 6918 : break;
6949 0 : default:
6950 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
6951 : }
6952 :
6953 25688133 : return error;
6954 : }
6955 :
6956 :
6957 93743181 : static ivas_error renderActiveInputsMc(
6958 : IVAS_REND_HANDLE hIvasRend,
6959 : IVAS_REND_AudioBuffer outAudio )
6960 : {
6961 : int16_t i;
6962 : input_mc *pCurrentInput;
6963 : ivas_error error;
6964 :
6965 187486362 : for ( i = 0, pCurrentInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pCurrentInput )
6966 : {
6967 93743181 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
6968 : {
6969 : /* Skip inactive inputs */
6970 68055048 : continue;
6971 : }
6972 :
6973 25688133 : if ( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
6974 : {
6975 0 : return error;
6976 : }
6977 : }
6978 :
6979 93743181 : return IVAS_ERR_OK;
6980 : }
6981 :
6982 :
6983 13527231 : static void renderSbaToMc(
6984 : const input_sba *sbaInput,
6985 : IVAS_REND_AudioBuffer outAudio )
6986 : {
6987 : int16_t i;
6988 : IVAS_REND_AudioBuffer inAudio;
6989 :
6990 13527231 : push_wmops( "renderSbaToMc" );
6991 13527231 : inAudio = sbaInput->base.inputBuffer;
6992 :
6993 143841732 : for ( i = 0; i < inAudio.config.numChannels; ++i )
6994 : {
6995 130314501 : renderBufferChannel( inAudio, i, sbaInput->hoaDecMtx[i], outAudio );
6996 : }
6997 :
6998 13527231 : pop_wmops();
6999 13527231 : return;
7000 : }
7001 :
7002 :
7003 5339862 : static void renderSbaToSba(
7004 : const input_sba *sbaInput,
7005 : IVAS_REND_AudioBuffer outAudio )
7006 : {
7007 : int16_t i;
7008 : IVAS_REND_AudioBuffer inAudio;
7009 :
7010 5339862 : push_wmops( "renderSbaToSba" );
7011 5339862 : inAudio = sbaInput->base.inputBuffer;
7012 :
7013 56780181 : for ( i = 0; i < inAudio.config.numChannels; ++i )
7014 : {
7015 51440319 : renderBufferChannel( inAudio, i, sbaInput->hoaDecMtx[i], outAudio );
7016 : }
7017 :
7018 5339862 : pop_wmops();
7019 5339862 : return;
7020 : }
7021 :
7022 :
7023 0 : static ivas_error renderSbaToMultiBinaural(
7024 : input_sba *sbaInput,
7025 : const AUDIO_CONFIG outConfig,
7026 : float out[][L_FRAME48k] )
7027 : {
7028 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7029 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7030 : int16_t sf;
7031 : int16_t i, j, pos_idx;
7032 : COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
7033 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
7034 : ivas_error error;
7035 : IVAS_REND_AudioBuffer tmpRotBuffer;
7036 : const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
7037 :
7038 0 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7039 : {
7040 0 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7041 : }
7042 0 : push_wmops( "renderSbaToMultiBinaural" );
7043 0 : pMultiBinPoseData = &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData;
7044 :
7045 0 : pCombinedOrientationDataLocal = *sbaInput->base.ctx.pCombinedOrientationData;
7046 0 : combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
7047 0 : if ( pMultiBinPoseData->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
7048 : {
7049 0 : for ( sf = 1; sf < combinedOrientationDataLocal.num_subframes; sf++ )
7050 : {
7051 0 : combinedOrientationDataLocal.Quaternions[sf] = combinedOrientationDataLocal.Quaternions[0];
7052 0 : for ( i = 0; i < 3; i++ )
7053 : {
7054 0 : for ( j = 0; j < 3; j++ )
7055 : {
7056 0 : combinedOrientationDataLocal.Rmat[sf][i][j] = combinedOrientationDataLocal.Rmat[0][i][j];
7057 : }
7058 : }
7059 : }
7060 : }
7061 :
7062 0 : tmpRotBuffer = sbaInput->base.inputBuffer;
7063 0 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
7064 :
7065 0 : for ( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
7066 : {
7067 : IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
7068 0 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7069 : {
7070 0 : Quaternions_orig[i] = combinedOrientationDataLocal.Quaternions[i];
7071 0 : Quaternions_abs.w = -3.0f;
7072 0 : Quat2EulerDegree( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z, &Quaternions_abs.y, &Quaternions_abs.x ); /*order in Quat2Euler seems to be reversed ?*/
7073 :
7074 0 : Quaternions_abs.x += pMultiBinPoseData->relative_head_poses[pos_idx][0];
7075 0 : Quaternions_abs.y += pMultiBinPoseData->relative_head_poses[pos_idx][1];
7076 0 : Quaternions_abs.z += pMultiBinPoseData->relative_head_poses[pos_idx][2];
7077 0 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_abs;
7078 0 : QuatToRotMat( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat[i] );
7079 : }
7080 :
7081 :
7082 : /* copy input for in-place rotation */
7083 0 : mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7084 :
7085 0 : pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
7086 :
7087 0 : if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, sbaInput->rot_gains_prev[pos_idx], tmpRotBuffer ) ) != IVAS_ERR_OK )
7088 : {
7089 0 : return error;
7090 : }
7091 :
7092 0 : copyBufferTo2dArray( tmpRotBuffer, tmpCrendBuffer );
7093 :
7094 0 : assert( sbaInput->crendWrapper->hCrend[0]->hReverb == NULL );
7095 :
7096 : /* call CREND */
7097 0 : if ( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL,
7098 0 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, pos_idx ) ) != IVAS_ERR_OK )
7099 : {
7100 0 : return error;
7101 : }
7102 :
7103 0 : for ( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
7104 : {
7105 0 : combinedOrientationDataLocal.Quaternions[i] = Quaternions_orig[i];
7106 : }
7107 :
7108 :
7109 : /* move to output */
7110 0 : for ( i = 0; i < BINAURAL_CHANNELS; i++ )
7111 : {
7112 0 : mvr2r( tmpCrendBuffer[i], out[pos_idx * BINAURAL_CHANNELS + i], tmpRotBuffer.config.numSamplesPerChannel );
7113 : }
7114 : }
7115 :
7116 0 : free( tmpRotBuffer.data );
7117 :
7118 0 : pop_wmops();
7119 0 : return IVAS_ERR_OK;
7120 : }
7121 :
7122 :
7123 0 : static void renderSbaToMultiBinauralCldfb(
7124 : input_sba *sbaInput,
7125 : float Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7126 : float Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
7127 : const int16_t low_res_pre_rend_rot,
7128 : const int16_t num_subframes )
7129 : {
7130 : float Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7131 : float Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7132 :
7133 0 : copyBufferToCLDFBarray( sbaInput->base.inputBuffer, Cldfb_RealBuffer, Cldfb_ImagBuffer );
7134 :
7135 0 : ivas_rend_CldfbMultiBinRendProcess( sbaInput->cldfbRendWrapper.hCldfbRend, sbaInput->base.ctx.pCombinedOrientationData, &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData,
7136 : Cldfb_RealBuffer, Cldfb_ImagBuffer, Cldfb_Out_Real, Cldfb_Out_Imag, low_res_pre_rend_rot, num_subframes );
7137 :
7138 0 : return;
7139 : }
7140 :
7141 :
7142 0 : static ivas_error renderSbaToSplitBinaural(
7143 : input_sba *sbaInput,
7144 : const AUDIO_CONFIG outConfig,
7145 : IVAS_REND_AudioBuffer outAudio )
7146 : {
7147 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7148 : ivas_error error;
7149 : float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7150 : float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7151 :
7152 0 : push_wmops( "renderSbaToSplitBinaural" );
7153 :
7154 0 : if ( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
7155 : {
7156 0 : renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 1,
7157 0 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) );
7158 :
7159 0 : accumulateCLDFBArrayToBuffer( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7160 : }
7161 : else
7162 : {
7163 0 : if ( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer ) ) != IVAS_ERR_OK )
7164 : {
7165 0 : return error;
7166 : }
7167 :
7168 0 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
7169 : }
7170 :
7171 0 : pop_wmops();
7172 0 : return IVAS_ERR_OK;
7173 : }
7174 :
7175 :
7176 15157380 : static ivas_error renderSbaToBinaural(
7177 : input_sba *sbaInput,
7178 : const AUDIO_CONFIG outConfig,
7179 : IVAS_REND_AudioBuffer outAudio )
7180 : {
7181 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7182 : ivas_error error;
7183 : IVAS_REND_AudioBuffer tmpRotBuffer;
7184 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7185 : int16_t i;
7186 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7187 : int8_t combinedOrientationEnabled;
7188 : int16_t subframe_idx;
7189 :
7190 15157380 : push_wmops( "renderSbaToBinaural" );
7191 15157380 : if ( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection == IVAS_BIN_RENDERER_TYPE_FASTCONV )
7192 : {
7193 : float Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7194 : float Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7195 :
7196 0 : renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 0,
7197 0 : getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) );
7198 :
7199 0 : accumulateCLDFBArrayToBuffer( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7200 : }
7201 : else
7202 : {
7203 257675460 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7204 : {
7205 242518080 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7206 : }
7207 :
7208 15157380 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7209 15157380 : combinedOrientationEnabled = 0;
7210 15157380 : if ( *hCombinedOrientationData != NULL )
7211 : {
7212 5875848 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7213 : {
7214 5875848 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7215 : {
7216 5875848 : combinedOrientationEnabled = 1;
7217 5875848 : break;
7218 : }
7219 : }
7220 : }
7221 :
7222 : /* apply rotation */
7223 15157380 : if ( combinedOrientationEnabled )
7224 : {
7225 5875848 : tmpRotBuffer = sbaInput->base.inputBuffer;
7226 5875848 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
7227 :
7228 : /* copy input for in-place rotation */
7229 5875848 : mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7230 :
7231 5875848 : if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
7232 5875848 : sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK )
7233 : {
7234 0 : return error;
7235 : }
7236 :
7237 5875848 : copyBufferTo2dArray( tmpRotBuffer, tmpCrendBuffer );
7238 5875848 : free( tmpRotBuffer.data );
7239 : }
7240 : else
7241 : {
7242 9281532 : copyBufferTo2dArray( sbaInput->base.inputBuffer, tmpCrendBuffer );
7243 : }
7244 :
7245 : /* call CREND */
7246 15157380 : if ( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL,
7247 15157380 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
7248 : {
7249 0 : return error;
7250 : }
7251 :
7252 15157380 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
7253 : }
7254 :
7255 15157380 : pop_wmops();
7256 15157380 : return IVAS_ERR_OK;
7257 : }
7258 :
7259 :
7260 4910118 : static ivas_error renderSbaToBinauralRoom(
7261 : input_sba *sbaInput,
7262 : const AUDIO_CONFIG outConfig,
7263 : IVAS_REND_AudioBuffer outAudio )
7264 : {
7265 : int16_t i;
7266 : int16_t tmp;
7267 : float tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7268 : ivas_error error;
7269 : IVAS_REND_AudioBuffer tmpRotBuffer;
7270 : IVAS_REND_AudioBuffer tmpMcBuffer;
7271 : IVAS_REND_AudioBuffer *tmpBufPtr;
7272 : float *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
7273 : const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
7274 : int8_t combinedOrientationEnabled;
7275 : int16_t subframe_idx;
7276 :
7277 4910118 : tmpRotBuffer = outAudio; /* avoid compilation warning */
7278 4910118 : push_wmops( "renderSbaToBinauralRoom" );
7279 :
7280 83472006 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
7281 : {
7282 78561888 : p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
7283 : }
7284 :
7285 4910118 : hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
7286 4910118 : combinedOrientationEnabled = 0;
7287 4910118 : if ( *hCombinedOrientationData != NULL )
7288 : {
7289 2937924 : for ( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
7290 : {
7291 2937924 : if ( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
7292 : {
7293 2937924 : combinedOrientationEnabled = 1;
7294 2937924 : break;
7295 : }
7296 : }
7297 : }
7298 :
7299 : /* apply rotation */
7300 4910118 : if ( combinedOrientationEnabled )
7301 : {
7302 2937924 : tmpRotBuffer = sbaInput->base.inputBuffer;
7303 2937924 : tmpRotBuffer.data = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( float ) );
7304 :
7305 : /* copy input for in-place rotation */
7306 2937924 : mvr2r( sbaInput->base.inputBuffer.data, tmpRotBuffer.data, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
7307 :
7308 2937924 : if ( ( error = rotateFrameSba( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
7309 2937924 : sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev[0], tmpRotBuffer ) ) != IVAS_ERR_OK )
7310 : {
7311 0 : return error;
7312 : }
7313 : }
7314 :
7315 : /* intermediate rendering to 7_1_4 */
7316 4910118 : tmpMcBuffer = sbaInput->base.inputBuffer;
7317 :
7318 4910118 : if ( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ) != IVAS_ERR_OK )
7319 : {
7320 0 : return error;
7321 : }
7322 :
7323 4910118 : tmpMcBuffer.config.numChannels = tmp;
7324 4910118 : tmpMcBuffer.data = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( float ) );
7325 4910118 : set_zero( tmpMcBuffer.data, tmpMcBuffer.config.numChannels * tmpMcBuffer.config.numSamplesPerChannel );
7326 :
7327 4910118 : tmpBufPtr = ( combinedOrientationEnabled ) ? &tmpRotBuffer : &sbaInput->base.inputBuffer;
7328 52198370 : for ( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
7329 : {
7330 47288252 : renderBufferChannel( *tmpBufPtr, i, sbaInput->hoaDecMtx[i], tmpMcBuffer );
7331 : }
7332 :
7333 4910118 : copyBufferTo2dArray( tmpMcBuffer, tmpCrendBuffer );
7334 :
7335 : /* call CREND */
7336 4910118 : if ( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL,
7337 4910118 : NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ) != IVAS_ERR_OK )
7338 : {
7339 0 : return error;
7340 : }
7341 :
7342 4910118 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
7343 :
7344 4910118 : if ( combinedOrientationEnabled )
7345 : {
7346 2937924 : free( tmpRotBuffer.data );
7347 : }
7348 4910118 : free( tmpMcBuffer.data );
7349 :
7350 4910118 : pop_wmops();
7351 4910118 : return IVAS_ERR_OK;
7352 : }
7353 :
7354 :
7355 6918 : static void renderSbaToMasa(
7356 : input_sba *sbaInput,
7357 : IVAS_REND_AudioBuffer outAudio )
7358 : {
7359 : float tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7360 :
7361 6918 : push_wmops( "renderMcToMasa" );
7362 6918 : copyBufferTo2dArray( sbaInput->base.inputBuffer, tmpRendBuffer );
7363 6918 : ivas_dirac_ana( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels );
7364 6918 : accumulate2dArrayToBuffer( tmpRendBuffer, &outAudio );
7365 :
7366 6918 : pop_wmops();
7367 6918 : return;
7368 : }
7369 :
7370 :
7371 38941509 : static ivas_error renderInputSba(
7372 : input_sba *sbaInput,
7373 : const AUDIO_CONFIG outConfig,
7374 : IVAS_REND_AudioBuffer outAudio )
7375 : {
7376 : ivas_error error;
7377 : IVAS_REND_AudioBuffer inAudio;
7378 : int16_t cldfb2tdSampleFact;
7379 :
7380 38941509 : error = IVAS_ERR_OK;
7381 38941509 : inAudio = sbaInput->base.inputBuffer;
7382 :
7383 38941509 : cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
7384 38941509 : if ( ( sbaInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) &&
7385 0 : ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
7386 : {
7387 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" );
7388 : }
7389 38941509 : sbaInput->base.numNewSamplesPerChannel = 0;
7390 :
7391 : /* Apply input gain to new audio */
7392 38941509 : v_multc( inAudio.data, sbaInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
7393 :
7394 : /* set combined orientation subframe info to start info */
7395 38941509 : ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
7396 :
7397 38941509 : switch ( getAudioConfigType( outConfig ) )
7398 : {
7399 13527231 : case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
7400 13527231 : renderSbaToMc( sbaInput, outAudio );
7401 13527231 : break;
7402 5339862 : case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
7403 5339862 : renderSbaToSba( sbaInput, outAudio );
7404 5339862 : break;
7405 20067498 : case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
7406 : switch ( outConfig )
7407 : {
7408 0 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
7409 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
7410 0 : error = renderSbaToSplitBinaural( sbaInput, outConfig, outAudio );
7411 0 : break;
7412 15157380 : case IVAS_AUDIO_CONFIG_BINAURAL:
7413 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
7414 15157380 : error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
7415 15157380 : break;
7416 4910118 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
7417 4910118 : error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
7418 4910118 : break;
7419 0 : default:
7420 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7421 : }
7422 20067498 : break;
7423 6918 : case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
7424 6918 : renderSbaToMasa( sbaInput, outAudio );
7425 6918 : break;
7426 0 : default:
7427 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
7428 : }
7429 :
7430 38941509 : return error;
7431 : }
7432 :
7433 :
7434 93743181 : static ivas_error renderActiveInputsSba(
7435 : IVAS_REND_HANDLE hIvasRend,
7436 : IVAS_REND_AudioBuffer outAudio )
7437 : {
7438 : int16_t i;
7439 : input_sba *pCurrentInput;
7440 : ivas_error error;
7441 :
7442 187486362 : for ( i = 0, pCurrentInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pCurrentInput )
7443 : {
7444 93743181 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
7445 : {
7446 : /* Skip inactive inputs */
7447 54801672 : continue;
7448 : }
7449 :
7450 38941509 : if ( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
7451 : {
7452 0 : return error;
7453 : }
7454 : }
7455 :
7456 93743181 : return IVAS_ERR_OK;
7457 : }
7458 :
7459 :
7460 17910615 : static void copyMasaMetadataToDiracRenderer(
7461 : MASA_METADATA_FRAME *meta,
7462 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
7463 : const int16_t maxBin )
7464 : {
7465 : int16_t band, sf, bin;
7466 : int16_t meta_write_index;
7467 :
7468 17910615 : hSpatParamRendCom->numParametricDirections = meta->descriptive_meta.numberOfDirections + 1;
7469 17910615 : hSpatParamRendCom->numSimultaneousDirections = meta->descriptive_meta.numberOfDirections + 1;
7470 :
7471 89553075 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
7472 : {
7473 71642460 : meta_write_index = ( hSpatParamRendCom->dirac_bs_md_write_idx + sf ) % hSpatParamRendCom->dirac_md_buffer_length;
7474 :
7475 1791061500 : for ( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
7476 : {
7477 4585117440 : for ( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
7478 : {
7479 2865698400 : hSpatParamRendCom->azimuth[meta_write_index][bin] = (int16_t) meta->directional_meta[0].azimuth[sf][band];
7480 2865698400 : hSpatParamRendCom->elevation[meta_write_index][bin] = (int16_t) meta->directional_meta[0].elevation[sf][band];
7481 2865698400 : hSpatParamRendCom->energy_ratio1[meta_write_index][bin] = meta->directional_meta[0].energy_ratio[sf][band];
7482 2865698400 : hSpatParamRendCom->diffuseness_vector[meta_write_index][bin] = 1.0f - meta->directional_meta[0].energy_ratio[sf][band];
7483 2865698400 : hSpatParamRendCom->spreadCoherence[meta_write_index][bin] = meta->directional_meta[0].spread_coherence[sf][band];
7484 2865698400 : hSpatParamRendCom->surroundingCoherence[meta_write_index][bin] = meta->common_meta.surround_coherence[sf][band];
7485 :
7486 2865698400 : if ( hSpatParamRendCom->numSimultaneousDirections == 2 )
7487 : {
7488 1351109280 : hSpatParamRendCom->azimuth2[meta_write_index][bin] = (int16_t) meta->directional_meta[1].azimuth[sf][band];
7489 1351109280 : hSpatParamRendCom->elevation2[meta_write_index][bin] = (int16_t) meta->directional_meta[1].elevation[sf][band];
7490 1351109280 : hSpatParamRendCom->energy_ratio2[meta_write_index][bin] = meta->directional_meta[1].energy_ratio[sf][band];
7491 1351109280 : hSpatParamRendCom->diffuseness_vector[meta_write_index][bin] -= meta->directional_meta[1].energy_ratio[sf][band];
7492 1351109280 : hSpatParamRendCom->spreadCoherence2[meta_write_index][bin] = meta->directional_meta[1].spread_coherence[sf][band];
7493 : }
7494 : }
7495 : }
7496 : }
7497 :
7498 17910615 : hSpatParamRendCom->dirac_bs_md_write_idx = ( hSpatParamRendCom->dirac_bs_md_write_idx + MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
7499 :
7500 17910615 : return;
7501 : }
7502 :
7503 :
7504 294966 : static void renderMasaToMasa(
7505 : input_masa *masaInput,
7506 : IVAS_REND_AudioBuffer outAudio )
7507 : {
7508 : int16_t sf, band, dir, numDirs;
7509 : float ratioSum;
7510 : MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
7511 : MASA_METADATA_FRAME *inMeta;
7512 : float tmpBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7513 : int16_t ts, i, j, l_ts;
7514 : float Chan_RealBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
7515 : float Chan_ImagBuffer[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
7516 : int16_t band_m_idx, block_m_idx;
7517 : int16_t mrange[2];
7518 : int16_t brange[2];
7519 : int16_t numAnalysisChannels;
7520 :
7521 294966 : copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer );
7522 :
7523 : /* Calculate energy */
7524 294966 : l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
7525 294966 : numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
7526 :
7527 : /* do processing over all CLDFB time slots */
7528 1474830 : for ( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
7529 : {
7530 1179864 : mrange[0] = DirAC_block_grouping[block_m_idx];
7531 1179864 : mrange[1] = DirAC_block_grouping[block_m_idx + 1];
7532 :
7533 1179864 : set_zero( masaInput->hMasaPrerend->energy[block_m_idx], MASA_FREQUENCY_BANDS );
7534 :
7535 5899320 : for ( ts = mrange[0]; ts < mrange[1]; ts++ )
7536 : {
7537 11805888 : for ( i = 0; i < numAnalysisChannels; i++ )
7538 : {
7539 7086432 : cldfbAnalysis_ts( &( tmpBuffer[i][l_ts * ts] ), Chan_RealBuffer[i], Chan_ImagBuffer[i], l_ts, masaInput->hMasaPrerend->cldfbAnaEnc[i] );
7540 : }
7541 :
7542 : /* Compute channel energy for metadata processing */
7543 110120640 : for ( band_m_idx = 0; band_m_idx < masaInput->hMasaPrerend->nbands; band_m_idx++ )
7544 : {
7545 105401184 : brange[0] = masaInput->hMasaPrerend->band_grouping[band_m_idx];
7546 105401184 : brange[1] = masaInput->hMasaPrerend->band_grouping[band_m_idx + 1];
7547 :
7548 294179424 : for ( j = brange[0]; j < brange[1]; j++ )
7549 : {
7550 472235520 : for ( i = 0; i < numAnalysisChannels; i++ )
7551 : {
7552 283457280 : 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];
7553 : }
7554 : }
7555 : }
7556 : }
7557 : }
7558 :
7559 : /* Copy audio channels if mismatch in number of transports */
7560 294966 : if ( masaInput->base.inputBuffer.config.numChannels == 1 && outAudio.config.numChannels == 2 )
7561 : {
7562 73515 : mvr2r( tmpBuffer[0], tmpBuffer[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
7563 : }
7564 221451 : else if ( masaInput->base.inputBuffer.config.numChannels == 2 && outAudio.config.numChannels == 1 )
7565 : {
7566 73968 : v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
7567 : }
7568 :
7569 : /* Copy metadata */
7570 294966 : outMeta = masaInput->hMasaPrerend->hMasaOut;
7571 294966 : inMeta = &masaInput->masaMetadata;
7572 294966 : numDirs = inMeta->descriptive_meta.numberOfDirections + 1;
7573 :
7574 1474830 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
7575 : {
7576 29496600 : for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
7577 : {
7578 : /* Remainder is always set to zero and energy removal is compensated in following steps
7579 : * to other ratios. */
7580 28316736 : inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
7581 :
7582 28316736 : ratioSum = 0;
7583 70891200 : for ( dir = 0; dir < numDirs; dir++ )
7584 : {
7585 42574464 : ratioSum += inMeta->directional_meta[dir].energy_ratio[sf][band];
7586 : }
7587 28316736 : ratioSum += inMeta->common_meta.diffuse_to_total_ratio[sf][band];
7588 :
7589 28316736 : if ( ratioSum == 0.0f )
7590 : {
7591 0 : for ( dir = 0; dir < numDirs; dir++ )
7592 : {
7593 0 : inMeta->directional_meta[dir].energy_ratio[sf][band] = 0.0f;
7594 : }
7595 0 : inMeta->common_meta.diffuse_to_total_ratio[sf][band] = 1.0f;
7596 : }
7597 28316736 : else if ( ratioSum != 1.0f )
7598 : {
7599 554562 : for ( dir = 0; dir < numDirs; dir++ )
7600 : {
7601 369708 : inMeta->directional_meta[dir].energy_ratio[sf][band] /= ratioSum;
7602 : }
7603 184854 : inMeta->common_meta.diffuse_to_total_ratio[sf][band] /= ratioSum;
7604 : }
7605 : }
7606 : }
7607 :
7608 1474830 : for ( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
7609 : {
7610 29496600 : for ( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
7611 : {
7612 28316736 : outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
7613 70891200 : for ( dir = 0; dir < numDirs; dir++ )
7614 : {
7615 42574464 : 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 );
7616 42574464 : outMeta->directToTotalRatio[dir][sf][band] = (uint8_t) floorf( inMeta->directional_meta[dir].energy_ratio[sf][band] * UINT8_MAX );
7617 42574464 : outMeta->diffuseToTotalRatio[sf][band] -= outMeta->directToTotalRatio[dir][sf][band];
7618 42574464 : outMeta->spreadCoherence[dir][sf][band] = (uint8_t) floorf( inMeta->directional_meta[dir].spread_coherence[sf][band] * UINT8_MAX );
7619 : }
7620 28316736 : outMeta->surroundCoherence[sf][band] = (uint8_t) floorf( inMeta->common_meta.surround_coherence[sf][band] * UINT8_MAX );
7621 : }
7622 : }
7623 :
7624 294966 : copy_masa_descriptive_meta( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
7625 :
7626 294966 : accumulate2dArrayToBuffer( tmpBuffer, &outAudio );
7627 :
7628 294966 : return;
7629 : }
7630 :
7631 :
7632 18652086 : static ivas_error renderInputMasa(
7633 : input_masa *masaInput,
7634 : const AUDIO_CONFIG outConfig,
7635 : IVAS_REND_AudioBuffer outAudio )
7636 : {
7637 : IVAS_REND_AudioBuffer inAudio;
7638 : int16_t ch;
7639 : int16_t maxBin;
7640 : float *tmpBuffer[MAX_OUTPUT_CHANNELS];
7641 : float tmpBuffer_buff[MAX_OUTPUT_CHANNELS][L_FRAME48k];
7642 : int16_t cldfb2tdSampleFact;
7643 : float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7644 : float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
7645 :
7646 18652086 : if ( !masaInput->metadataHasBeenFed )
7647 : {
7648 0 : return IVAS_ERR_MISSING_METADATA;
7649 : }
7650 :
7651 18652086 : inAudio = masaInput->base.inputBuffer;
7652 18652086 : cldfb2tdSampleFact = outAudio.config.is_cldfb ? 2 : 1;
7653 18652086 : if ( ( masaInput->base.numNewSamplesPerChannel * cldfb2tdSampleFact != outAudio.config.numSamplesPerChannel ) &&
7654 0 : ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && ( outConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
7655 : {
7656 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" );
7657 : }
7658 18652086 : masaInput->base.numNewSamplesPerChannel = 0;
7659 :
7660 : /* Apply input gain to new audio */
7661 18652086 : v_multc( inAudio.data, masaInput->base.gain, inAudio.data, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
7662 :
7663 18652086 : maxBin = (int16_t) ( *masaInput->base.ctx.pOutSampleRate * INV_CLDFB_BANDWIDTH );
7664 :
7665 : /* set combined orientation subframe info to start info */
7666 18652086 : ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
7667 :
7668 18652086 : if ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7669 : {
7670 : /* MASA prerendering path for MASA -> MASA */
7671 294966 : renderMasaToMasa( masaInput, outAudio );
7672 : }
7673 : else
7674 : {
7675 : /* MASA external renderer -> other formats */
7676 : int16_t num_subframes;
7677 312071040 : for ( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
7678 : {
7679 293713920 : tmpBuffer[ch] = tmpBuffer_buff[ch];
7680 : }
7681 :
7682 18357120 : copyBufferTo2dArray( masaInput->base.inputBuffer, tmpBuffer_buff );
7683 :
7684 18357120 : num_subframes = (int16_t) ( masaInput->base.inputBuffer.config.numSamplesPerChannel / ( *masaInput->base.ctx.pOutSampleRate / ( IVAS_NUM_FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ) );
7685 :
7686 18357120 : if ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
7687 0 : {
7688 : /* split rendering. use the combined of the first subframe in all subframes */
7689 : int16_t sf, i, j;
7690 : COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
7691 0 : pCombinedOrientationData = *masaInput->base.ctx.pCombinedOrientationData;
7692 0 : for ( sf = 1; sf < pCombinedOrientationData->num_subframes; sf++ )
7693 : {
7694 0 : pCombinedOrientationData->Quaternions[sf] = pCombinedOrientationData->Quaternions[0];
7695 0 : for ( i = 0; i < 3; i++ )
7696 : {
7697 0 : for ( j = 0; j < 3; j++ )
7698 : {
7699 0 : pCombinedOrientationData->Rmat[sf][i][j] = pCombinedOrientationData->Rmat[0][i][j];
7700 : }
7701 : }
7702 : }
7703 :
7704 0 : copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
7705 :
7706 0 : 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 );
7707 :
7708 0 : accumulateCLDFBArrayToBuffer( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
7709 : }
7710 : else
7711 : {
7712 : /* non-split path */
7713 18357120 : switch ( masaInput->hMasaExtRend->renderer_type )
7714 : {
7715 8544765 : case RENDERER_DIRAC:
7716 8544765 : copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
7717 8544765 : ivas_masa_ext_dirac_render( masaInput->hMasaExtRend, tmpBuffer, num_subframes );
7718 8544765 : break;
7719 9365850 : case RENDERER_STEREO_PARAMETRIC:
7720 : case RENDERER_BINAURAL_PARAMETRIC:
7721 : case RENDERER_BINAURAL_PARAMETRIC_ROOM:
7722 9365850 : copyMasaMetadataToDiracRenderer( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
7723 9365850 : ivas_masa_ext_rend_parambin_render( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer, num_subframes, NULL, NULL, NULL );
7724 9365850 : break;
7725 446505 : case RENDERER_DISABLE:
7726 446505 : break; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
7727 0 : default:
7728 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
7729 : }
7730 :
7731 18357120 : accumulate2dArrayToBuffer( tmpBuffer_buff, &outAudio );
7732 : }
7733 : }
7734 :
7735 18652086 : return IVAS_ERR_OK;
7736 : }
7737 :
7738 :
7739 93743181 : static ivas_error renderActiveInputsMasa(
7740 : IVAS_REND_HANDLE hIvasRend,
7741 : IVAS_REND_AudioBuffer outAudio )
7742 : {
7743 : int16_t i;
7744 : input_masa *pCurrentInput;
7745 : ivas_error error;
7746 :
7747 187486362 : for ( i = 0, pCurrentInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pCurrentInput )
7748 : {
7749 93743181 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
7750 : {
7751 : /* Skip inactive inputs */
7752 75091095 : continue;
7753 : }
7754 :
7755 18652086 : if ( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ) != IVAS_ERR_OK )
7756 : {
7757 0 : return error;
7758 : }
7759 : }
7760 :
7761 93743181 : return IVAS_ERR_OK;
7762 : }
7763 :
7764 :
7765 : /*---------------------------------------------------------------------*
7766 : * IVAS_REND_GetMasaMetadata( )
7767 : *
7768 : * Get metadata of the estimated MASA frame
7769 : *---------------------------------------------------------------------*/
7770 :
7771 0 : ivas_error IVAS_REND_GetMasaMetadata(
7772 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7773 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to analyzed MASA metadata */
7774 : const IVAS_REND_AudioConfigType inputType /* i : Input type */
7775 : )
7776 : {
7777 0 : if ( hIvasRend == NULL )
7778 : {
7779 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7780 : }
7781 :
7782 : /* Get the metadata handle */
7783 0 : if ( inputType == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
7784 : {
7785 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7786 : }
7787 0 : else if ( inputType == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
7788 : {
7789 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7790 : }
7791 0 : else if ( inputType == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
7792 : {
7793 0 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7794 : }
7795 : else
7796 : {
7797 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7798 : }
7799 :
7800 0 : return IVAS_ERR_OK;
7801 : }
7802 :
7803 :
7804 : /*---------------------------------------------------------------------*
7805 : * IVAS_REND_MergeMasaMetadata( )
7806 : *
7807 : * Merge MASA metadata from two formats
7808 : *---------------------------------------------------------------------*/
7809 :
7810 308700 : ivas_error IVAS_REND_MergeMasaMetadata(
7811 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7812 : MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o : pointer to handle, which will be set to point to merged metadata */
7813 : const IVAS_REND_AudioConfigType inputType1, /* i : Input type 1 */
7814 : const IVAS_REND_AudioConfigType inputType2 /* i : Input type 2 */
7815 : )
7816 : {
7817 : MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
7818 : float( *inEne1 )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7819 : float( *inEne2 )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
7820 :
7821 308700 : if ( hIvasRend == NULL )
7822 : {
7823 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7824 : }
7825 :
7826 : /* Input1 metadata and energy */
7827 308700 : if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
7828 : {
7829 0 : *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7830 0 : inEne1 = &( hIvasRend->inputsIsm->hOMasa->energy );
7831 : }
7832 308700 : else if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
7833 : {
7834 0 : *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7835 0 : inEne1 = &( hIvasRend->inputsMc->hMcMasa->energy );
7836 : }
7837 308700 : else if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
7838 : {
7839 20700 : *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
7840 20700 : inEne1 = &( hIvasRend->inputsSba->hDirAC->energy );
7841 : }
7842 288000 : else if ( inputType1 == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7843 : {
7844 288000 : *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7845 288000 : inEne1 = &( hIvasRend->inputsMasa->hMasaPrerend->energy );
7846 : }
7847 : else
7848 : {
7849 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7850 : }
7851 :
7852 : /* Input2 metadata and energy */
7853 308700 : if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED )
7854 : {
7855 294900 : inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
7856 294900 : inEne2 = &( hIvasRend->inputsIsm->hOMasa->energy );
7857 : }
7858 13800 : else if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED )
7859 : {
7860 6900 : inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
7861 6900 : inEne2 = &( hIvasRend->inputsMc->hMcMasa->energy );
7862 : }
7863 6900 : else if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS )
7864 : {
7865 0 : inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
7866 0 : inEne2 = &( hIvasRend->inputsSba->hDirAC->energy );
7867 : }
7868 6900 : else if ( inputType2 == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7869 : {
7870 6900 : inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
7871 6900 : inEne2 = &( hIvasRend->inputsMasa->hMasaPrerend->energy );
7872 : }
7873 : else
7874 : {
7875 0 : return IVAS_ERR_NOT_SUPPORTED_OPTION;
7876 : }
7877 :
7878 : /* Merge metadata */
7879 308700 : ivas_prerend_merge_masa_metadata( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1, inMeta2, inputType2, *inEne2 );
7880 308700 : ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_MASA1 ? 0u : 1u;
7881 :
7882 308700 : return IVAS_ERR_OK;
7883 : }
7884 :
7885 :
7886 : /*---------------------------------------------------------------------*
7887 : * IVAS_REND_SetTotalNumberOfObjects( )
7888 : *
7889 : * Set the total number of objects to the first object data
7890 : *---------------------------------------------------------------------*/
7891 :
7892 3177 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
7893 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7894 : const uint16_t total_num_objects /* i : total number of objects */
7895 : )
7896 : {
7897 3177 : if ( hIvasRend == NULL )
7898 : {
7899 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7900 : }
7901 :
7902 3177 : hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
7903 :
7904 3177 : return IVAS_ERR_OK;
7905 : }
7906 :
7907 :
7908 : /*---------------------------------------------------------------------*
7909 : * IVAS_REND_SetIsmMetadataDelay( )
7910 : *
7911 : * Set the Metadata Delay in ms in order to sync with audio delay
7912 : *---------------------------------------------------------------------*/
7913 :
7914 3177 : ivas_error IVAS_REND_SetIsmMetadataDelay(
7915 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
7916 : const int16_t sync_md_delay /* i : ISM Metadata Delay in ms to sync with audio delay */
7917 : )
7918 : {
7919 : int16_t i;
7920 :
7921 3177 : if ( hIvasRend == NULL )
7922 : {
7923 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7924 : }
7925 :
7926 15885 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
7927 : {
7928 12708 : hIvasRend->inputsIsm[i].ism_metadata_delay_ms = sync_md_delay;
7929 : }
7930 :
7931 3177 : return IVAS_ERR_OK;
7932 : }
7933 :
7934 :
7935 : /*-------------------------------------------------------------------*
7936 : * getSamplesInternal()
7937 : *
7938 : *
7939 : *-------------------------------------------------------------------*/
7940 :
7941 93743181 : static ivas_error getSamplesInternal(
7942 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
7943 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
7944 : )
7945 : {
7946 : ivas_error error;
7947 : int16_t numOutChannels;
7948 : int16_t cldfb2tdSampleFact;
7949 :
7950 : /* Validate function arguments */
7951 93743181 : if ( hIvasRend == NULL || outAudio.data == NULL )
7952 : {
7953 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
7954 : }
7955 :
7956 93743181 : cldfb2tdSampleFact = ( outAudio.config.is_cldfb ) ? 2 : 1;
7957 :
7958 93743181 : if ( outAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
7959 93743181 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
7960 : {
7961 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
7962 : }
7963 :
7964 93743181 : if ( outAudio.config.numChannels <= 0 || MAX_OUTPUT_CHANNELS < outAudio.config.numChannels )
7965 : {
7966 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
7967 : }
7968 :
7969 93743181 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
7970 45597315 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
7971 45597315 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
7972 45597315 : ( outAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( hIvasRend->num_subframes * BINAURAL_RENDERING_FRAME_SIZE_MS ) * hIvasRend->sampleRateOut )
7973 : {
7974 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
7975 : }
7976 :
7977 : /* Check that there is allowed configuration for MASA format output */
7978 93743181 : if ( getAudioConfigType( hIvasRend->outputConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_MASA )
7979 : {
7980 : int16_t i;
7981 294966 : int16_t numMasaInputs = 0;
7982 294966 : int16_t numOtherInputs = 0;
7983 :
7984 589932 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
7985 : {
7986 294966 : numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7987 : }
7988 :
7989 589932 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
7990 : {
7991 294966 : numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7992 : }
7993 :
7994 589932 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
7995 : {
7996 294966 : numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
7997 : }
7998 :
7999 : /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
8000 294966 : numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
8001 :
8002 294966 : if ( numMasaInputs == 0 || numOtherInputs == 0 )
8003 : {
8004 0 : return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
8005 : }
8006 : }
8007 :
8008 93743181 : if ( ( error = IVAS_REND_GetNumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
8009 : {
8010 0 : return error;
8011 : }
8012 :
8013 93743181 : if ( numOutChannels != outAudio.config.numChannels &&
8014 0 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
8015 0 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
8016 : {
8017 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
8018 : }
8019 :
8020 : /* Clear output buffer */
8021 93743181 : set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
8022 :
8023 93743181 : if ( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
8024 : {
8025 0 : return error;
8026 : }
8027 :
8028 93743181 : if ( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
8029 : {
8030 0 : return error;
8031 : }
8032 :
8033 93743181 : if ( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
8034 : {
8035 0 : return error;
8036 : }
8037 :
8038 93743181 : if ( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
8039 : {
8040 0 : return error;
8041 : }
8042 :
8043 93743181 : return IVAS_ERR_OK;
8044 : }
8045 :
8046 : /*-------------------------------------------------------------------*
8047 : * IVAS_REND_GetSamples()
8048 : *
8049 : *
8050 : *-------------------------------------------------------------------*/
8051 :
8052 93743181 : ivas_error IVAS_REND_GetSamples(
8053 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
8054 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
8055 : )
8056 : {
8057 : ivas_error error;
8058 :
8059 93743181 : if ( ( error = getSamplesInternal( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
8060 : {
8061 0 : return error;
8062 : }
8063 :
8064 93743181 : if ( outAudio.config.is_cldfb == 0 )
8065 : {
8066 : #ifndef DISABLE_LIMITER
8067 : #ifdef DEBUGGING
8068 : hIvasRend->numClipping +=
8069 : #endif
8070 93743181 : limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
8071 : #endif
8072 : }
8073 :
8074 : /* update global cominbed orientation start index */
8075 93743181 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
8076 :
8077 93743181 : return IVAS_ERR_OK;
8078 : }
8079 :
8080 :
8081 : /*-------------------------------------------------------------------*
8082 : * IVAS_REND_GetSplitBinauralBitstream()
8083 : *
8084 : *
8085 : *-------------------------------------------------------------------*/
8086 :
8087 0 : ivas_error IVAS_REND_GetSplitBinauralBitstream(
8088 : IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
8089 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
8090 : IVAS_REND_BitstreamBuffer *hBits /* o : buffer for output bitstream */
8091 : )
8092 : {
8093 : ivas_error error;
8094 : int16_t ch;
8095 : int16_t cldfb_in_flag;
8096 : int16_t i, ro_md_flag;
8097 : int16_t num_poses_orig;
8098 : float *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
8099 : float Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8100 : float Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
8101 : IVAS_REND_AudioBufferConfig *pSplitEncBufConfig;
8102 : ISAR_SPLIT_REND_CONFIG_HANDLE pSplitRendConfig;
8103 : ISAR_SPLIT_REND_BITS_DATA bits;
8104 : float *p_Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX];
8105 : float *p_Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX];
8106 : int16_t j;
8107 :
8108 0 : for ( i = 0; i < BINAURAL_CHANNELS * MAX_HEAD_ROT_POSES; ++i )
8109 : {
8110 0 : for ( j = 0; j < CLDFB_NO_COL_MAX; ++j )
8111 : {
8112 0 : p_Cldfb_RealBuffer_Binaural[i][j] = Cldfb_RealBuffer_Binaural[i][j];
8113 0 : p_Cldfb_ImagBuffer_Binaural[i][j] = Cldfb_ImagBuffer_Binaural[i][j];
8114 : }
8115 : }
8116 :
8117 0 : for ( ch = 0; ch < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; ch++ )
8118 : {
8119 0 : tmpBinaural[ch] = tmpBinaural_buff[ch];
8120 : }
8121 :
8122 0 : cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
8123 0 : pSplitEncBufConfig = &hIvasRend->splitRendEncBuffer.config;
8124 0 : pSplitRendConfig = &hIvasRend->hRendererConfig->split_rend_config;
8125 :
8126 : /* 0 DoF / No pose correction retains frame size */
8127 0 : pSplitEncBufConfig->is_cldfb = cldfb_in_flag;
8128 0 : if ( pSplitRendConfig->dof == 0 || pSplitRendConfig->poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
8129 : {
8130 0 : pSplitEncBufConfig->numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
8131 : }
8132 : /* Pose correction requires 20ms */
8133 : else
8134 : {
8135 0 : pSplitEncBufConfig->numSamplesPerChannel = (int16_t) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
8136 : }
8137 0 : pSplitEncBufConfig->numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
8138 :
8139 0 : num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
8140 0 : ISAR_PRE_REND_GetMultiBinPoseData( pSplitRendConfig,
8141 0 : &hIvasRend->splitRendWrapper->multiBinPoseData,
8142 : hIvasRend->headRotData.sr_pose_pred_axis );
8143 0 : assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" );
8144 :
8145 : /* hIvasRend->splitRendEncBuffer contains multi-pose data for BINAURAL_SPLIT_CODED output
8146 : outAudio used later for main pose BINAURAL_SPLIT_PCM output */
8147 0 : if ( ( error = getSamplesInternal( hIvasRend, hIvasRend->splitRendEncBuffer ) ) != IVAS_ERR_OK )
8148 : {
8149 0 : return error;
8150 : }
8151 :
8152 : /* copy outputs */
8153 0 : if ( hIvasRend->splitRendEncBuffer.config.is_cldfb == 1 )
8154 : {
8155 0 : cldfb_in_flag = 1;
8156 0 : copyBufferToCLDFBarray( hIvasRend->splitRendEncBuffer, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
8157 : }
8158 : else
8159 : {
8160 0 : cldfb_in_flag = 0;
8161 0 : copyBufferTo2dArray( hIvasRend->splitRendEncBuffer, tmpBinaural_buff );
8162 : }
8163 :
8164 : /* Encode split rendering bitstream */
8165 0 : convertBitsBufferToInternalBitsBuff( *hBits, &bits );
8166 :
8167 0 : ro_md_flag = 0;
8168 0 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8169 : {
8170 0 : if ( hIvasRend->inputsIsm[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
8171 : {
8172 0 : ro_md_flag = 1;
8173 0 : break;
8174 : }
8175 : }
8176 :
8177 0 : if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper,
8178 : hIvasRend->headRotData.headPositions[0],
8179 : pSplitRendConfig->splitRendBitRate,
8180 : pSplitRendConfig->codec,
8181 0 : pSplitRendConfig->isar_frame_size_ms,
8182 0 : pSplitRendConfig->codec_frame_size_ms,
8183 : &bits,
8184 : p_Cldfb_RealBuffer_Binaural,
8185 : p_Cldfb_ImagBuffer_Binaural,
8186 0 : ( const int16_t )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ),
8187 : tmpBinaural,
8188 : 1,
8189 : cldfb_in_flag,
8190 0 : ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0,
8191 : ro_md_flag ) ) != IVAS_ERR_OK )
8192 : {
8193 0 : return error;
8194 : }
8195 :
8196 0 : convertInternalBitsBuffToBitsBuffer( hBits, bits );
8197 :
8198 : /* copy over first pose data to outAudio */
8199 0 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
8200 : {
8201 : /* set outAudio to zero - getSamplesInternal only cleared splitRendEncBuffer */
8202 0 : set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
8203 0 : accumulate2dArrayToBuffer( tmpBinaural_buff, &outAudio );
8204 : }
8205 :
8206 0 : if ( outAudio.config.is_cldfb == 0 )
8207 : {
8208 : #ifndef DISABLE_LIMITER
8209 : #ifdef DEBUGGING
8210 : hIvasRend->numClipping +=
8211 : #endif
8212 0 : limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
8213 : #endif
8214 : }
8215 :
8216 : /* update global cominbed orientation start index */
8217 0 : ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
8218 :
8219 0 : return IVAS_ERR_OK;
8220 : }
8221 :
8222 :
8223 : /*-------------------------------------------------------------------*
8224 : * IVAS_REND_GetSplitRendBitstreamHeader()
8225 : *
8226 : *
8227 : *-------------------------------------------------------------------*/
8228 :
8229 0 : ivas_error IVAS_REND_GetSplitRendBitstreamHeader(
8230 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8231 : ISAR_SPLIT_REND_CODEC *pCodec, /* o : pointer to codec setting */
8232 : ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o : pointer to pose correction mode */
8233 : int16_t *pCodec_frame_size_ms, /* o : pointer to codec frame size setting */
8234 : int16_t *pIsar_frame_size_ms, /* o : pointer to ISAR frame size setting */
8235 : int16_t *pLc3plusHighRes /* o : pointer to LC3plus High-Res setting */
8236 : )
8237 : {
8238 0 : if ( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
8239 : {
8240 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8241 : }
8242 :
8243 0 : *pCodec = hIvasRend->hRendererConfig->split_rend_config.codec;
8244 0 : *pCodec_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms;
8245 0 : *pIsar_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms;
8246 0 : *poseCorrection = hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode;
8247 0 : *pLc3plusHighRes = hIvasRend->hRendererConfig->split_rend_config.lc3plus_highres;
8248 :
8249 0 : return IVAS_ERR_OK;
8250 : }
8251 :
8252 :
8253 : /*-------------------------------------------------------------------*
8254 : * IVAS_REND_Close()
8255 : *
8256 : *
8257 : *-------------------------------------------------------------------*/
8258 :
8259 5151 : void IVAS_REND_Close(
8260 : IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
8261 : )
8262 : {
8263 : uint16_t i;
8264 : IVAS_REND_HANDLE hIvasRend;
8265 :
8266 : /* Validate function arguments */
8267 5151 : if ( phIvasRend == NULL || *phIvasRend == NULL )
8268 : {
8269 0 : return;
8270 : }
8271 5151 : hIvasRend = *phIvasRend;
8272 :
8273 5151 : if ( hIvasRend->efapOutWrapper.hEfap != NULL )
8274 : {
8275 3815 : efap_free_data( &hIvasRend->efapOutWrapper.hEfap );
8276 : }
8277 :
8278 : /* clear inputs */
8279 25755 : for ( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
8280 : {
8281 20604 : clearInputIsm( &hIvasRend->inputsIsm[i] );
8282 : }
8283 10302 : for ( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
8284 : {
8285 5151 : clearInputMc( &hIvasRend->inputsMc[i] );
8286 : }
8287 10302 : for ( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
8288 : {
8289 5151 : clearInputSba( &hIvasRend->inputsSba[i] );
8290 5151 : hIvasRend->hHrtfs.hHrtfFastConv = NULL;
8291 : }
8292 10302 : for ( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
8293 : {
8294 5151 : clearInputMasa( &hIvasRend->inputsMasa[i] );
8295 : }
8296 :
8297 : /* clear Config. Renderer */
8298 5151 : ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
8299 :
8300 5151 : ivas_limiter_close( &hIvasRend->hLimiter );
8301 :
8302 : /* Split binaural rendering */
8303 5151 : if ( hIvasRend->splitRendWrapper != NULL )
8304 : {
8305 0 : ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
8306 0 : free( hIvasRend->splitRendWrapper );
8307 0 : hIvasRend->splitRendWrapper = NULL;
8308 : }
8309 :
8310 5151 : closeHeadRotation( hIvasRend );
8311 :
8312 5151 : ivas_external_orientation_close( &hIvasRend->hExternalOrientationData );
8313 5151 : ivas_combined_orientation_close( &hIvasRend->hCombinedOrientationData );
8314 :
8315 :
8316 : /* Parametric binauralizer HRTF filters */
8317 5151 : ivas_HRTF_td_binary_close( &( hIvasRend->hHrtfs.hHrtfTD ) );
8318 5151 : ivas_HRTF_CRend_binary_close( &( hIvasRend->hHrtfs.hHrtfCrend ) );
8319 5151 : ivas_HRTF_fastconv_binary_close( &( hIvasRend->hHrtfs.hHrtfFastConv ) );
8320 5151 : ivas_HRTF_parambin_binary_close( &( hIvasRend->hHrtfs.hHrtfParambin ) );
8321 5151 : ivas_HRTF_statistics_binary_close( &( hIvasRend->hHrtfs.hHrtfStatistics ) );
8322 5151 : free( hIvasRend );
8323 5151 : *phIvasRend = NULL;
8324 :
8325 5151 : return;
8326 : }
8327 :
8328 :
8329 : /*-------------------------------------------------------------------*
8330 : * IVAS_REND_openCldfb()
8331 : *
8332 : *
8333 : *-------------------------------------------------------------------*/
8334 :
8335 0 : ivas_error IVAS_REND_openCldfb(
8336 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
8337 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS],
8338 : const int16_t num_in_chs,
8339 : const int16_t num_out_chs,
8340 : const int32_t output_Fs )
8341 : {
8342 : int16_t n;
8343 : ivas_error error;
8344 :
8345 0 : for ( n = 0; n < num_in_chs; n++ )
8346 : {
8347 0 : if ( ( error = openCldfb( &( cldfbAna[n] ), CLDFB_ANALYSIS, output_Fs, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
8348 : {
8349 0 : return error;
8350 : }
8351 : }
8352 0 : for ( ; n < RENDERER_MAX_INPUT_CHANNELS; n++ )
8353 : {
8354 0 : cldfbAna[n] = NULL;
8355 : }
8356 :
8357 0 : for ( n = 0; n < num_out_chs; n++ )
8358 : {
8359 0 : if ( ( error = openCldfb( &( cldfbSyn[n] ), CLDFB_SYNTHESIS, output_Fs, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
8360 : {
8361 0 : return error;
8362 : }
8363 : }
8364 0 : for ( ; n < RENDERER_MAX_OUTPUT_CHANNELS; n++ )
8365 : {
8366 0 : cldfbSyn[n] = NULL;
8367 : }
8368 :
8369 0 : return IVAS_ERR_OK;
8370 : }
8371 :
8372 :
8373 : /*-------------------------------------------------------------------*
8374 : * IVAS_REND_closeCldfb()
8375 : *
8376 : *
8377 : *-------------------------------------------------------------------*/
8378 :
8379 0 : void IVAS_REND_closeCldfb(
8380 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[RENDERER_MAX_INPUT_CHANNELS],
8381 : IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[RENDERER_MAX_OUTPUT_CHANNELS] )
8382 : {
8383 : int16_t n;
8384 :
8385 0 : for ( n = 0; n < RENDERER_MAX_INPUT_CHANNELS; n++ )
8386 : {
8387 0 : if ( cldfbAna[n] != NULL )
8388 : {
8389 0 : deleteCldfb( &( cldfbAna[n] ) );
8390 0 : cldfbAna[n] = NULL;
8391 : }
8392 : }
8393 :
8394 0 : for ( n = 0; n < RENDERER_MAX_OUTPUT_CHANNELS; n++ )
8395 : {
8396 0 : if ( cldfbSyn[n] != NULL )
8397 : {
8398 0 : deleteCldfb( &( cldfbSyn[n] ) );
8399 0 : cldfbSyn[n] = NULL;
8400 : }
8401 : }
8402 :
8403 0 : return;
8404 : }
8405 :
8406 :
8407 : /*-------------------------------------------------------------------*
8408 : * IVAS_REND_cldfbSynthesis_wrapper()
8409 : *
8410 : *
8411 : *-------------------------------------------------------------------*/
8412 :
8413 0 : void IVAS_REND_cldfbAnalysis_ts_wrapper(
8414 : const float *timeIn, /* i : time buffer */
8415 : float realBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : real value buffer */
8416 : float imagBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o : imag value buffer */
8417 : const int16_t samplesToProcess, /* i : samples to process */
8418 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb /* i : filterbank state */
8419 : )
8420 : {
8421 0 : cldfbAnalysis_ts( timeIn, realBuffer, imagBuffer, samplesToProcess, h_cldfb );
8422 :
8423 0 : return;
8424 : }
8425 :
8426 :
8427 : /*-------------------------------------------------------------------*
8428 : * IVAS_REND_cldfbSynthesis_wrapper()
8429 : *
8430 : *
8431 : *-------------------------------------------------------------------*/
8432 :
8433 0 : void IVAS_REND_cldfbSynthesis_wrapper(
8434 : float **realBuffer, /* i : real values */
8435 : float **imagBuffer, /* i : imag values */
8436 : float *timeOut, /* o : output time domain samples */
8437 : const int16_t samplesToProcess, /* i : number of processed samples */
8438 : IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb /* i : filter bank state */
8439 : )
8440 : {
8441 0 : cldfbSynthesis( realBuffer, imagBuffer, timeOut, samplesToProcess, h_cldfb );
8442 :
8443 0 : return;
8444 : }
8445 :
8446 :
8447 : #ifdef DEBUGGING
8448 : /*-------------------------------------------------------------------*
8449 : * IVAS_REND_GetNoCLipping()
8450 : *
8451 : *
8452 : *-------------------------------------------------------------------*/
8453 :
8454 : int32_t IVAS_REND_GetNoCLipping(
8455 : IVAS_REND_CONST_HANDLE hIvasRend )
8456 : {
8457 : return hIvasRend->numClipping;
8458 : }
8459 :
8460 : int32_t IVAS_REND_GetCntFramesLimited(
8461 : IVAS_REND_CONST_HANDLE hIvasRend )
8462 : {
8463 : if ( hIvasRend->hLimiter == NULL )
8464 : {
8465 : return 0;
8466 : }
8467 :
8468 : return hIvasRend->hLimiter->cnt_frames_limited;
8469 : }
8470 : #endif
8471 :
8472 :
8473 : /*---------------------------------------------------------------------*
8474 : * IVAS_REND_GetHrtfTdHandle( )
8475 : *
8476 : *
8477 : *---------------------------------------------------------------------*/
8478 :
8479 0 : ivas_error IVAS_REND_GetHrtfTdHandle(
8480 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8481 : IVAS_DEC_HRTF_TD_HANDLE **hHrtfTD /* o : TD rend. HRTF handle */
8482 : )
8483 : {
8484 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfTD == NULL )
8485 : {
8486 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
8487 : }
8488 :
8489 0 : *hHrtfTD = &hIvasRend->hHrtfs.hHrtfTD;
8490 :
8491 0 : return IVAS_ERR_OK;
8492 : }
8493 :
8494 :
8495 : /*---------------------------------------------------------------------*
8496 : * IVAS_REND_GetHrtfCRendHandle( )
8497 : *
8498 : *
8499 : *---------------------------------------------------------------------*/
8500 :
8501 0 : ivas_error IVAS_REND_GetHrtfCRendHandle(
8502 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8503 : IVAS_DEC_HRTF_CREND_HANDLE **hHrtfCrend /* o : Crend HRTF handle */
8504 : )
8505 : {
8506 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfCrend == NULL )
8507 : {
8508 0 : return IVAS_ERR_WRONG_PARAMS;
8509 : }
8510 :
8511 0 : *hHrtfCrend = &hIvasRend->hHrtfs.hHrtfCrend;
8512 :
8513 0 : return IVAS_ERR_OK;
8514 : }
8515 :
8516 :
8517 : /*---------------------------------------------------------------------*
8518 : * IVAS_REND_GetHrtfFastConvHandle( )
8519 : *
8520 : *
8521 : *---------------------------------------------------------------------*/
8522 :
8523 0 : ivas_error IVAS_REND_GetHrtfFastConvHandle(
8524 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8525 : IVAS_DEC_HRTF_FASTCONV_HANDLE **hHrtfFastConv /* o : FASTCONV HRTF handle */
8526 : )
8527 : {
8528 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfFastConv == NULL )
8529 : {
8530 0 : return IVAS_ERR_WRONG_PARAMS;
8531 : }
8532 :
8533 0 : *hHrtfFastConv = &hIvasRend->hHrtfs.hHrtfFastConv;
8534 :
8535 0 : return IVAS_ERR_OK;
8536 : }
8537 :
8538 :
8539 : /*---------------------------------------------------------------------*
8540 : * IVAS_REND_GetHrtfParamBinHandle( )
8541 : *
8542 : *
8543 : *---------------------------------------------------------------------*/
8544 :
8545 0 : ivas_error IVAS_REND_GetHrtfParamBinHandle(
8546 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8547 : IVAS_DEC_HRTF_PARAMBIN_HANDLE **hHrtfParambin /* o : Parametric binauralizer HRTF handle */
8548 : )
8549 : {
8550 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfParambin == NULL )
8551 : {
8552 0 : return IVAS_ERR_WRONG_PARAMS;
8553 : }
8554 :
8555 0 : *hHrtfParambin = &hIvasRend->hHrtfs.hHrtfParambin;
8556 :
8557 0 : return IVAS_ERR_OK;
8558 : }
8559 :
8560 : /*---------------------------------------------------------------------*
8561 : * IVAS_REND_GetHrtfStatisticsHandle( )
8562 : *
8563 : *
8564 : *---------------------------------------------------------------------*/
8565 :
8566 0 : ivas_error IVAS_REND_GetHrtfStatisticsHandle(
8567 : IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
8568 : IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o : HRTF statistics handle */
8569 : )
8570 : {
8571 0 : if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfStatistics == NULL )
8572 : {
8573 0 : return IVAS_ERR_WRONG_PARAMS;
8574 : }
8575 :
8576 0 : *hHrtfStatistics = &hIvasRend->hHrtfs.hHrtfStatistics;
8577 :
8578 0 : return IVAS_ERR_OK;
8579 : }
8580 :
8581 600 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
8582 : input_masa *inputMasa )
8583 : {
8584 : int16_t nchan_out_woLFE;
8585 : int16_t nchan_transport;
8586 : uint16_t i, j, k;
8587 : float ls_azimuth[MAX_OUTPUT_CHANNELS];
8588 : float ls_elevation[MAX_OUTPUT_CHANNELS];
8589 : int32_t output_Fs;
8590 : ivas_error error;
8591 : DIRAC_REND_HANDLE hDirACRend;
8592 : SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
8593 :
8594 600 : error = IVAS_ERR_OK;
8595 :
8596 600 : hDirACRend = NULL;
8597 600 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
8598 :
8599 600 : hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
8600 :
8601 : /*-----------------------------------------------------------------*
8602 : * prepare library opening
8603 : *-----------------------------------------------------------------*/
8604 :
8605 600 : if ( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
8606 : {
8607 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
8608 : }
8609 :
8610 600 : nchan_transport = inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA2 ? 2 : 1;
8611 :
8612 : /*-----------------------------------------------------------------*
8613 : * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
8614 : *-----------------------------------------------------------------*/
8615 :
8616 600 : ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
8617 :
8618 600 : if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_LS_CUSTOM )
8619 : {
8620 : /* Copy from ivas_ls_custom_setup */
8621 90 : hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
8622 90 : hDirACRend->hOutSetup.ls_azimuth = inputMasa->base.ctx.pCustomLsOut->ls_azimuth;
8623 90 : hDirACRend->hOutSetup.ls_elevation = inputMasa->base.ctx.pCustomLsOut->ls_elevation;
8624 :
8625 90 : hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
8626 90 : hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
8627 :
8628 90 : hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
8629 90 : hDirACRend->hOutSetup.is_planar_setup = (int8_t) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
8630 : }
8631 :
8632 600 : nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
8633 :
8634 600 : if ( hDirACRend->hOutSetup.ls_azimuth != NULL && hDirACRend->hOutSetup.ls_elevation != NULL )
8635 : {
8636 390 : mvr2r( hDirACRend->hOutSetup.ls_azimuth, ls_azimuth, nchan_out_woLFE );
8637 390 : mvr2r( hDirACRend->hOutSetup.ls_elevation, ls_elevation, nchan_out_woLFE );
8638 : }
8639 :
8640 600 : if ( hDirACRend->hOutSetup.ambisonics_order == -1 )
8641 : {
8642 420 : hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
8643 420 : if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_MONO || hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_STEREO )
8644 : {
8645 30 : hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
8646 : }
8647 : }
8648 180 : else if ( hDirACRend->hOutSetup.ambisonics_order >= SBA_FOA_ORDER )
8649 : {
8650 180 : mvr2r( ls_azimuth_4d4, ls_azimuth, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
8651 180 : mvr2r( ls_elevation_4d4, ls_elevation, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
8652 : }
8653 :
8654 : /*-----------------------------------------------------------------*
8655 : * set input parameters
8656 : *-----------------------------------------------------------------*/
8657 :
8658 600 : if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_MONO )
8659 : {
8660 30 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
8661 30 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
8662 30 : nchan_out_woLFE = 1;
8663 : }
8664 570 : else if ( hDirACRend->hOutSetup.is_loudspeaker_setup )
8665 : {
8666 390 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
8667 390 : hDirACRend->panningConf = DIRAC_PANNING_VBAP;
8668 : }
8669 180 : else if ( !hDirACRend->hOutSetup.is_loudspeaker_setup && nchan_transport > 1 )
8670 : {
8671 90 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
8672 90 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
8673 : }
8674 : else
8675 : {
8676 90 : hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
8677 90 : hDirACRend->panningConf = DIRAC_PANNING_HOA3;
8678 : }
8679 :
8680 600 : if ( ( hDirACRend->frequency_axis = (float *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( float ) ) ) == NULL )
8681 : {
8682 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8683 : }
8684 600 : set_f( hDirACRend->frequency_axis, 0.0f, hSpatParamRendCom->num_freq_bands );
8685 :
8686 600 : ivas_dirac_dec_get_frequency_axis( hDirACRend->frequency_axis, output_Fs, hSpatParamRendCom->num_freq_bands );
8687 :
8688 600 : if ( hDirACRend->panningConf == DIRAC_PANNING_HOA3 && nchan_transport == 2 )
8689 : {
8690 120 : if ( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
8691 : {
8692 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8693 : }
8694 120 : ivas_masa_init_stereotype_detection( hDirACRend->masa_stereo_type_detect );
8695 : }
8696 : else
8697 : {
8698 480 : hDirACRend->masa_stereo_type_detect = NULL;
8699 : }
8700 :
8701 600 : hSpatParamRendCom->numIsmDirections = 0;
8702 :
8703 : /*-----------------------------------------------------------------*
8704 : * (re)configure sub-modules
8705 : *-----------------------------------------------------------------*/
8706 :
8707 : /* prototype signal computation */
8708 : /* allocate output setup related arrays */
8709 600 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_LS )
8710 : {
8711 : /* Directional and diffuses components in output LS format */
8712 390 : hDirACRend->num_outputs_diff = nchan_out_woLFE;
8713 390 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
8714 : }
8715 210 : else if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8716 : {
8717 : /* Directional and diffuses components in SHD */
8718 : /* Diffuseness components up to 1st order */
8719 90 : hDirACRend->num_outputs_diff = ( min( hDirACRend->hOutSetup.ambisonics_order, 1 ) + 1 ) * ( min( hDirACRend->hOutSetup.ambisonics_order, 1 ) + 1 );
8720 90 : hDirACRend->num_outputs_dir = ivas_sba_get_nchan( hDirACRend->hOutSetup.ambisonics_order, 0 );
8721 : }
8722 120 : else if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD )
8723 : {
8724 90 : hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
8725 90 : hDirACRend->num_outputs_dir = nchan_out_woLFE;
8726 : }
8727 30 : else if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_MONO )
8728 : {
8729 30 : hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
8730 30 : hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
8731 : }
8732 : else
8733 : {
8734 0 : assert( 0 && "DirAC: not existing synthesis methods!" );
8735 : }
8736 :
8737 600 : if ( ( hDirACRend->proto_index_dir = (int16_t *) malloc( sizeof( int16_t ) * hDirACRend->num_outputs_dir ) ) == NULL )
8738 : {
8739 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8740 : }
8741 :
8742 600 : if ( ( hDirACRend->proto_index_diff = (int16_t *) malloc( sizeof( int16_t ) * hDirACRend->num_outputs_diff ) ) == NULL )
8743 : {
8744 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8745 : }
8746 :
8747 600 : set_s( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
8748 600 : set_s( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
8749 :
8750 600 : hDirACRend->sba_map_tc = sba_map_tc;
8751 :
8752 600 : if ( nchan_transport == 1 )
8753 : {
8754 285 : hDirACRend->num_protos_ambi = 1;
8755 285 : hDirACRend->num_protos_dir = 1;
8756 285 : hDirACRend->num_protos_diff = 1;
8757 : }
8758 315 : else if ( nchan_transport == 2 )
8759 : {
8760 315 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8761 : {
8762 0 : hDirACRend->num_protos_ambi = 2;
8763 0 : hDirACRend->num_protos_diff = 1;
8764 0 : hDirACRend->num_protos_dir = 2;
8765 0 : hDirACRend->proto_index_dir[1] = 1;
8766 : }
8767 315 : else if ( hDirACRend->hOutSetup.output_config == IVAS_AUDIO_CONFIG_MONO )
8768 : {
8769 : /* Following the foa rendering for code compatibility */
8770 30 : hDirACRend->num_protos_ambi = 2;
8771 30 : hDirACRend->num_protos_dir = 2;
8772 30 : hDirACRend->num_protos_diff = 3;
8773 30 : hDirACRend->proto_index_dir[0] = 0;
8774 30 : hDirACRend->proto_index_diff[0] = 0;
8775 : }
8776 : else
8777 : {
8778 285 : hDirACRend->num_protos_ambi = 2;
8779 285 : hDirACRend->num_protos_diff = 3;
8780 :
8781 2715 : for ( k = 0; k < hDirACRend->num_outputs_diff; k++ )
8782 : {
8783 2430 : if ( ls_azimuth[k] > 0.0f )
8784 : {
8785 1140 : hDirACRend->proto_index_diff[k] = 1;
8786 : }
8787 1290 : else if ( ls_azimuth[k] < 0.0f )
8788 : {
8789 1095 : hDirACRend->proto_index_diff[k] = 2;
8790 : }
8791 : else
8792 : {
8793 195 : hDirACRend->proto_index_diff[k] = 0;
8794 : }
8795 : }
8796 :
8797 285 : if ( hDirACRend->hOutSetup.is_loudspeaker_setup )
8798 : {
8799 195 : hDirACRend->num_protos_dir = 3;
8800 195 : mvs2s( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
8801 : }
8802 : else
8803 : {
8804 90 : hDirACRend->num_protos_dir = 2;
8805 90 : hDirACRend->proto_index_dir[1] = 1;
8806 : }
8807 : }
8808 : }
8809 :
8810 : /* direct/diffuse responses */
8811 600 : if ( ( hDirACRend->diffuse_response_function = (float *) malloc( sizeof( float ) * hDirACRend->num_outputs_dir ) ) == NULL )
8812 : {
8813 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8814 : }
8815 :
8816 600 : if ( ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_LS ) || ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD ) || ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_MONO ) )
8817 : {
8818 510 : initDiffuseResponses( hDirACRend->diffuse_response_function, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
8819 510 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
8820 : }
8821 : else
8822 : {
8823 90 : initDiffuseResponses( hDirACRend->diffuse_response_function, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
8824 90 : hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
8825 : }
8826 :
8827 600 : hDirACRend->hoa_encoder = NULL;
8828 600 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD )
8829 : {
8830 90 : if ( ( hDirACRend->hoa_encoder = (float *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( float ) ) ) == NULL )
8831 : {
8832 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8833 : }
8834 :
8835 90 : set_f( hDirACRend->hoa_encoder, 0.0f, nchan_out_woLFE * hDirACRend->num_outputs_diff );
8836 90 : compute_hoa_encoder_mtx( ls_azimuth, ls_elevation, hDirACRend->hoa_encoder, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
8837 : }
8838 :
8839 : /* VBAP */
8840 600 : inputMasa->hMasaExtRend->hVBAPdata = NULL;
8841 :
8842 600 : if ( hDirACRend->panningConf == DIRAC_PANNING_VBAP )
8843 : {
8844 390 : if ( ( error = vbap_init_data( &( inputMasa->hMasaExtRend->hVBAPdata ), ls_azimuth, ls_elevation, nchan_out_woLFE, MASA_FORMAT ) ) != IVAS_ERR_OK )
8845 : {
8846 0 : return error;
8847 : }
8848 : }
8849 :
8850 : /* HOA panning/dec */
8851 600 : hDirACRend->hoa_decoder = NULL;
8852 600 : if ( hDirACRend->panningConf == DIRAC_PANNING_HOA3 )
8853 : {
8854 210 : if ( hDirACRend->hOutSetup.is_loudspeaker_setup )
8855 : {
8856 30 : if ( ( error = ivas_sba_get_hoa_dec_matrix( hDirACRend->hOutSetup, &inputMasa->hMasaExtRend->hoa_dec_mtx, hDirACRend->hOutSetup.ambisonics_order ) ) != IVAS_ERR_OK )
8857 : {
8858 0 : return error;
8859 : }
8860 :
8861 30 : hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
8862 : }
8863 : }
8864 :
8865 : /* decorrelation */
8866 600 : hDirACRend->proto_signal_decorr_on = 1;
8867 600 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_MONO )
8868 : {
8869 30 : hDirACRend->proto_signal_decorr_on = 0;
8870 : }
8871 :
8872 600 : if ( hDirACRend->proto_signal_decorr_on )
8873 : {
8874 570 : if ( ( error = ivas_dirac_dec_decorr_open( &( hDirACRend->h_freq_domain_decorr_ap_params ),
8875 570 : &( hDirACRend->h_freq_domain_decorr_ap_state ),
8876 570 : hSpatParamRendCom->num_freq_bands,
8877 570 : hDirACRend->num_outputs_diff,
8878 570 : hDirACRend->num_protos_diff,
8879 : hDirACRend->synthesisConf,
8880 : hDirACRend->frequency_axis,
8881 : nchan_transport,
8882 : output_Fs ) ) != IVAS_ERR_OK )
8883 : {
8884 0 : return error;
8885 : }
8886 : }
8887 :
8888 : /* output synthesis */
8889 600 : if ( ( ivas_dirac_dec_output_synthesis_open( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ) != IVAS_ERR_OK )
8890 : {
8891 0 : return error;
8892 : }
8893 600 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
8894 :
8895 600 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_PSD_SHD || hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8896 : {
8897 180 : hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
8898 : }
8899 :
8900 : /*-----------------------------------------------------------------*
8901 : * memory allocation
8902 : *-----------------------------------------------------------------*/
8903 :
8904 600 : if ( hDirACRend->synthesisConf == DIRAC_SYNTHESIS_GAIN_SHD )
8905 : {
8906 90 : hDirACRend->proto_frame_f = NULL;
8907 : }
8908 : else
8909 : {
8910 510 : if ( ( hDirACRend->proto_frame_f = (float *) malloc( sizeof( float ) * 2 * hDirACRend->num_protos_diff * hSpatParamRendCom->num_freq_bands ) ) == NULL )
8911 : {
8912 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
8913 : }
8914 : }
8915 :
8916 :
8917 600 : hDirACRend->buffer_energy = NULL;
8918 :
8919 2400 : for ( i = 0; i < DIRAC_NUM_DIMS; i++ )
8920 : {
8921 59400 : for ( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
8922 : {
8923 57600 : hDirACRend->buffer_intensity_real[i][j] = NULL;
8924 : }
8925 : }
8926 :
8927 : /* output synthesis */
8928 600 : ivas_dirac_dec_output_synthesis_init( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
8929 :
8930 : /* Allocate stack memory */
8931 600 : if ( ( error = ivas_dirac_alloc_mem( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ) != IVAS_ERR_OK )
8932 : {
8933 0 : return error;
8934 : }
8935 :
8936 600 : inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
8937 :
8938 600 : return error;
8939 : }
8940 :
8941 600 : static ivas_error ivas_masa_ext_rend_parambin_init(
8942 : input_masa *inputMasa, /* i/o: MASA external renderer structure */
8943 : const RENDER_CONFIG_DATA *hRendCfg, /* i : Renderer configuration data handle */
8944 : HRTFS_STATISTICS_HANDLE hHrtfStatistics /* i : HRTF statistics */
8945 : )
8946 : {
8947 : DIRAC_DEC_BIN_HANDLE hDiracDecBin;
8948 : HRTFS_PARAMBIN_HANDLE *phHrtfParambin;
8949 : int16_t nBins;
8950 : int32_t output_Fs;
8951 : RENDERER_TYPE renderer_type;
8952 : int16_t j, k, bin;
8953 : int16_t num_poses;
8954 : float binCenterFreq, tmpFloat;
8955 : ivas_error error;
8956 : float frequency_axis[CLDFB_NO_CHANNELS_MAX];
8957 : int16_t pos_idx;
8958 : const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics;
8959 :
8960 600 : error = IVAS_ERR_OK;
8961 :
8962 600 : phHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
8963 :
8964 : /* Set common variables and defaults */
8965 600 : output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
8966 600 : nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
8967 600 : renderer_type = inputMasa->hMasaExtRend->renderer_type;
8968 :
8969 600 : num_poses = 1;
8970 600 : if ( inputMasa->base.ctx.pSplitRendWrapper != NULL )
8971 : {
8972 0 : num_poses = inputMasa->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
8973 : }
8974 :
8975 1200 : for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
8976 : {
8977 600 : hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin[pos_idx];
8978 :
8979 : /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
8980 600 : if ( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
8981 : {
8982 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
8983 : }
8984 :
8985 600 : hDiracDecBin->hTdDecorr = NULL;
8986 600 : hDiracDecBin->hReverb = NULL;
8987 600 : hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
8988 600 : hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
8989 600 : hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
8990 600 : hDiracDecBin->useTdDecorr = 0; /* Always use frequency domain decorrelator in external renderer */
8991 :
8992 1800 : for ( j = 0; j < BINAURAL_CHANNELS; j++ )
8993 : {
8994 8400 : for ( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
8995 : {
8996 7200 : set_zero( hDiracDecBin->processMtxRe[j][k], nBins );
8997 7200 : set_zero( hDiracDecBin->processMtxIm[j][k], nBins );
8998 : }
8999 :
9000 3600 : for ( k = 0; k < BINAURAL_CHANNELS; k++ )
9001 : {
9002 2400 : set_zero( hDiracDecBin->processMtxDecRe[j][k], nBins );
9003 2400 : set_zero( hDiracDecBin->processMtxDecIm[j][k], nBins );
9004 : }
9005 1200 : set_zero( hDiracDecBin->ChEnePrev[j], nBins );
9006 1200 : set_zero( hDiracDecBin->ChEneOutPrev[j], nBins );
9007 : }
9008 600 : set_zero( hDiracDecBin->ChCrossRePrev, nBins );
9009 600 : set_zero( hDiracDecBin->ChCrossImPrev, nBins );
9010 600 : set_zero( hDiracDecBin->ChCrossReOutPrev, nBins );
9011 600 : set_zero( hDiracDecBin->ChCrossImOutPrev, nBins );
9012 600 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
9013 :
9014 24600 : for ( bin = 0; bin < nBins; bin++ )
9015 : {
9016 24000 : binCenterFreq = ( (float) bin + 0.5f ) / (float) nBins * ( (float) output_Fs / 2.0f );
9017 : /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
9018 24000 : tmpFloat = max( 0.0f, 1.0f - binCenterFreq / 2700.0f );
9019 24000 : hDiracDecBin->diffuseFieldCoherence[bin] = tmpFloat * sinf( binCenterFreq * EVS_PI / 550.0f ) / ( binCenterFreq * EVS_PI / 550.0f );
9020 : }
9021 :
9022 : /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
9023 600 : set_zero( hDiracDecBin->diffuseFieldCoherenceX, BINAURAL_COHERENCE_DIFFERENCE_BINS );
9024 600 : set_zero( hDiracDecBin->diffuseFieldCoherenceY, BINAURAL_COHERENCE_DIFFERENCE_BINS );
9025 600 : set_zero( hDiracDecBin->diffuseFieldCoherenceZ, BINAURAL_COHERENCE_DIFFERENCE_BINS );
9026 :
9027 600 : if ( renderer_type == RENDERER_BINAURAL_PARAMETRIC ) /* Indication of binaural rendering without room effect */
9028 : {
9029 120 : set_f( hDiracDecBin->earlyPartEneCorrection, 1.0f, CLDFB_NO_CHANNELS_MAX );
9030 120 : hDiracDecBin->hReverb = NULL;
9031 : }
9032 480 : else if ( renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM ) /* Indication of binaural rendering with room effect */
9033 : {
9034 420 : if ( *inputMasa->base.ctx.pOutConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
9035 : {
9036 120 : mvr2r( ( *phHrtfParambin )->parametricEarlyPartEneCorrection, hDiracDecBin->earlyPartEneCorrection, nBins );
9037 120 : pRoomAcoustics = NULL;
9038 : }
9039 : else
9040 : {
9041 300 : set_f( hDiracDecBin->earlyPartEneCorrection, 1.0f, CLDFB_NO_CHANNELS_MAX );
9042 300 : pRoomAcoustics = &( hRendCfg->roomAcoustics );
9043 : }
9044 :
9045 420 : if ( hDiracDecBin->hReverb == NULL && pos_idx == 0 ) /* open reverb only for the main direction */
9046 : {
9047 420 : if ( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb,
9048 : hHrtfStatistics,
9049 : nBins,
9050 : CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
9051 : pRoomAcoustics,
9052 : output_Fs,
9053 420 : ( *phHrtfParambin )->parametricReverberationTimes,
9054 420 : ( *phHrtfParambin )->parametricReverberationEneCorrections,
9055 420 : hDiracDecBin->earlyPartEneCorrection ) ) != IVAS_ERR_OK )
9056 : {
9057 0 : return error;
9058 : }
9059 : }
9060 : }
9061 60 : else if ( renderer_type == RENDERER_STEREO_PARAMETRIC )
9062 : {
9063 60 : set_f( hDiracDecBin->earlyPartEneCorrection, 1.0f, CLDFB_NO_CHANNELS_MAX );
9064 60 : hDiracDecBin->hReverb = NULL;
9065 60 : hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
9066 : }
9067 : else /* Not valid renderer type for this renderer */
9068 : {
9069 0 : assert( false );
9070 : }
9071 :
9072 600 : if ( pos_idx == 0 ) /* open decorrelator only for the main direction */
9073 : {
9074 : /* Always open frequency domain decorrelator */
9075 600 : ivas_dirac_dec_get_frequency_axis( frequency_axis, output_Fs, nBins );
9076 600 : if ( ( error = ivas_dirac_dec_decorr_open( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
9077 600 : &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
9078 : nBins,
9079 : BINAURAL_CHANNELS,
9080 : BINAURAL_CHANNELS,
9081 : DIRAC_SYNTHESIS_PSD_LS,
9082 : frequency_axis,
9083 : BINAURAL_CHANNELS,
9084 : output_Fs ) ) != IVAS_ERR_OK )
9085 : {
9086 0 : return error;
9087 : }
9088 : }
9089 :
9090 : /* External renderer uses constant regularization factor */
9091 600 : hDiracDecBin->reqularizationFactor = 0.4f;
9092 :
9093 600 : hDiracDecBin->phHrtfParambin = phHrtfParambin;
9094 :
9095 600 : inputMasa->hMasaExtRend->hDiracDecBin[pos_idx] = hDiracDecBin;
9096 : }
9097 :
9098 600 : return error;
9099 : }
9100 :
9101 1230 : static ivas_error initMasaExtRenderer(
9102 : input_masa *inputMasa,
9103 : const AUDIO_CONFIG outConfig,
9104 : const RENDER_CONFIG_DATA *hRendCfg,
9105 : hrtf_handles *hrtfs )
9106 : {
9107 : int16_t i;
9108 : ivas_error error;
9109 : MASA_EXT_REND_HANDLE hMasaExtRend;
9110 :
9111 1230 : error = IVAS_ERR_OK;
9112 :
9113 1230 : if ( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
9114 : {
9115 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
9116 : }
9117 :
9118 1230 : inputMasa->hMasaExtRend = hMasaExtRend;
9119 :
9120 : /* Default init */
9121 1230 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
9122 1230 : hMasaExtRend->hDirACRend = NULL;
9123 1230 : hMasaExtRend->hSpatParamRendCom = NULL;
9124 11070 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
9125 : {
9126 9840 : hMasaExtRend->hDiracDecBin[i] = NULL;
9127 : }
9128 1230 : hMasaExtRend->hReverb = NULL;
9129 1230 : hMasaExtRend->hHrtfParambin = &hrtfs->hHrtfParambin;
9130 1230 : hMasaExtRend->hVBAPdata = NULL;
9131 1230 : hMasaExtRend->hoa_dec_mtx = NULL;
9132 :
9133 1230 : if ( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ) != IVAS_ERR_OK )
9134 : {
9135 0 : return error;
9136 : }
9137 :
9138 1230 : if ( outConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
9139 : {
9140 90 : hMasaExtRend->nchan_output = inputMasa->base.ctx.pCustomLsOut->num_spk + inputMasa->base.ctx.pCustomLsOut->num_lfe;
9141 : }
9142 1140 : else if ( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ) != IVAS_ERR_OK )
9143 : {
9144 0 : return error;
9145 : }
9146 :
9147 1230 : switch ( outConfig )
9148 : {
9149 60 : case IVAS_AUDIO_CONFIG_MONO:
9150 60 : if ( inputMasa->base.inConfig == IVAS_AUDIO_CONFIG_MASA2 )
9151 : {
9152 30 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
9153 : }
9154 : else
9155 : {
9156 : /* 1TC MASA to mono does not need rendering. */
9157 30 : hMasaExtRend->renderer_type = RENDERER_DISABLE;
9158 : }
9159 60 : break;
9160 :
9161 60 : case IVAS_AUDIO_CONFIG_STEREO:
9162 60 : hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
9163 60 : break;
9164 :
9165 570 : case IVAS_AUDIO_CONFIG_5_1:
9166 : case IVAS_AUDIO_CONFIG_7_1:
9167 : case IVAS_AUDIO_CONFIG_5_1_2:
9168 : case IVAS_AUDIO_CONFIG_5_1_4:
9169 : case IVAS_AUDIO_CONFIG_7_1_4:
9170 : case IVAS_AUDIO_CONFIG_LS_CUSTOM:
9171 : case IVAS_AUDIO_CONFIG_FOA:
9172 : case IVAS_AUDIO_CONFIG_HOA2:
9173 : case IVAS_AUDIO_CONFIG_HOA3:
9174 570 : hMasaExtRend->renderer_type = RENDERER_DIRAC;
9175 570 : break;
9176 :
9177 120 : case IVAS_AUDIO_CONFIG_BINAURAL:
9178 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
9179 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
9180 120 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
9181 120 : break;
9182 :
9183 420 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
9184 : case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
9185 420 : hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
9186 420 : break;
9187 :
9188 0 : default:
9189 0 : return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
9190 : }
9191 :
9192 1230 : if ( hMasaExtRend->renderer_type != RENDERER_DISABLE )
9193 : {
9194 : int16_t subframe;
9195 :
9196 1200 : 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 )
9197 : {
9198 0 : return error;
9199 : }
9200 :
9201 : /* Simple population of the metadata index map as no adaptation is present */
9202 1200 : set_s( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
9203 6000 : for ( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
9204 : {
9205 4800 : hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
9206 : }
9207 1200 : hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
9208 : }
9209 :
9210 1230 : if ( hMasaExtRend->renderer_type == RENDERER_DIRAC )
9211 : {
9212 600 : if ( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ) != IVAS_ERR_OK )
9213 : {
9214 0 : return error;
9215 : }
9216 : }
9217 :
9218 1230 : if ( hMasaExtRend->renderer_type == RENDERER_BINAURAL_PARAMETRIC || hMasaExtRend->renderer_type == RENDERER_BINAURAL_PARAMETRIC_ROOM || hMasaExtRend->renderer_type == RENDERER_STEREO_PARAMETRIC )
9219 : {
9220 600 : if ( hMasaExtRend->renderer_type != RENDERER_STEREO_PARAMETRIC )
9221 : {
9222 540 : if ( ( error = ivas_dirac_dec_binaural_copy_hrtfs( inputMasa->hMasaExtRend->hHrtfParambin ) ) != IVAS_ERR_OK )
9223 : {
9224 0 : return error;
9225 : }
9226 : }
9227 :
9228 600 : if ( ( error = ivas_masa_ext_rend_parambin_init( inputMasa, hRendCfg, hrtfs->hHrtfStatistics ) ) != IVAS_ERR_OK )
9229 : {
9230 0 : return error;
9231 : }
9232 : }
9233 :
9234 : /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
9235 3690 : for ( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
9236 : {
9237 2460 : hMasaExtRend->cldfbAnaRend[i] = NULL;
9238 : }
9239 :
9240 20910 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
9241 : {
9242 19680 : hMasaExtRend->cldfbSynRend[i] = NULL;
9243 : }
9244 :
9245 1230 : if ( hMasaExtRend->renderer_type != RENDERER_DISABLE )
9246 : {
9247 3015 : for ( i = 0; i < hMasaExtRend->nchan_input; i++ )
9248 : {
9249 1815 : if ( ( error = openCldfb( &( hMasaExtRend->cldfbAnaRend[i] ), CLDFB_ANALYSIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
9250 : {
9251 0 : return error;
9252 : }
9253 : }
9254 :
9255 7890 : for ( i = 0; i < hMasaExtRend->nchan_output; i++ )
9256 : {
9257 6690 : if ( ( error = openCldfb( &( hMasaExtRend->cldfbSynRend[i] ), CLDFB_SYNTHESIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS ) ) != IVAS_ERR_OK )
9258 : {
9259 0 : return error;
9260 : }
9261 : }
9262 : }
9263 :
9264 1230 : inputMasa->hMasaExtRend = hMasaExtRend;
9265 :
9266 1230 : return IVAS_ERR_OK;
9267 : }
9268 :
9269 :
9270 5151 : static void freeMasaExtRenderer(
9271 : MASA_EXT_REND_HANDLE *hMasaExtRendOut )
9272 : {
9273 : MASA_EXT_REND_HANDLE hMasaExtRend;
9274 : int16_t i;
9275 :
9276 5151 : if ( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
9277 : {
9278 3921 : return;
9279 : }
9280 :
9281 1230 : hMasaExtRend = *hMasaExtRendOut;
9282 :
9283 1230 : if ( hMasaExtRend->hDirACRend != NULL )
9284 : {
9285 600 : ivas_dirac_rend_close( &hMasaExtRend->hDirACRend );
9286 : }
9287 :
9288 1230 : if ( hMasaExtRend->hSpatParamRendCom != NULL )
9289 : {
9290 1200 : ivas_spat_hSpatParamRendCom_close( &hMasaExtRend->hSpatParamRendCom );
9291 : }
9292 :
9293 11070 : for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
9294 : {
9295 9840 : if ( hMasaExtRend->hDiracDecBin[i] != NULL )
9296 : {
9297 600 : ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin[i] );
9298 : }
9299 : }
9300 :
9301 :
9302 1230 : if ( hMasaExtRend->hReverb != NULL )
9303 : {
9304 0 : ivas_binaural_reverb_close( &hMasaExtRend->hReverb );
9305 : }
9306 :
9307 1230 : if ( hMasaExtRend->hHrtfParambin != NULL )
9308 : {
9309 1230 : ivas_HRTF_parambin_binary_close( hMasaExtRend->hHrtfParambin );
9310 : }
9311 :
9312 1230 : if ( hMasaExtRend->hVBAPdata != NULL )
9313 : {
9314 390 : vbap_free_data( &hMasaExtRend->hVBAPdata );
9315 : }
9316 :
9317 1230 : if ( hMasaExtRend->hoa_dec_mtx != NULL )
9318 : {
9319 30 : free( hMasaExtRend->hoa_dec_mtx );
9320 : }
9321 :
9322 3690 : for ( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
9323 : {
9324 2460 : if ( hMasaExtRend->cldfbAnaRend[i] != NULL )
9325 : {
9326 1815 : deleteCldfb( &hMasaExtRend->cldfbAnaRend[i] );
9327 : }
9328 : }
9329 :
9330 20910 : for ( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
9331 : {
9332 19680 : if ( hMasaExtRend->cldfbSynRend[i] != NULL )
9333 : {
9334 6690 : deleteCldfb( &hMasaExtRend->cldfbSynRend[i] );
9335 : }
9336 : }
9337 :
9338 1230 : free( hMasaExtRend );
9339 1230 : *hMasaExtRendOut = NULL;
9340 :
9341 1230 : return;
9342 : }
9343 :
9344 :
9345 5151 : static ivas_error printConfigInfo_rend(
9346 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
9347 : )
9348 : {
9349 : ivas_error error;
9350 : char config_str[200];
9351 :
9352 : /*-----------------------------------------------------------------*
9353 : * Print output audio configuration
9354 : *-----------------------------------------------------------------*/
9355 :
9356 5151 : if ( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ) != IVAS_ERR_OK )
9357 : {
9358 0 : return error;
9359 : }
9360 :
9361 5151 : fprintf( stdout, "Output configuration: %s\n", config_str );
9362 :
9363 : /*-----------------------------------------------------------------*
9364 : * Print renderer configurations
9365 : *-----------------------------------------------------------------*/
9366 :
9367 5151 : fprintf( stdout, "Output sampling rate: %d Hz\n", hIvasRend->sampleRateOut );
9368 :
9369 5151 : if ( hIvasRend->headRotData.headRotEnabled == 1 )
9370 : {
9371 876 : fprintf( stdout, "Head-tracking: ON\n" );
9372 : }
9373 :
9374 5151 : if ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL ||
9375 4619 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ||
9376 4087 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ||
9377 2907 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ||
9378 2907 : hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
9379 : {
9380 2244 : fprintf( stdout, "Render framesize: %dms\n", hIvasRend->num_subframes * BINAURAL_RENDERING_FRAME_SIZE_MS );
9381 : }
9382 :
9383 5151 : return IVAS_ERR_OK;
9384 : }
9385 :
9386 :
9387 : /*---------------------------------------------------------------------*
9388 : * IVAS_REND_PrintInputConfig()
9389 : *
9390 : *
9391 : *---------------------------------------------------------------------*/
9392 :
9393 7893 : void IVAS_REND_PrintInputConfig(
9394 : const IVAS_AUDIO_CONFIG inputConfig /* i : input audio configuration */
9395 : )
9396 : {
9397 : char config_str[200];
9398 :
9399 7893 : get_channel_config( inputConfig, &config_str[0] );
9400 7893 : fprintf( stdout, "Input configuration: %s\n", config_str );
9401 :
9402 7893 : return;
9403 : }
9404 :
9405 :
9406 : /*---------------------------------------------------------------------*
9407 : * IVAS_REND_PrintConfig()
9408 : *
9409 : *
9410 : *---------------------------------------------------------------------*/
9411 :
9412 5151 : ivas_error IVAS_REND_PrintConfig(
9413 : IVAS_REND_HANDLE hIvasRend /* i : IVAS renderer handle */
9414 : )
9415 : {
9416 5151 : if ( hIvasRend == NULL )
9417 : {
9418 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
9419 : }
9420 :
9421 5151 : return printConfigInfo_rend( hIvasRend );
9422 : }
9423 :
9424 :
9425 : /*---------------------------------------------------------------------*
9426 : * IVAS_REND_PrintDisclaimer()
9427 : *
9428 : * Print IVAS disclaimer to console
9429 : *---------------------------------------------------------------------*/
9430 :
9431 5151 : void IVAS_REND_PrintDisclaimer( void )
9432 : {
9433 5151 : print_disclaimer( stderr );
9434 :
9435 5151 : return;
9436 : }
|