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