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