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