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