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