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