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