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 :
34 : #include "options.h"
35 : #include "lib_isar_post_rend.h"
36 : #include "isar_prot.h"
37 : #include "prot.h"
38 : #include "ivas_prot.h"
39 :
40 :
41 : #include "ivas_prot_rend.h"
42 : #include <assert.h>
43 : #include <math.h>
44 : #include "wmc_auto.h"
45 :
46 :
47 : /*-------------------------------------------------------------------*
48 : * Local constants
49 : *-------------------------------------------------------------------*/
50 :
51 : /*-------------------------------------------------------------------*
52 : * Local types
53 : *-------------------------------------------------------------------*/
54 :
55 : /* Lightweight helper struct that gathers all information required for rendering
56 : * any config to any other config. Used to simplify signatures of rendering functions.
57 : *
58 : * This struct should store ONLY CONST POINTERS to data existing elsewhere.
59 : * Storing pointers instead of data itself ensures that no additional updates
60 : * are required when any of these are changed in the renderer. Making the pointers
61 : * const ensures that this data is only read, but not modified by the rendering functions. */
62 : typedef struct
63 : {
64 : const int32_t *pOutSampleRate;
65 : const AUDIO_CONFIG *pOutConfig;
66 : const ISAR_POST_REND_HeadRotData *pHeadRotData;
67 : const int16_t *pSplitRendBFI;
68 : const ISAR_SPLIT_REND_CONFIG_DATA *pSplitRenderConfig;
69 : } rendering_context_isar;
70 :
71 : /* Common base for input structs */
72 : typedef struct
73 : {
74 : AUDIO_CONFIG inConfig;
75 : ISAR_POST_REND_InputId id;
76 : IVAS_REND_AudioBuffer inputBuffer;
77 : float gain; /* Linear, not in dB */
78 : rendering_context_isar ctx;
79 : int32_t numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */
80 : } input_base_isar;
81 :
82 : typedef struct
83 : {
84 : input_base_isar base;
85 : ISAR_SPLIT_POST_REND_WRAPPER splitPostRendWrapper;
86 : float *bufferData;
87 : int16_t numCachedSamples; /* Number of decoded samples in bufferData that have not yet been played out */
88 : ISAR_POST_REND_BitstreamBuffer *hBits;
89 : } input_split_post_rend;
90 :
91 : struct ISAR_POST_REND
92 : {
93 : int32_t sampleRateOut;
94 :
95 : IVAS_LIMITER_HANDLE hLimiter;
96 : #ifdef DEBUGGING
97 : int32_t numClipping; /* Counter of clipped output samples */
98 : #endif
99 :
100 : input_split_post_rend inputsSplitPost[RENDERER_MAX_BIN_INPUTS];
101 :
102 : AUDIO_CONFIG inputConfig;
103 : AUDIO_CONFIG outputConfig;
104 :
105 : ISAR_POST_REND_HeadRotData headRotData;
106 : int16_t splitRendBFI;
107 :
108 : int8_t rendererConfigEnabled;
109 : ISAR_SPLIT_REND_CONFIG_DATA splitRenderConfig;
110 :
111 : int16_t num_subframes;
112 : };
113 :
114 :
115 : /*-------------------------------------------------------------------*
116 : * ISAR_POST_REND_AudioConfigType()
117 : *
118 : *
119 : *-------------------------------------------------------------------*/
120 :
121 : /*! r: ISAR audio type */
122 3563754 : ISAR_POST_REND_AudioConfigType isar_getAudioConfigType(
123 : const AUDIO_CONFIG config /* i : audio configuration */
124 : )
125 : {
126 : ISAR_POST_REND_AudioConfigType type;
127 :
128 3563754 : switch ( config )
129 : {
130 3563754 : case IVAS_AUDIO_CONFIG_BINAURAL:
131 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
132 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
133 3563754 : type = ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL;
134 3563754 : break;
135 0 : default:
136 0 : type = ISAR_POST_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
137 0 : break;
138 : }
139 :
140 3563754 : return type;
141 : }
142 :
143 :
144 : /*-------------------------------------------------------------------*
145 : * Local functions
146 : *-------------------------------------------------------------------*/
147 :
148 3584 : static ivas_error allocateInputBaseBufferData(
149 : float **data,
150 : const int16_t data_size )
151 : {
152 3584 : *data = (float *) malloc( data_size * sizeof( float ) );
153 3584 : if ( *data == NULL )
154 : {
155 0 : return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for input base buffer data" );
156 : }
157 :
158 3584 : return IVAS_ERR_OK;
159 : }
160 :
161 :
162 3584 : static void freeInputBaseBufferData(
163 : float **data )
164 : {
165 3584 : if ( *data != NULL )
166 : {
167 3584 : free( *data );
168 3584 : *data = NULL;
169 : }
170 :
171 3584 : return;
172 : }
173 :
174 :
175 13622 : static IVAS_QUATERNION quaternionInit(
176 : void )
177 : {
178 : IVAS_QUATERNION q;
179 13622 : q.w = 1.0f;
180 13622 : q.x = q.y = q.z = 0.0f;
181 13622 : return q;
182 : }
183 :
184 678596 : static void convertBitsBufferToInternalBitsBuff(
185 : const ISAR_POST_REND_BitstreamBuffer outBits,
186 : ISAR_SPLIT_REND_BITS_HANDLE hBits )
187 : {
188 678596 : hBits->bits_buf = outBits.bits;
189 678596 : hBits->bits_read = outBits.config.bitsRead;
190 678596 : hBits->bits_written = outBits.config.bitsWritten;
191 678596 : hBits->buf_len = outBits.config.bufLenInBytes;
192 678596 : hBits->codec = outBits.config.codec;
193 678596 : hBits->pose_correction = outBits.config.poseCorrection;
194 678596 : hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
195 678596 : hBits->isar_frame_size_ms = outBits.config.isar_frame_size_ms;
196 678596 : hBits->lc3plus_highres = outBits.config.lc3plusHighRes;
197 :
198 678596 : return;
199 : }
200 :
201 :
202 678596 : static void convertInternalBitsBuffToBitsBuffer(
203 : ISAR_POST_REND_BitstreamBuffer *hOutBits,
204 : const ISAR_SPLIT_REND_BITS_DATA bits )
205 : {
206 678596 : hOutBits->bits = bits.bits_buf;
207 678596 : hOutBits->config.bitsRead = bits.bits_read;
208 678596 : hOutBits->config.bitsWritten = bits.bits_written;
209 678596 : hOutBits->config.bufLenInBytes = bits.buf_len;
210 678596 : hOutBits->config.codec = bits.codec;
211 678596 : hOutBits->config.poseCorrection = bits.pose_correction;
212 678596 : hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
213 678596 : hOutBits->config.isar_frame_size_ms = bits.isar_frame_size_ms;
214 678596 : hOutBits->config.lc3plusHighRes = bits.lc3plus_highres;
215 :
216 678596 : return;
217 : }
218 :
219 :
220 10326 : static void copyBufferTo2dArray(
221 : const IVAS_REND_AudioBuffer buffer,
222 : float array[][L_FRAME48k] )
223 : {
224 : uint32_t smplIdx;
225 : uint32_t chnlIdx;
226 : const float *readPtr;
227 :
228 10326 : assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
229 10326 : readPtr = buffer.data;
230 :
231 30978 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
232 : {
233 19846572 : for ( smplIdx = 0; smplIdx < (uint32_t) buffer.config.numSamplesPerChannel; ++smplIdx )
234 : {
235 19825920 : array[chnlIdx][smplIdx] = *readPtr++;
236 : }
237 : }
238 :
239 10326 : return;
240 : }
241 :
242 :
243 678596 : static void accumulate2dArrayToBuffer(
244 : float array[][L_FRAME48k],
245 : const IVAS_REND_AudioBuffer *buffer )
246 : {
247 : int16_t smplIdx, chnlIdx;
248 : float *writePtr;
249 :
250 678596 : writePtr = buffer->data;
251 2035788 : for ( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
252 : {
253 1093059592 : for ( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
254 : {
255 1091702400 : *writePtr++ += array[chnlIdx][smplIdx];
256 : }
257 : }
258 :
259 678596 : return;
260 : }
261 :
262 : #ifndef DISABLE_LIMITER
263 :
264 : /*-------------------------------------------------------------------*
265 : * limitRendererOutput()
266 : *
267 : * In-place saturation control for multichannel buffers with adaptive release time
268 : *-------------------------------------------------------------------*/
269 :
270 : /*! r: number of clipped output samples */
271 678596 : static int32_t limitRendererOutput(
272 : IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle */
273 : float *output, /* i/o: I/O buffer */
274 : const int16_t output_frame, /* i : number of samples per channel in the buffer */
275 : const float threshold /* i : signal amplitude above which limiting starts to be applied */
276 : )
277 : {
278 : int16_t i;
279 : float **channels;
280 : int16_t num_channels;
281 678596 : int32_t numClipping = 0;
282 :
283 : /* return early if given bad parameters */
284 678596 : if ( hLimiter == NULL || output == NULL || output_frame <= 0 )
285 : {
286 0 : return 0;
287 : }
288 :
289 678596 : channels = hLimiter->channel_ptrs;
290 678596 : num_channels = hLimiter->num_channels;
291 :
292 2035788 : for ( i = 0; i < num_channels; ++i )
293 : {
294 1357192 : channels[i] = output + i * output_frame;
295 : }
296 :
297 678596 : limiter_process( hLimiter, output_frame, threshold, 0, NULL );
298 :
299 : /* Apply clipping to buffer in case the limiter let through some samples > 1.0f */
300 1092380996 : for ( i = 0; i < output_frame * num_channels; ++i )
301 : {
302 : #ifdef DEBUGGING
303 : if ( output[i] < INT16_MIN || output[i] > INT16_MAX )
304 : {
305 : ++numClipping;
306 : }
307 : #endif
308 :
309 1091702400 : output[i] = min( max( INT16_MIN, output[i] ), INT16_MAX );
310 : }
311 :
312 678596 : return numClipping;
313 : }
314 :
315 : #endif
316 :
317 : /*-------------------------------------------------------------------*
318 : * validateOutputSampleRate()
319 : *
320 : *
321 : *-------------------------------------------------------------------*/
322 :
323 3584 : static ivas_error validateOutputSampleRate(
324 : const int32_t sampleRate,
325 : const AUDIO_CONFIG outConfig )
326 : {
327 3584 : if ( ( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED || outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) && sampleRate != 48000 )
328 : {
329 0 : return IVAS_ERROR( IVAS_ERR_INVALID_SAMPLING_RATE, "Error: Only 48kHz output sampling rate is supported for split rendering." );
330 : }
331 : else
332 : {
333 : /* Otherwise rendering to binaural, support the same set as IVAS decoder */
334 3584 : switch ( sampleRate )
335 : {
336 3584 : case 8000:
337 : case 16000:
338 : case 32000:
339 : case 48000:
340 3584 : return IVAS_ERR_OK;
341 : }
342 :
343 0 : return IVAS_ERR_INVALID_SAMPLING_RATE;
344 : }
345 : }
346 :
347 :
348 : /*-------------------------------------------------------------------*
349 : * Local functions
350 : *-------------------------------------------------------------------*/
351 :
352 3584 : static ivas_error initLimiter(
353 : IVAS_LIMITER_HANDLE *phLimiter,
354 : const int16_t numChannels,
355 : const int32_t sampleRate )
356 : {
357 : ivas_error error;
358 :
359 : /* If re-initializing with unchanged values, return early */
360 3584 : if ( *phLimiter != NULL && ( *phLimiter )->num_channels == numChannels && ( *phLimiter )->sampling_rate == sampleRate )
361 : {
362 0 : return IVAS_ERR_OK;
363 : }
364 :
365 : /* Support re-init: close if already allocated */
366 3584 : if ( *phLimiter != NULL )
367 : {
368 0 : ivas_limiter_close( phLimiter );
369 : }
370 :
371 3584 : if ( ( error = ivas_limiter_open( phLimiter, numChannels, sampleRate ) ) != IVAS_ERR_OK )
372 : {
373 0 : return error;
374 : }
375 :
376 3584 : return IVAS_ERR_OK;
377 : }
378 :
379 :
380 3584 : static ivas_error initHeadRotation(
381 : ISAR_POST_REND_HANDLE hIvasRend )
382 : {
383 : int16_t i, crossfade_len;
384 : float tmp;
385 :
386 : /* Head rotation is enabled by default */
387 3584 : hIvasRend->headRotData.headRotEnabled = 1;
388 :
389 : /* Initialize 5ms crossfade */
390 3584 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
391 3584 : tmp = 1.f / ( crossfade_len - 1 );
392 863744 : for ( i = 0; i < crossfade_len; i++ )
393 : {
394 860160 : hIvasRend->headRotData.crossfade[i] = i * tmp;
395 : }
396 :
397 : /* Initialize with unit quaternions */
398 17206 : for ( i = 0; i < hIvasRend->num_subframes; ++i )
399 : {
400 13622 : hIvasRend->headRotData.headPositions[i] = quaternionInit();
401 : }
402 :
403 3584 : hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
404 :
405 3584 : return IVAS_ERR_OK;
406 : }
407 :
408 :
409 10752 : static void initRendInputBase(
410 : input_base_isar *inputBase,
411 : const AUDIO_CONFIG inConfig,
412 : const IVAS_REND_InputId id,
413 : const rendering_context_isar rendCtx,
414 : float *dataBuf,
415 : const int16_t dataBufSize )
416 : {
417 10752 : inputBase->inConfig = inConfig;
418 10752 : inputBase->id = id;
419 10752 : inputBase->gain = 1.0f;
420 10752 : inputBase->ctx = rendCtx;
421 10752 : inputBase->numNewSamplesPerChannel = 0;
422 :
423 10752 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
424 10752 : inputBase->inputBuffer.config.numChannels = 0;
425 10752 : inputBase->inputBuffer.data = dataBuf;
426 10752 : if ( inputBase->inputBuffer.data != NULL )
427 : {
428 3584 : set_zero( inputBase->inputBuffer.data, dataBufSize );
429 : }
430 :
431 10752 : return;
432 : }
433 :
434 :
435 3584 : static rendering_context_isar getRendCtx(
436 : ISAR_POST_REND_HANDLE hIvasRend )
437 : {
438 : rendering_context_isar ctx;
439 :
440 : /* Note: when refactoring this, always take the ADDRESS of a member of the
441 : * renderer struct, so that the context stores a POINTER to the member, even
442 : * if the member is a pointer or handle itself. */
443 3584 : ctx.pOutConfig = &hIvasRend->outputConfig;
444 3584 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
445 3584 : ctx.pHeadRotData = &hIvasRend->headRotData;
446 3584 : ctx.pSplitRendBFI = &hIvasRend->splitRendBFI;
447 3584 : ctx.pSplitRenderConfig = &hIvasRend->splitRenderConfig;
448 :
449 3584 : return ctx;
450 : }
451 :
452 :
453 1203636 : static ivas_error getRendInputNumChannels(
454 : const void *rendInput,
455 : int16_t *numInChannels )
456 : {
457 : /* Using a void pointer for this function to be reusable for any input type (input_ism, input_mc, input_sba).
458 : Assumptions: - input_base_isar is always the first member in the input struct */
459 : (void) rendInput;
460 :
461 1203636 : *numInChannels = 2;
462 :
463 1203636 : return IVAS_ERR_OK;
464 : }
465 :
466 :
467 3584 : static ivas_error updateSplitPostRendPanGains(
468 : input_split_post_rend *inputSplitPostRend,
469 : const AUDIO_CONFIG outConfig,
470 : ISAR_SPLIT_REND_CONFIG_DATA *hRendCfg )
471 : {
472 : ivas_error error;
473 : rendering_context_isar rendCtx;
474 : LC3PLUS_CONFIG config;
475 : int16_t iNumBlocksPerFrame, iNumLCLDIterationsPerFrame;
476 :
477 : (void) outConfig;
478 :
479 3584 : rendCtx = inputSplitPostRend->base.ctx;
480 3584 : isar_renderSplitGetMultiBinPoseData( hRendCfg, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, rendCtx.pHeadRotData->sr_pose_pred_axis );
481 :
482 3584 : config.high_res_mode_enabled = ( hRendCfg->lc3plus_highres != 0 );
483 3584 : config.lc3plus_frame_duration_us = hRendCfg->codec_frame_size_ms * 1000;
484 3584 : config.isar_frame_duration_us = hRendCfg->isar_frame_size_ms * 1000;
485 :
486 3584 : if ( hRendCfg->codec_frame_size_ms > 0 )
487 : {
488 3584 : iNumLCLDIterationsPerFrame = (int16_t) config.isar_frame_duration_us / ( 1000 * hRendCfg->codec_frame_size_ms );
489 3584 : iNumLCLDIterationsPerFrame = max( 1, iNumLCLDIterationsPerFrame );
490 3584 : iNumBlocksPerFrame = CLDFB_NO_COL_MAX * hRendCfg->codec_frame_size_ms / 20;
491 : }
492 : else
493 : {
494 0 : iNumLCLDIterationsPerFrame = 1;
495 0 : iNumBlocksPerFrame = CLDFB_NO_COL_MAX;
496 : }
497 :
498 3584 : config.channels = BINAURAL_CHANNELS;
499 3584 : config.samplerate = *inputSplitPostRend->base.ctx.pOutSampleRate;
500 :
501 3584 : if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LCLD )
502 : {
503 2098 : if ( ( error = isar_splitBinLCLDDecOpen( &inputSplitPostRend->splitPostRendWrapper.hSplitBinLCLDDec, *inputSplitPostRend->base.ctx.pOutSampleRate, BINAURAL_CHANNELS, iNumBlocksPerFrame, iNumLCLDIterationsPerFrame ) ) != IVAS_ERR_OK )
504 : {
505 0 : return error;
506 : }
507 : }
508 1486 : else if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS )
509 : {
510 1442 : if ( ( error = ISAR_LC3PLUS_DEC_Open( config, &inputSplitPostRend->splitPostRendWrapper.hLc3plusDec ) ) != IVAS_ERR_OK )
511 : {
512 0 : return error;
513 : }
514 : }
515 :
516 3584 : if ( ( error = isar_splitBinPostRendOpen( &inputSplitPostRend->splitPostRendWrapper.hBinHrSplitPostRend, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
517 : {
518 0 : return error;
519 : }
520 :
521 3584 : return IVAS_ERR_OK;
522 : }
523 :
524 :
525 3584 : static ivas_error setRendInputActiveSplitPostRend(
526 : void *input,
527 : const AUDIO_CONFIG inConfig,
528 : const IVAS_REND_InputId id,
529 : ISAR_SPLIT_REND_CONFIG_DATA *hRendCfg )
530 : {
531 : ivas_error error;
532 : rendering_context_isar rendCtx;
533 : AUDIO_CONFIG outConfig;
534 : input_split_post_rend *inputSplitPostRend;
535 :
536 3584 : inputSplitPostRend = (input_split_post_rend *) input;
537 3584 : rendCtx = inputSplitPostRend->base.ctx;
538 3584 : outConfig = *rendCtx.pOutConfig;
539 :
540 3584 : if ( ( error = allocateInputBaseBufferData( &inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
541 : {
542 0 : return error;
543 : }
544 :
545 3584 : initRendInputBase( &inputSplitPostRend->base, inConfig, id, rendCtx, inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH );
546 3584 : inputSplitPostRend->numCachedSamples = 0;
547 :
548 3584 : if ( ( error = updateSplitPostRendPanGains( inputSplitPostRend, outConfig, hRendCfg ) ) != IVAS_ERR_OK )
549 : {
550 0 : return error;
551 : }
552 :
553 3584 : return IVAS_ERR_OK;
554 : }
555 :
556 :
557 3584 : static void clearInputSplitRend(
558 : input_split_post_rend *inputSplitRend )
559 : {
560 : rendering_context_isar rendCtx;
561 :
562 3584 : rendCtx = inputSplitRend->base.ctx;
563 :
564 3584 : freeInputBaseBufferData( &inputSplitRend->bufferData );
565 :
566 3584 : initRendInputBase( &inputSplitRend->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
567 :
568 3584 : if ( inputSplitRend->splitPostRendWrapper.hBinHrSplitPostRend != NULL )
569 : {
570 3584 : isar_splitBinPostRendClose( &inputSplitRend->splitPostRendWrapper.hBinHrSplitPostRend );
571 : }
572 :
573 3584 : if ( inputSplitRend->splitPostRendWrapper.hSplitBinLCLDDec != NULL )
574 : {
575 2098 : isar_splitBinLCLDDecClose( &inputSplitRend->splitPostRendWrapper.hSplitBinLCLDDec );
576 : }
577 :
578 3584 : if ( inputSplitRend->splitPostRendWrapper.hLc3plusDec != NULL )
579 : {
580 1442 : ISAR_LC3PLUS_DEC_Close( &inputSplitRend->splitPostRendWrapper.hLc3plusDec );
581 : }
582 :
583 3584 : return;
584 : }
585 :
586 :
587 : /*-------------------------------------------------------------------------
588 : * ISAR_POST_REND_open()
589 : *
590 : *
591 : *------------------------------------------------------------------------*/
592 :
593 3584 : ivas_error ISAR_POST_REND_open(
594 : ISAR_POST_REND_HANDLE *phIvasRend, /* i/o: Pointer to renderer handle */
595 : const int32_t outputSampleRate, /* i : output sampling rate */
596 : const IVAS_AUDIO_CONFIG outConfig, /* i : output audio config */
597 : const bool asHrtfBinary, /* i : load hrtf binary file */
598 : const int16_t nonDiegeticPan, /* i : non-diegetic object flag */
599 : const float nonDiegeticPanGain, /* i : non-diegetic panning gain */
600 : const int16_t num_subframes /* i : number of subframes */
601 : )
602 : {
603 : int16_t i;
604 : ISAR_POST_REND_HANDLE hIvasRend;
605 : ivas_error error;
606 : int16_t numOutChannels;
607 :
608 : (void) asHrtfBinary;
609 : (void) nonDiegeticPan;
610 : (void) nonDiegeticPanGain;
611 :
612 : /* Validate function arguments */
613 3584 : if ( phIvasRend == NULL )
614 : {
615 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
616 : }
617 :
618 3584 : if ( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ) != IVAS_ERR_OK )
619 : {
620 0 : return error;
621 : }
622 :
623 3584 : *phIvasRend = (ISAR_POST_REND_HANDLE) malloc( sizeof( struct ISAR_POST_REND ) );
624 3584 : if ( *phIvasRend == NULL )
625 : {
626 0 : return IVAS_ERR_FAILED_ALLOC;
627 : }
628 :
629 3584 : hIvasRend = *phIvasRend;
630 3584 : hIvasRend->sampleRateOut = outputSampleRate;
631 3584 : hIvasRend->outputConfig = outConfig;
632 3584 : hIvasRend->hLimiter = NULL;
633 3584 : hIvasRend->num_subframes = 1;
634 : #ifdef DEBUGGING
635 : hIvasRend->numClipping = 0;
636 : #endif
637 3584 : hIvasRend->num_subframes = num_subframes;
638 :
639 : /* Initialize limiter */
640 3584 : if ( ( error = ISAR_POST_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
641 : {
642 0 : return error;
643 : }
644 :
645 3584 : if ( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ) != IVAS_ERR_OK )
646 : {
647 0 : return error;
648 : }
649 :
650 : /* Initialize headrotation data */
651 3584 : if ( ( error = initHeadRotation( hIvasRend ) ) != IVAS_ERR_OK )
652 : {
653 0 : return error;
654 : }
655 :
656 : /* Initialize inputs */
657 :
658 7168 : for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; ++i )
659 : {
660 3584 : initRendInputBase( &hIvasRend->inputsSplitPost[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
661 :
662 3584 : isar_init_split_post_rend_handles( &hIvasRend->inputsSplitPost[i].splitPostRendWrapper );
663 :
664 3584 : hIvasRend->splitRendBFI = 0;
665 3584 : hIvasRend->inputsSplitPost[i].bufferData = NULL;
666 : }
667 :
668 3584 : return IVAS_ERR_OK;
669 : }
670 :
671 :
672 : /*-------------------------------------------------------------------*
673 : * ISAR_POST_REND_NumOutChannels()
674 : *
675 : *
676 : *-------------------------------------------------------------------*/
677 :
678 682180 : ivas_error ISAR_POST_REND_NumOutChannels(
679 : ISAR_POST_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
680 : int16_t *numOutChannels /* o : number of output channels */
681 : )
682 : {
683 : /* Validate function arguments */
684 682180 : if ( hIvasRend == NULL || numOutChannels == NULL )
685 : {
686 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
687 : }
688 :
689 682180 : *numOutChannels = 2;
690 :
691 682180 : return IVAS_ERR_OK;
692 : }
693 :
694 :
695 3584 : static IVAS_REND_InputId makeInputId(
696 : AUDIO_CONFIG config,
697 : const int32_t inputIndex )
698 : {
699 : /* Put config type in second byte (from LSB), put index + 1 in first byte
700 : *
701 : * Index is incremented here so that a valid ID can never be 0. */
702 3584 : return (IVAS_REND_InputId) ( ( ( (uint32_t) isar_getAudioConfigType( config ) ) << 8 ) | ( inputIndex + 1 ) );
703 : }
704 :
705 :
706 1200052 : static ivas_error getInputById(
707 : ISAR_POST_REND_HANDLE hIvasRend,
708 : const IVAS_REND_InputId inputId,
709 : void **ppInput )
710 : {
711 : int32_t inputIndex;
712 : IVAS_REND_AudioConfigType configType;
713 : input_base_isar *pInputBase;
714 :
715 : /* Reverse makeInputId() */
716 1200052 : inputIndex = ( inputId & 0xFF ) - 1;
717 1200052 : configType = ( inputId & 0xFF00 ) >> 8;
718 :
719 : /* Validate values derived from input ID */
720 1200052 : if ( inputIndex < 0 )
721 : {
722 0 : return IVAS_ERR_INVALID_INPUT_ID;
723 : }
724 1200052 : switch ( configType )
725 : {
726 1200052 : case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
727 1200052 : if ( inputIndex > RENDERER_MAX_BIN_INPUTS )
728 : {
729 0 : return IVAS_ERR_INVALID_INPUT_ID;
730 : }
731 1200052 : pInputBase = &hIvasRend->inputsSplitPost[inputIndex].base;
732 1200052 : break;
733 0 : default:
734 0 : return IVAS_ERR_INVALID_INPUT_ID;
735 : }
736 :
737 : /* Ensure input ID matches and that input is active */
738 1200052 : if ( pInputBase->id != inputId || pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
739 : {
740 0 : return IVAS_ERR_INVALID_INPUT_ID;
741 : }
742 :
743 : /* Validation done, set value via output parameter */
744 1200052 : *ppInput = pInputBase;
745 :
746 1200052 : return IVAS_ERR_OK;
747 : }
748 :
749 :
750 : /*-------------------------------------------------------------------*
751 : * ISAR_POST_REND_SetInputGain()
752 : *
753 : *
754 : *-------------------------------------------------------------------*/
755 :
756 0 : ivas_error ISAR_POST_REND_SetInputGain(
757 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
758 : const ISAR_POST_REND_InputId inputId, /* i : ID of the input */
759 : const float gain /* i : linear gain (not in dB) */
760 : )
761 : {
762 : input_base_isar *inputBase;
763 : ivas_error error;
764 :
765 : /* Validate function arguments */
766 0 : if ( hIvasRend == NULL )
767 : {
768 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
769 : }
770 :
771 0 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
772 : {
773 0 : printf( "Hoo\n" );
774 0 : return error;
775 : }
776 :
777 0 : inputBase->gain = gain;
778 :
779 0 : return IVAS_ERR_OK;
780 : }
781 :
782 :
783 603610 : static ivas_error getConstInputById(
784 : ISAR_POST_REND_CONST_HANDLE hIvasRend,
785 : const ISAR_POST_REND_InputId inputId,
786 : const void **ppInput )
787 : {
788 : int32_t inputIndex;
789 : IVAS_REND_AudioConfigType configType;
790 : const input_base_isar *pInputBase;
791 :
792 : /* Reverse makeInputId() */
793 603610 : inputIndex = ( inputId & 0xFF ) - 1;
794 603610 : configType = ( inputId & 0xFF00 ) >> 8;
795 :
796 : /* Validate values derived from input ID */
797 603610 : if ( inputIndex < 0 )
798 : {
799 0 : return IVAS_ERR_INVALID_INPUT_ID;
800 : }
801 603610 : switch ( configType )
802 : {
803 603610 : case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
804 603610 : if ( inputIndex > RENDERER_MAX_BIN_INPUTS )
805 : {
806 0 : return IVAS_ERR_INVALID_INPUT_ID;
807 : }
808 603610 : pInputBase = &hIvasRend->inputsSplitPost[inputIndex].base;
809 603610 : break;
810 0 : default:
811 0 : return IVAS_ERR_INVALID_INPUT_ID;
812 : }
813 :
814 : /* Ensure input ID matches and that input is active */
815 603610 : if ( pInputBase->id != inputId || pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
816 : {
817 0 : return IVAS_ERR_INVALID_INPUT_ID;
818 : }
819 :
820 : /* Validation done, set value via output parameter */
821 603610 : *ppInput = pInputBase;
822 :
823 603610 : return IVAS_ERR_OK;
824 : }
825 :
826 :
827 3584 : static ivas_error findFreeInputSlot(
828 : const void *inputs,
829 : const int32_t inputStructSize,
830 : const int32_t maxInputs,
831 : int32_t *inputIndex )
832 : {
833 : /* Using a void pointer and a separately provided size is a hack for this function
834 : to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
835 : Assumptions:
836 : - input_base_isar is always the first member in the input struct
837 : - provided size is correct
838 : */
839 :
840 : int32_t i;
841 : bool canAddInput;
842 : const uint8_t *pByte;
843 : const input_base_isar *pInputBase;
844 :
845 3584 : canAddInput = false;
846 :
847 : /* Find first unused input in array */
848 3584 : for ( i = 0, pByte = inputs; i < maxInputs; ++i, pByte += inputStructSize )
849 : {
850 3584 : pInputBase = (const input_base_isar *) pByte;
851 :
852 3584 : if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
853 : {
854 3584 : *inputIndex = i;
855 3584 : canAddInput = true;
856 3584 : break;
857 : }
858 : }
859 :
860 3584 : if ( !canAddInput )
861 : {
862 0 : return IVAS_ERR_TOO_MANY_INPUTS;
863 : }
864 :
865 3584 : return IVAS_ERR_OK;
866 : }
867 :
868 :
869 : /*-------------------------------------------------------------------*
870 : * ISAR_POST_REND_AddInput()
871 : *
872 : *
873 : *-------------------------------------------------------------------*/
874 :
875 3584 : ivas_error ISAR_POST_REND_AddInput(
876 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
877 : const IVAS_AUDIO_CONFIG inConfig, /* i : audio config for a new input */
878 : ISAR_POST_REND_InputId *inputId /* o : ID of the new input */
879 : )
880 : {
881 : ivas_error error;
882 : int32_t maxNumInputsOfType;
883 : void *inputsArray;
884 : int32_t inputStructSize;
885 :
886 : ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, ISAR_SPLIT_REND_CONFIG_DATA * );
887 : int32_t inputIndex;
888 :
889 : /* Validate function arguments */
890 3584 : if ( hIvasRend == NULL || inputId == NULL )
891 : {
892 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
893 : }
894 :
895 3584 : switch ( isar_getAudioConfigType( inConfig ) )
896 : {
897 3584 : case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
898 3584 : maxNumInputsOfType = RENDERER_MAX_BIN_INPUTS;
899 3584 : inputsArray = hIvasRend->inputsSplitPost;
900 3584 : inputStructSize = sizeof( *hIvasRend->inputsSplitPost );
901 3584 : activateInput = setRendInputActiveSplitPostRend;
902 3584 : break;
903 0 : default:
904 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
905 : }
906 :
907 : /* Find first free input in array corresponding to input type */
908 3584 : if ( ( error = findFreeInputSlot( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
909 : {
910 0 : return error;
911 : }
912 :
913 3584 : *inputId = makeInputId( inConfig, inputIndex );
914 :
915 3584 : if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, &hIvasRend->splitRenderConfig ) ) != IVAS_ERR_OK )
916 : {
917 0 : return error;
918 : }
919 :
920 3584 : return IVAS_ERR_OK;
921 : }
922 :
923 :
924 : /*-------------------------------------------------------------------*
925 : * ISAR_POST_REND_GetInputNumChannels()
926 : *
927 : *
928 : *-------------------------------------------------------------------*/
929 :
930 603610 : ivas_error ISAR_POST_REND_GetInputNumChannels(
931 : ISAR_POST_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
932 : const ISAR_POST_REND_InputId inputId, /* i : ID of the input */
933 : int16_t *numChannels /* o : number of channels of the input */
934 : )
935 : {
936 : ivas_error error;
937 : const input_base_isar *pInput;
938 :
939 : /* Validate function arguments */
940 603610 : if ( hIvasRend == NULL || numChannels == NULL )
941 : {
942 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
943 : }
944 :
945 603610 : if ( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ) != IVAS_ERR_OK )
946 : {
947 0 : return error;
948 : }
949 :
950 603610 : if ( ( error = getRendInputNumChannels( pInput, numChannels ) ) != IVAS_ERR_OK )
951 : {
952 0 : return error;
953 : }
954 :
955 603610 : return IVAS_ERR_OK;
956 : }
957 :
958 :
959 : /*-------------------------------------------------------------------*
960 : * ISAR_POST_REND_GetDelay()
961 : *
962 : *
963 : *-------------------------------------------------------------------*/
964 :
965 3584 : ivas_error ISAR_POST_REND_GetDelay(
966 : ISAR_POST_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
967 : int16_t *nSamples, /* o : Renderer delay in samples */
968 : int32_t *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
969 : )
970 : {
971 : int16_t i;
972 : int32_t latency_ns;
973 : int32_t max_latency_ns;
974 :
975 : /* Validate function arguments */
976 3584 : if ( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
977 : {
978 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
979 : }
980 :
981 3584 : *timeScale = hIvasRend->sampleRateOut;
982 3584 : *nSamples = 0;
983 3584 : max_latency_ns = 0;
984 :
985 : /* Compute the maximum delay across all inputs */
986 7168 : for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; i++ )
987 : {
988 3584 : if ( hIvasRend->inputsSplitPost[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
989 : {
990 3584 : latency_ns = 0;
991 3584 : if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hLc3plusDec != NULL )
992 : {
993 : int32_t lc3plusDelaySamples;
994 1442 : ISAR_LC3PLUS_DEC_GetDelay( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hLc3plusDec, &lc3plusDelaySamples );
995 1442 : latency_ns = (int32_t) roundf( lc3plusDelaySamples * 1000000000.f / *timeScale );
996 : }
997 3584 : if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
998 : {
999 2426 : latency_ns += IVAS_FB_DEC_DELAY_NS;
1000 : }
1001 1158 : else if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hSplitBinLCLDDec != NULL )
1002 : {
1003 764 : latency_ns += IVAS_FB_DEC_DELAY_NS;
1004 : }
1005 3584 : max_latency_ns = max( max_latency_ns, latency_ns );
1006 : }
1007 : }
1008 :
1009 3584 : *nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
1010 :
1011 3584 : return IVAS_ERR_OK;
1012 : }
1013 :
1014 :
1015 : /*-------------------------------------------------------------------*
1016 : * ISAR_POST_REND_FeedInputAudio()
1017 : *
1018 : *
1019 : *-------------------------------------------------------------------*/
1020 :
1021 600026 : ivas_error ISAR_POST_REND_FeedInputAudio(
1022 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1023 : const ISAR_POST_REND_InputId inputId, /* i : ID of the input */
1024 : const ISAR_POST_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */
1025 : )
1026 : {
1027 : ivas_error error;
1028 : input_base_isar *inputBase;
1029 : int16_t numInputChannels;
1030 : int16_t cldfb2tdSampleFact;
1031 :
1032 : /* Validate function arguments */
1033 600026 : if ( hIvasRend == NULL || inputAudio.data == NULL )
1034 : {
1035 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1036 : }
1037 :
1038 600026 : cldfb2tdSampleFact = ( inputAudio.config.is_cldfb ) ? 2 : 1;
1039 :
1040 600026 : if ( inputAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
1041 600026 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 1 ) )
1042 : {
1043 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
1044 : }
1045 :
1046 600026 : if ( inputAudio.config.numChannels <= 0 || MAX_INPUT_CHANNELS < inputAudio.config.numChannels )
1047 : {
1048 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1049 : }
1050 :
1051 600026 : if ( isar_getAudioConfigType( hIvasRend->outputConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
1052 600026 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
1053 600026 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
1054 600026 : ( inputAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( BINAURAL_RENDERING_FRAME_SIZE_MS * hIvasRend->num_subframes ) * hIvasRend->sampleRateOut )
1055 : {
1056 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
1057 : }
1058 :
1059 600026 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
1060 : {
1061 0 : printf( "Foo\n" );
1062 0 : return error;
1063 : }
1064 :
1065 600026 : if ( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ) != IVAS_ERR_OK )
1066 : {
1067 0 : return error;
1068 : }
1069 :
1070 600026 : if ( numInputChannels != inputAudio.config.numChannels )
1071 : {
1072 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1073 : }
1074 :
1075 600026 : inputBase->inputBuffer.config = inputAudio.config;
1076 :
1077 600026 : mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
1078 :
1079 600026 : inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact;
1080 :
1081 600026 : return IVAS_ERR_OK;
1082 : }
1083 :
1084 :
1085 : /*-------------------------------------------------------------------*
1086 : * ISAR_POST_REND_InitConfig()
1087 : *
1088 : *
1089 : *-------------------------------------------------------------------*/
1090 :
1091 3584 : ivas_error ISAR_POST_REND_InitConfig(
1092 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1093 : const AUDIO_CONFIG outAudioConfig /* i : output audioConfig */
1094 : )
1095 : {
1096 : bool rendererConfigEnabled;
1097 :
1098 3584 : rendererConfigEnabled = ( isar_getAudioConfigType( outAudioConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL );
1099 :
1100 3584 : if ( rendererConfigEnabled )
1101 : {
1102 3584 : hIvasRend->rendererConfigEnabled = 1;
1103 : }
1104 : else
1105 : {
1106 0 : hIvasRend->rendererConfigEnabled = 0;
1107 : }
1108 :
1109 3584 : if ( rendererConfigEnabled )
1110 : {
1111 3584 : hIvasRend->splitRenderConfig.splitRendBitRate = SPLIT_REND_768k;
1112 3584 : hIvasRend->splitRenderConfig.dof = 3;
1113 3584 : hIvasRend->splitRenderConfig.hq_mode = 0;
1114 3584 : hIvasRend->splitRenderConfig.codec_delay_ms = 0;
1115 3584 : hIvasRend->splitRenderConfig.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1116 3584 : hIvasRend->splitRenderConfig.isar_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1117 3584 : hIvasRend->splitRenderConfig.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
1118 3584 : hIvasRend->splitRenderConfig.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
1119 3584 : hIvasRend->splitRenderConfig.rendererSelection = IVAS_BIN_RENDERER_TYPE_DEFAULT;
1120 : }
1121 :
1122 3584 : return IVAS_ERR_OK;
1123 : }
1124 :
1125 :
1126 : /*-------------------------------------------------------------------*
1127 : * ISAR_POST_REND_GetRenderConfig()
1128 : *
1129 : *
1130 : *-------------------------------------------------------------------*/
1131 :
1132 0 : int16_t ISAR_POST_REND_GetRenderConfig(
1133 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: IVAS decoder handle */
1134 : const ISAR_SPLIT_REND_CONFIG_HANDLE splitRenderConfig /* o : Render configuration handle */
1135 : )
1136 : {
1137 : ISAR_SPLIT_REND_CONFIG_DATA hRCin;
1138 :
1139 0 : if ( hIvasRend == NULL )
1140 : {
1141 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1142 : }
1143 :
1144 0 : hRCin = hIvasRend->splitRenderConfig;
1145 :
1146 0 : splitRenderConfig->splitRendBitRate = SPLIT_REND_768k;
1147 0 : splitRenderConfig->dof = 3;
1148 0 : splitRenderConfig->hq_mode = 0;
1149 0 : splitRenderConfig->codec_delay_ms = 0;
1150 0 : splitRenderConfig->codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1151 0 : splitRenderConfig->isar_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1152 0 : splitRenderConfig->codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
1153 0 : splitRenderConfig->poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
1154 0 : splitRenderConfig->rendererSelection = hRCin.rendererSelection;
1155 :
1156 0 : return IVAS_ERR_OK;
1157 : }
1158 :
1159 :
1160 : /*-------------------------------------------------------------------*
1161 : * ISAR_POST_REND_FeedSplitBinauralBitstream()
1162 : *
1163 : *
1164 : *-------------------------------------------------------------------*/
1165 :
1166 600026 : ivas_error ISAR_POST_REND_FeedSplitBinauralBitstream(
1167 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1168 : const IVAS_REND_InputId inputId, /* i : ID of the input */
1169 : ISAR_POST_REND_BitstreamBuffer *hBits /* i : buffer for input bitstream */
1170 : )
1171 : {
1172 : ivas_error error;
1173 : input_base_isar *inputBase;
1174 : input_split_post_rend *inputSplitPostRend;
1175 :
1176 : /* Validate function arguments */
1177 600026 : if ( hIvasRend == NULL || hBits == NULL )
1178 : {
1179 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1180 : }
1181 :
1182 600026 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
1183 : {
1184 0 : printf( "Goo\n" );
1185 0 : return error;
1186 : }
1187 :
1188 600026 : inputSplitPostRend = (input_split_post_rend *) inputBase;
1189 600026 : inputSplitPostRend->hBits = hBits;
1190 :
1191 600026 : return IVAS_ERR_OK;
1192 : }
1193 :
1194 :
1195 : /*-------------------------------------------------------------------*
1196 : * ISAR_POST_REND_SetHeadRotation()
1197 : *
1198 : *
1199 : *-------------------------------------------------------------------*/
1200 :
1201 2274380 : ivas_error ISAR_POST_REND_SetHeadRotation(
1202 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1203 : const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */
1204 : const IVAS_VECTOR3 Pos, /* i : listener positions for next rendering call */
1205 : const ISAR_SPLIT_REND_ROT_AXIS rot_axis, /* i : external control for rotation axis for split rendering */
1206 : const int16_t sf_idx /* i : subframe index */
1207 : )
1208 : {
1209 : IVAS_QUATERNION rotQuat;
1210 :
1211 : /* Validate function arguments */
1212 2274380 : if ( hIvasRend == NULL )
1213 : {
1214 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1215 : }
1216 :
1217 2274380 : if ( isar_getAudioConfigType( hIvasRend->outputConfig ) != ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL )
1218 : {
1219 : /* Head rotation can be set only with binaural output */
1220 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
1221 : }
1222 :
1223 2274380 : hIvasRend->headRotData.headRotEnabled = 1;
1224 :
1225 : /* check for Euler angle signaling */
1226 2274380 : if ( headRot.w == -3.0f )
1227 : {
1228 1805180 : Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat );
1229 : }
1230 : else
1231 : {
1232 469200 : rotQuat = headRot;
1233 : }
1234 :
1235 2274380 : hIvasRend->headRotData.headPositions[sf_idx] = rotQuat;
1236 2274380 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
1237 2274380 : hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
1238 :
1239 2274380 : return IVAS_ERR_OK;
1240 : }
1241 :
1242 :
1243 : /*-------------------------------------------------------------------*
1244 : * ISAR_POST_REND_SetSplitRendBFI()
1245 : *
1246 : *
1247 : *-------------------------------------------------------------------*/
1248 :
1249 614640 : ivas_error ISAR_POST_REND_SetSplitRendBFI(
1250 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1251 : const int16_t bfi /* i : BFI flag */
1252 : )
1253 : {
1254 614640 : hIvasRend->splitRendBFI = bfi;
1255 :
1256 614640 : return IVAS_ERR_OK;
1257 : }
1258 :
1259 :
1260 : /*-------------------------------------------------------------------*
1261 : * Local functions
1262 : *-------------------------------------------------------------------*/
1263 :
1264 250328 : static ivas_error splitBinLc3plusDecode(
1265 : ISAR_SPLIT_POST_REND_WRAPPER *hSplitBin,
1266 : ISAR_SPLIT_REND_BITS_HANDLE bits,
1267 : float outputBuffer[BINAURAL_CHANNELS][L_FRAME48k],
1268 : const int16_t SplitRendBFI )
1269 : {
1270 : ivas_error error;
1271 : float *channel_ptrs[MAX_HEAD_ROT_POSES * 2];
1272 : int32_t lc3plusBitstreamSize;
1273 :
1274 250328 : push_wmops( "splitBinLc3plusDecode" );
1275 250328 : assert( hSplitBin->hLc3plusDec != NULL );
1276 :
1277 2860600 : for ( int16_t i = 0; i < BINAURAL_CHANNELS * hSplitBin->multiBinPoseData.num_poses; ++i )
1278 : {
1279 2610272 : channel_ptrs[i] = outputBuffer[i];
1280 : }
1281 :
1282 250328 : if ( SplitRendBFI == 0 )
1283 : {
1284 : /* Find next byte boundary */
1285 830925 : while ( bits->bits_read % 8 != 0 )
1286 : {
1287 581621 : ++bits->bits_read;
1288 : }
1289 :
1290 : /* Size is in bytes */
1291 249304 : assert( ( bits->bits_written - bits->bits_read ) % 8 == 0 );
1292 249304 : lc3plusBitstreamSize = ( bits->bits_written - bits->bits_read ) / 8;
1293 :
1294 249304 : if ( ( error = ISAR_LC3PLUS_DEC_Decode( hSplitBin->hLc3plusDec, &bits->bits_buf[bits->bits_read / 8], lc3plusBitstreamSize, channel_ptrs ) ) != IVAS_ERR_OK )
1295 : {
1296 0 : return error;
1297 : }
1298 : }
1299 : else
1300 : {
1301 1024 : if ( ( error = ISAR_LC3PLUS_DEC_Conceal( hSplitBin->hLc3plusDec, channel_ptrs ) ) != IVAS_ERR_OK )
1302 : {
1303 0 : return error;
1304 : }
1305 : }
1306 :
1307 250328 : pop_wmops();
1308 250328 : return IVAS_ERR_OK;
1309 : }
1310 :
1311 :
1312 678596 : static ivas_error renderSplitBinauralWithPostRot(
1313 : input_split_post_rend *splitBinInput,
1314 : IVAS_REND_AudioBuffer outAudio,
1315 : const int16_t SplitRendBFI,
1316 : const int16_t num_subframes )
1317 : {
1318 : float Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
1319 : float Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
1320 : ivas_error error;
1321 : float Cldfb_RealBuffer_Binaural_5ms[MAX_PARAM_SPATIAL_SUBFRAMES][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX];
1322 : float Cldfb_ImagBuffer_Binaural_5ms[MAX_PARAM_SPATIAL_SUBFRAMES][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX];
1323 : IVAS_QUATERNION QuaternionsPost[MAX_PARAM_SPATIAL_SUBFRAMES];
1324 : int16_t sf_idx, ch_idx;
1325 : ISAR_SPLIT_REND_BITS_DATA bits;
1326 : float tmpCrendBuffer[BINAURAL_CHANNELS][L_FRAME48k];
1327 : float tmpCrendBuffer_sf[BINAURAL_CHANNELS][L_FRAME48k];
1328 : ISAR_SPLIT_POST_REND_WRAPPER *hSplitBin;
1329 : int8_t isPostRendInputCldfb;
1330 : int16_t chnlIdx, slotIdx, smplIdx;
1331 : int16_t preRendFrameSize_ms;
1332 : int16_t outBufNumSamplesPerChannel, outBufNumColPerChannel;
1333 : int16_t numSamplesPerChannelCacheSize, numColPerChannelCacheSize;
1334 : float *readPtr, *writePtr;
1335 : int16_t iNumBlocksPerFrame, iNumLCLDIterationsPerFrame;
1336 : const ISAR_POST_REND_HeadRotData *pHeadRotData;
1337 :
1338 678596 : isPostRendInputCldfb = 0;
1339 678596 : push_wmops( "renderSplitBinauralWithPostRot" );
1340 678596 : error = IVAS_ERR_OK;
1341 :
1342 678596 : if ( outAudio.config.numSamplesPerChannel / *splitBinInput->base.ctx.pOutSampleRate > splitBinInput->hBits->config.isar_frame_size_ms )
1343 : {
1344 0 : return IVAS_ERR_INTERNAL_FATAL;
1345 : }
1346 :
1347 678596 : pHeadRotData = splitBinInput->base.ctx.pHeadRotData;
1348 678596 : hSplitBin = &splitBinInput->splitPostRendWrapper;
1349 678596 : convertBitsBufferToInternalBitsBuff( *splitBinInput->hBits, &bits );
1350 :
1351 678596 : iNumLCLDIterationsPerFrame = 1;
1352 678596 : iNumBlocksPerFrame = CLDFB_NO_COL_MAX;
1353 678596 : if ( splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec != NULL )
1354 : {
1355 360337 : iNumBlocksPerFrame = splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec->iNumBlocks;
1356 360337 : iNumLCLDIterationsPerFrame = splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec->iNumIterations;
1357 : }
1358 :
1359 678596 : outBufNumSamplesPerChannel = outAudio.config.numSamplesPerChannel / num_subframes;
1360 2952976 : for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
1361 : {
1362 2274380 : QuaternionsPost[sf_idx] = pHeadRotData->headPositions[sf_idx];
1363 : }
1364 :
1365 678596 : if ( !SplitRendBFI )
1366 : {
1367 661072 : hSplitBin->first_good_frame_received = 1;
1368 : }
1369 :
1370 678596 : if ( hSplitBin->first_good_frame_received == 1 )
1371 : {
1372 662362 : if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
1373 : {
1374 405018 : if ( !SplitRendBFI )
1375 : {
1376 : #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG
1377 : isar_splitBinPostRendMdDec( &bits, hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData, hSplitBin->hBinHrSplitPreRend );
1378 : #else
1379 403728 : isar_splitBinPostRendMdDec( &bits, hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData );
1380 : #endif
1381 : }
1382 : }
1383 :
1384 : /*copy pose correction after MD is parsed*/
1385 662362 : hSplitBin->multiBinPoseData.poseCorrectionMode = bits.pose_correction;
1386 :
1387 : /* decode audio */
1388 662362 : if ( splitBinInput->base.inConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
1389 : {
1390 652183 : if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
1391 : {
1392 350555 : isPostRendInputCldfb = 1;
1393 : }
1394 :
1395 652183 : numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outBufNumSamplesPerChannel;
1396 :
1397 652183 : outBufNumColPerChannel = MAX_PARAM_SPATIAL_SUBFRAMES;
1398 652183 : numColPerChannelCacheSize = ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ) - outBufNumColPerChannel;
1399 :
1400 2829983 : for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
1401 : {
1402 2177800 : if ( splitBinInput->numCachedSamples == 0 )
1403 : {
1404 575233 : if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
1405 : {
1406 324905 : isar_splitBinLCLDDecProcess( hSplitBin->hSplitBinLCLDDec, &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, SplitRendBFI );
1407 :
1408 : /* copy data over to 5ms buffer */
1409 974715 : for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
1410 : {
1411 3249050 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; ++slotIdx )
1412 : {
1413 2599240 : mvr2r( Cldfb_RealBuffer_Binaural[chnlIdx][slotIdx], Cldfb_RealBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx], CLDFB_NO_CHANNELS_MAX );
1414 2599240 : mvr2r( Cldfb_ImagBuffer_Binaural[chnlIdx][slotIdx], Cldfb_ImagBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx], CLDFB_NO_CHANNELS_MAX );
1415 : }
1416 : }
1417 :
1418 : /* cache the remaining 15ms */
1419 324905 : splitBinInput->numCachedSamples = numColPerChannelCacheSize;
1420 324905 : writePtr = splitBinInput->bufferData;
1421 4018541 : for ( slotIdx = CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; slotIdx < ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ); ++slotIdx )
1422 : {
1423 11080908 : for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
1424 : {
1425 450623592 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1426 : {
1427 443236320 : *writePtr++ = Cldfb_RealBuffer_Binaural[chnlIdx][slotIdx][smplIdx];
1428 : }
1429 450623592 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1430 : {
1431 443236320 : *writePtr++ = Cldfb_ImagBuffer_Binaural[chnlIdx][slotIdx][smplIdx];
1432 : }
1433 : }
1434 : }
1435 : }
1436 : else
1437 : {
1438 250328 : if ( ( error = splitBinLc3plusDecode( hSplitBin, &bits, tmpCrendBuffer, SplitRendBFI ) ) != IVAS_ERR_OK )
1439 : {
1440 0 : return error;
1441 : }
1442 :
1443 : /* cache the remaining decoded audio */
1444 250328 : splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
1445 250328 : mvr2r( &tmpCrendBuffer[0][outBufNumSamplesPerChannel], splitBinInput->bufferData, numSamplesPerChannelCacheSize );
1446 250328 : mvr2r( &tmpCrendBuffer[1][outBufNumSamplesPerChannel], splitBinInput->bufferData + numSamplesPerChannelCacheSize, numSamplesPerChannelCacheSize );
1447 : }
1448 : }
1449 : else
1450 : {
1451 : /* copy from cache */
1452 1602567 : if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
1453 : {
1454 923409 : int16_t readOffset = ( numColPerChannelCacheSize - splitBinInput->numCachedSamples );
1455 923409 : readPtr = splitBinInput->bufferData;
1456 923409 : isPostRendInputCldfb = 1;
1457 :
1458 923409 : readPtr += 2 * readOffset * CLDFB_NO_CHANNELS_MAX * BINAURAL_CHANNELS;
1459 4617045 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; ++slotIdx )
1460 : {
1461 11080908 : for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
1462 : {
1463 450623592 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1464 : {
1465 443236320 : Cldfb_RealBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx][smplIdx] = *readPtr++;
1466 : }
1467 450623592 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1468 : {
1469 443236320 : Cldfb_ImagBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx][smplIdx] = *readPtr++;
1470 : }
1471 : }
1472 : }
1473 :
1474 923409 : splitBinInput->numCachedSamples -= outBufNumColPerChannel;
1475 : }
1476 : else
1477 : {
1478 679158 : int16_t readOffset = numSamplesPerChannelCacheSize - splitBinInput->numCachedSamples;
1479 679158 : mvr2r( splitBinInput->bufferData + readOffset, &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1480 679158 : mvr2r( splitBinInput->bufferData + readOffset + numSamplesPerChannelCacheSize, &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1481 679158 : splitBinInput->numCachedSamples -= outBufNumSamplesPerChannel;
1482 : }
1483 : }
1484 : }
1485 : }
1486 : else
1487 : {
1488 10179 : copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer );
1489 10179 : if ( splitBinInput->numCachedSamples == 0 )
1490 : {
1491 10179 : preRendFrameSize_ms = splitBinInput->base.ctx.pSplitRenderConfig->isar_frame_size_ms;
1492 10179 : numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * preRendFrameSize_ms / 1000 );
1493 10179 : numSamplesPerChannelCacheSize -= outAudio.config.numSamplesPerChannel;
1494 10179 : splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
1495 : }
1496 : else
1497 : {
1498 0 : splitBinInput->numCachedSamples -= outAudio.config.numSamplesPerChannel;
1499 : }
1500 : }
1501 :
1502 : /* apply pose correction if enabled */
1503 2880878 : for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
1504 : {
1505 2218516 : if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE && isPostRendInputCldfb )
1506 454102 : {
1507 : /* 0DOF with LCLD codec requires CLDFB synthesis */
1508 : int16_t slot_idx;
1509 :
1510 1362306 : for ( ch_idx = 0; ch_idx < BINAURAL_CHANNELS; ch_idx++ )
1511 : {
1512 : float *RealBuffer[CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES];
1513 : float *ImagBuffer[CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES];
1514 :
1515 4541020 : for ( slot_idx = 0; slot_idx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; slot_idx++ )
1516 : {
1517 3632816 : RealBuffer[slot_idx] = Cldfb_RealBuffer_Binaural_5ms[sf_idx][ch_idx][slot_idx];
1518 3632816 : ImagBuffer[slot_idx] = Cldfb_ImagBuffer_Binaural_5ms[sf_idx][ch_idx][slot_idx];
1519 : }
1520 :
1521 908204 : cldfbSynthesis( RealBuffer,
1522 : ImagBuffer,
1523 908204 : &( tmpCrendBuffer[ch_idx][sf_idx * outBufNumSamplesPerChannel] ),
1524 908204 : hSplitBin->hBinHrSplitPostRend->cldfbSyn[0]->no_channels * CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
1525 908204 : hSplitBin->hBinHrSplitPostRend->cldfbSyn[ch_idx] );
1526 : }
1527 : }
1528 1764414 : else if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
1529 : {
1530 1496952 : mvr2r( &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], tmpCrendBuffer_sf[0], outBufNumSamplesPerChannel );
1531 1496952 : mvr2r( &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], tmpCrendBuffer_sf[1], outBufNumSamplesPerChannel );
1532 :
1533 1496952 : isar_rend_CldfbSplitPostRendProcess( hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData, QuaternionsPost[sf_idx], Cldfb_RealBuffer_Binaural_5ms[sf_idx], Cldfb_ImagBuffer_Binaural_5ms[sf_idx], tmpCrendBuffer_sf, isPostRendInputCldfb );
1534 :
1535 1496952 : mvr2r( tmpCrendBuffer_sf[0], &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1536 1496952 : mvr2r( tmpCrendBuffer_sf[1], &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1537 : }
1538 : }
1539 : }
1540 : else
1541 : {
1542 16234 : if ( splitBinInput->numCachedSamples == 0 )
1543 : {
1544 14614 : numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outAudio.config.numSamplesPerChannel;
1545 14614 : splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
1546 : }
1547 : else
1548 : {
1549 1620 : splitBinInput->numCachedSamples -= outAudio.config.numSamplesPerChannel;
1550 : }
1551 :
1552 16234 : if ( splitBinInput->base.inConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
1553 : {
1554 48261 : for ( ch_idx = 0; ch_idx < BINAURAL_CHANNELS; ch_idx++ )
1555 : {
1556 32174 : set_zero( tmpCrendBuffer[ch_idx], outAudio.config.numSamplesPerChannel );
1557 : }
1558 : }
1559 : else
1560 : {
1561 147 : copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer );
1562 : }
1563 : }
1564 :
1565 678596 : convertInternalBitsBuffToBitsBuffer( splitBinInput->hBits, bits );
1566 678596 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
1567 :
1568 678596 : pop_wmops();
1569 678596 : return error;
1570 : }
1571 :
1572 :
1573 678596 : static ivas_error renderInputSplitBin(
1574 : input_split_post_rend *splitBinInput,
1575 : const AUDIO_CONFIG outConfig,
1576 : IVAS_REND_AudioBuffer outAudio,
1577 : const int16_t SplitRendBFI,
1578 : const int16_t num_subframes )
1579 : {
1580 : ivas_error error;
1581 : IVAS_REND_AudioBuffer inAudio;
1582 :
1583 678596 : inAudio = splitBinInput->base.inputBuffer;
1584 :
1585 678596 : splitBinInput->base.numNewSamplesPerChannel = 0;
1586 :
1587 : /* Apply input gain to new audio */
1588 678596 : v_multc( inAudio.data,
1589 : splitBinInput->base.gain,
1590 : inAudio.data,
1591 678596 : inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
1592 678596 : switch ( outConfig )
1593 : {
1594 678596 : case IVAS_AUDIO_CONFIG_BINAURAL:
1595 678596 : error = renderSplitBinauralWithPostRot( splitBinInput, outAudio, SplitRendBFI, num_subframes );
1596 678596 : break;
1597 0 : default:
1598 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
1599 : }
1600 :
1601 678596 : return error;
1602 : }
1603 :
1604 :
1605 678596 : static ivas_error renderActiveInputsSplitBin(
1606 : ISAR_POST_REND_HANDLE hIvasRend,
1607 : IVAS_REND_AudioBuffer outAudio )
1608 : {
1609 : int16_t i;
1610 : input_split_post_rend *pCurrentInput;
1611 : ivas_error error;
1612 :
1613 1357192 : for ( i = 0, pCurrentInput = hIvasRend->inputsSplitPost; i < RENDERER_MAX_BIN_INPUTS; ++i, ++pCurrentInput )
1614 : {
1615 678596 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
1616 : {
1617 : /* Skip inactive inputs */
1618 0 : continue;
1619 : }
1620 :
1621 678596 : if ( ( error = renderInputSplitBin( pCurrentInput, hIvasRend->outputConfig, outAudio, hIvasRend->splitRendBFI, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
1622 : {
1623 0 : return error;
1624 : }
1625 : }
1626 :
1627 678596 : return IVAS_ERR_OK;
1628 : }
1629 :
1630 :
1631 : /*-------------------------------------------------------------------*
1632 : * ISAR_POST_REND_getSamples()
1633 : *
1634 : *
1635 : *-------------------------------------------------------------------*/
1636 :
1637 678596 : ivas_error ISAR_POST_REND_getSamples(
1638 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1639 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
1640 : )
1641 : {
1642 : ivas_error error;
1643 : int16_t numOutChannels;
1644 : int16_t cldfb2tdSampleFact;
1645 :
1646 : /* Validate function arguments */
1647 678596 : if ( hIvasRend == NULL || outAudio.data == NULL )
1648 : {
1649 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1650 : }
1651 :
1652 678596 : cldfb2tdSampleFact = ( outAudio.config.is_cldfb ) ? 2 : 1;
1653 :
1654 678596 : if ( outAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
1655 678596 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
1656 : {
1657 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
1658 : }
1659 :
1660 678596 : if ( outAudio.config.numChannels <= 0 || MAX_OUTPUT_CHANNELS < outAudio.config.numChannels )
1661 : {
1662 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1663 : }
1664 :
1665 678596 : if ( isar_getAudioConfigType( hIvasRend->outputConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
1666 678596 : ( outAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( hIvasRend->num_subframes * BINAURAL_RENDERING_FRAME_SIZE_MS ) * hIvasRend->sampleRateOut )
1667 : {
1668 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
1669 : }
1670 :
1671 678596 : if ( ( error = ISAR_POST_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
1672 : {
1673 0 : return error;
1674 : }
1675 :
1676 678596 : if ( numOutChannels != outAudio.config.numChannels && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
1677 : {
1678 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1679 : }
1680 :
1681 : /* Clear original output buffer */
1682 678596 : set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
1683 :
1684 678596 : if ( ( error = renderActiveInputsSplitBin( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
1685 : {
1686 0 : return error;
1687 : }
1688 :
1689 : #ifndef DISABLE_LIMITER
1690 : #ifdef DEBUGGING
1691 : hIvasRend->numClipping +=
1692 : #endif
1693 678596 : limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
1694 : #endif
1695 :
1696 678596 : return IVAS_ERR_OK;
1697 : }
1698 :
1699 :
1700 : /*-------------------------------------------------------------------*
1701 : * ISAR_POST_REND_GetSplitBinauralSamples()
1702 : *
1703 : *
1704 : *-------------------------------------------------------------------*/
1705 :
1706 678596 : ivas_error ISAR_POST_REND_GetSplitBinauralSamples(
1707 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1708 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
1709 : bool *needNewFrame )
1710 : {
1711 : ivas_error error;
1712 :
1713 678596 : if ( ( error = ISAR_POST_REND_getSamples( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
1714 : {
1715 0 : return error;
1716 : }
1717 678596 : *needNewFrame = hIvasRend->inputsSplitPost[0].numCachedSamples == 0;
1718 :
1719 678596 : return IVAS_ERR_OK;
1720 : }
1721 :
1722 :
1723 : /*-------------------------------------------------------------------*
1724 : * ISAR_POST_REND_Close()
1725 : *
1726 : *
1727 : *-------------------------------------------------------------------*/
1728 :
1729 3584 : void ISAR_POST_REND_Close(
1730 : ISAR_POST_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
1731 : )
1732 : {
1733 : uint16_t i;
1734 : ISAR_POST_REND_HANDLE hIvasRend;
1735 :
1736 : /* Validate function arguments */
1737 3584 : if ( phIvasRend == NULL || *phIvasRend == NULL )
1738 : {
1739 0 : return;
1740 : }
1741 3584 : hIvasRend = *phIvasRend;
1742 :
1743 7168 : for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; ++i )
1744 : {
1745 3584 : clearInputSplitRend( &hIvasRend->inputsSplitPost[i] );
1746 : }
1747 :
1748 3584 : ivas_limiter_close( &hIvasRend->hLimiter );
1749 :
1750 3584 : free( hIvasRend );
1751 3584 : *phIvasRend = NULL;
1752 :
1753 3584 : return;
1754 : }
1755 :
1756 :
1757 : /*-------------------------------------------------------------------*
1758 : * ISAR_REND_SetSplitRendBitstreamHeader()
1759 : *
1760 : *
1761 : *-------------------------------------------------------------------*/
1762 :
1763 3584 : ivas_error ISAR_REND_SetSplitRendBitstreamHeader(
1764 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
1765 : const ISAR_SPLIT_REND_CODEC codec, /* o : codec setting */
1766 : const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection, /* o : pose correction mode */
1767 : const int16_t codec_frame_size_ms, /* i : codec frame size setting */
1768 : const int16_t isar_frame_size_ms, /* i : ISAR codec frame size setting */
1769 : const int16_t lc3plus_highres /* i : LC3plus Hig-Res setting. Ignored if codec is not LC3plus */
1770 : )
1771 : {
1772 3584 : if ( hIvasRend == NULL )
1773 : {
1774 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1775 : }
1776 :
1777 3584 : hIvasRend->splitRenderConfig.codec = codec;
1778 3584 : hIvasRend->splitRenderConfig.isar_frame_size_ms = isar_frame_size_ms;
1779 3584 : hIvasRend->splitRenderConfig.codec_frame_size_ms = codec_frame_size_ms;
1780 3584 : hIvasRend->splitRenderConfig.poseCorrectionMode = poseCorrection;
1781 3584 : hIvasRend->splitRenderConfig.lc3plus_highres = lc3plus_highres;
1782 :
1783 3584 : return IVAS_ERR_OK;
1784 : }
1785 :
1786 : #ifdef DEBUGGING
1787 : /*-------------------------------------------------------------------*
1788 : * ISAR_POST_REND_GetNoCLipping()
1789 : *
1790 : *
1791 : *-------------------------------------------------------------------*/
1792 :
1793 : int32_t ISAR_POST_REND_GetNoCLipping(
1794 : ISAR_POST_REND_HANDLE hIvasRend )
1795 : {
1796 : return hIvasRend->numClipping;
1797 : }
1798 :
1799 :
1800 : /*-------------------------------------------------------------------*
1801 : * ISAR_POST_REND_GetCntFramesLimited()
1802 : *
1803 : *
1804 : *-------------------------------------------------------------------*/
1805 :
1806 : int32_t ISAR_POST_REND_GetCntFramesLimited(
1807 : ISAR_POST_REND_HANDLE hIvasRend )
1808 : {
1809 : if ( hIvasRend->hLimiter == NULL )
1810 : {
1811 : return 0;
1812 : }
1813 :
1814 : return hIvasRend->hLimiter->cnt_frames_limited;
1815 : }
1816 : #endif
|