Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2026 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 3880962 : ISAR_POST_REND_AudioConfigType isar_getAudioConfigType(
123 : const AUDIO_CONFIG config /* i : audio configuration */
124 : )
125 : {
126 : ISAR_POST_REND_AudioConfigType type;
127 :
128 3880962 : switch ( config )
129 : {
130 3880962 : case IVAS_AUDIO_CONFIG_BINAURAL:
131 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
132 : case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
133 3880962 : type = ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL;
134 3880962 : break;
135 0 : default:
136 0 : type = ISAR_POST_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
137 0 : break;
138 : }
139 :
140 3880962 : return type;
141 : }
142 :
143 :
144 : /*-------------------------------------------------------------------*
145 : * Local functions
146 : *-------------------------------------------------------------------*/
147 :
148 3820 : static ivas_error allocateInputBaseBufferData(
149 : float **data,
150 : const int16_t data_size )
151 : {
152 3820 : *data = (float *) malloc( data_size * sizeof( float ) );
153 3820 : 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 3820 : return IVAS_ERR_OK;
159 : }
160 :
161 :
162 3820 : static void freeInputBaseBufferData(
163 : float **data )
164 : {
165 3820 : if ( *data != NULL )
166 : {
167 3820 : free( *data );
168 3820 : *data = NULL;
169 : }
170 :
171 3820 : return;
172 : }
173 :
174 :
175 14515 : static IVAS_QUATERNION quaternionInit(
176 : void )
177 : {
178 : IVAS_QUATERNION q;
179 14515 : q.w = 1.0f;
180 14515 : q.x = q.y = q.z = 0.0f;
181 14515 : return q;
182 : }
183 :
184 739596 : static void convertBitsBufferToInternalBitsBuff(
185 : const ISAR_POST_REND_BitstreamBuffer outBits,
186 : ISAR_SPLIT_REND_BITS_HANDLE hBits )
187 : {
188 739596 : hBits->bits_buf = outBits.bits;
189 739596 : hBits->bits_read = outBits.config.bitsRead;
190 739596 : hBits->bits_written = outBits.config.bitsWritten;
191 739596 : hBits->buf_len = outBits.config.bufLenInBytes;
192 739596 : hBits->codec = outBits.config.codec;
193 739596 : hBits->pose_correction = outBits.config.poseCorrection;
194 739596 : hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
195 739596 : hBits->isar_frame_size_ms = outBits.config.isar_frame_size_ms;
196 739596 : hBits->lc3plus_highres = outBits.config.lc3plusHighRes;
197 :
198 739596 : return;
199 : }
200 :
201 :
202 739596 : static void convertInternalBitsBuffToBitsBuffer(
203 : ISAR_POST_REND_BitstreamBuffer *hOutBits,
204 : const ISAR_SPLIT_REND_BITS_DATA bits )
205 : {
206 739596 : hOutBits->bits = bits.bits_buf;
207 739596 : hOutBits->config.bitsRead = bits.bits_read;
208 739596 : hOutBits->config.bitsWritten = bits.bits_written;
209 739596 : hOutBits->config.bufLenInBytes = bits.buf_len;
210 739596 : hOutBits->config.codec = bits.codec;
211 739596 : hOutBits->config.poseCorrection = bits.pose_correction;
212 739596 : hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
213 739596 : hOutBits->config.isar_frame_size_ms = bits.isar_frame_size_ms;
214 739596 : hOutBits->config.lc3plusHighRes = bits.lc3plus_highres;
215 :
216 739596 : return;
217 : }
218 :
219 :
220 11076 : 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 11076 : assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
229 11076 : readPtr = buffer.data;
230 :
231 33228 : for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
232 : {
233 21288072 : for ( smplIdx = 0; smplIdx < (uint32_t) buffer.config.numSamplesPerChannel; ++smplIdx )
234 : {
235 21265920 : array[chnlIdx][smplIdx] = *readPtr++;
236 : }
237 : }
238 :
239 11076 : return;
240 : }
241 :
242 :
243 739596 : 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 739596 : writePtr = buffer->data;
251 2218788 : for ( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
252 : {
253 1190141592 : for ( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
254 : {
255 1188662400 : *writePtr++ += array[chnlIdx][smplIdx];
256 : }
257 : }
258 :
259 739596 : 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 739596 : 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 739596 : int32_t numClipping = 0;
282 :
283 : /* return early if given bad parameters */
284 739596 : if ( hLimiter == NULL || output == NULL || output_frame <= 0 )
285 : {
286 0 : return 0;
287 : }
288 :
289 739596 : channels = hLimiter->channel_ptrs;
290 739596 : num_channels = hLimiter->num_channels;
291 :
292 2218788 : for ( i = 0; i < num_channels; ++i )
293 : {
294 1479192 : channels[i] = output + i * output_frame;
295 : }
296 :
297 739596 : 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 1189401996 : 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 1188662400 : output[i] = min( max( INT16_MIN, output[i] ), INT16_MAX );
310 : }
311 :
312 739596 : return numClipping;
313 : }
314 :
315 : #endif
316 :
317 : /*-------------------------------------------------------------------*
318 : * validateOutputSampleRate()
319 : *
320 : *
321 : *-------------------------------------------------------------------*/
322 :
323 3820 : static ivas_error validateOutputSampleRate(
324 : const int32_t sampleRate,
325 : const AUDIO_CONFIG outConfig )
326 : {
327 3820 : 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 3820 : switch ( sampleRate )
335 : {
336 3820 : case 8000:
337 : case 16000:
338 : case 32000:
339 : case 48000:
340 3820 : 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 3820 : 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 3820 : 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 3820 : if ( *phLimiter != NULL )
367 : {
368 0 : ivas_limiter_close( phLimiter );
369 : }
370 :
371 3820 : if ( ( error = ivas_limiter_open( phLimiter, numChannels, sampleRate ) ) != IVAS_ERR_OK )
372 : {
373 0 : return error;
374 : }
375 :
376 3820 : return IVAS_ERR_OK;
377 : }
378 :
379 :
380 3820 : 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 3820 : hIvasRend->headRotData.headRotEnabled = 1;
388 :
389 : /* Initialize 5ms crossfade */
390 3820 : crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
391 3820 : tmp = 1.f / ( crossfade_len - 1 );
392 920620 : for ( i = 0; i < crossfade_len; i++ )
393 : {
394 916800 : hIvasRend->headRotData.crossfade[i] = i * tmp;
395 : }
396 :
397 : /* Initialize with unit quaternions */
398 18335 : for ( i = 0; i < hIvasRend->num_subframes; ++i )
399 : {
400 14515 : hIvasRend->headRotData.headPositions[i] = quaternionInit();
401 : }
402 :
403 3820 : hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
404 :
405 3820 : return IVAS_ERR_OK;
406 : }
407 :
408 :
409 11460 : 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 11460 : inputBase->inConfig = inConfig;
418 11460 : inputBase->id = id;
419 11460 : inputBase->gain = 1.0f;
420 11460 : inputBase->ctx = rendCtx;
421 11460 : inputBase->numNewSamplesPerChannel = 0;
422 :
423 11460 : inputBase->inputBuffer.config.numSamplesPerChannel = 0;
424 11460 : inputBase->inputBuffer.config.numChannels = 0;
425 11460 : inputBase->inputBuffer.data = dataBuf;
426 11460 : if ( inputBase->inputBuffer.data != NULL )
427 : {
428 3820 : set_zero( inputBase->inputBuffer.data, dataBufSize );
429 : }
430 :
431 11460 : return;
432 : }
433 :
434 :
435 3820 : 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 3820 : ctx.pOutConfig = &hIvasRend->outputConfig;
444 3820 : ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
445 3820 : ctx.pHeadRotData = &hIvasRend->headRotData;
446 3820 : ctx.pSplitRendBFI = &hIvasRend->splitRendBFI;
447 3820 : ctx.pSplitRenderConfig = &hIvasRend->splitRenderConfig;
448 :
449 3820 : return ctx;
450 : }
451 :
452 :
453 1310872 : 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 1310872 : *numInChannels = 2;
462 :
463 1310872 : return IVAS_ERR_OK;
464 : }
465 :
466 :
467 3820 : 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 3820 : rendCtx = inputSplitPostRend->base.ctx;
480 3820 : isar_renderSplitGetMultiBinPoseData( hRendCfg, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, rendCtx.pHeadRotData->sr_pose_pred_axis );
481 :
482 3820 : config.high_res_mode_enabled = ( hRendCfg->lc3plus_highres != 0 );
483 3820 : config.lc3plus_frame_duration_us = hRendCfg->codec_frame_size_ms * 1000;
484 3820 : config.isar_frame_duration_us = hRendCfg->isar_frame_size_ms * 1000;
485 :
486 3820 : if ( hRendCfg->codec_frame_size_ms > 0 )
487 : {
488 3820 : iNumLCLDIterationsPerFrame = (int16_t) config.isar_frame_duration_us / ( 1000 * hRendCfg->codec_frame_size_ms );
489 3820 : iNumLCLDIterationsPerFrame = max( 1, iNumLCLDIterationsPerFrame );
490 3820 : 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 3820 : config.channels = BINAURAL_CHANNELS;
499 3820 : config.samplerate = *inputSplitPostRend->base.ctx.pOutSampleRate;
500 :
501 3820 : if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LCLD )
502 : {
503 2149 : 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 1671 : else if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS )
509 : {
510 1624 : if ( ( error = ISAR_LC3PLUS_DEC_Open( config, &inputSplitPostRend->splitPostRendWrapper.hLc3plusDec ) ) != IVAS_ERR_OK )
511 : {
512 0 : return error;
513 : }
514 : }
515 :
516 3820 : if ( ( error = isar_splitBinPostRendOpen( &inputSplitPostRend->splitPostRendWrapper.hBinHrSplitPostRend, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
517 : {
518 0 : return error;
519 : }
520 :
521 3820 : return IVAS_ERR_OK;
522 : }
523 :
524 :
525 3820 : 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 3820 : inputSplitPostRend = (input_split_post_rend *) input;
537 3820 : rendCtx = inputSplitPostRend->base.ctx;
538 3820 : outConfig = *rendCtx.pOutConfig;
539 :
540 3820 : if ( ( error = allocateInputBaseBufferData( &inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
541 : {
542 0 : return error;
543 : }
544 :
545 3820 : initRendInputBase( &inputSplitPostRend->base, inConfig, id, rendCtx, inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH );
546 3820 : inputSplitPostRend->numCachedSamples = 0;
547 :
548 3820 : if ( ( error = updateSplitPostRendPanGains( inputSplitPostRend, outConfig, hRendCfg ) ) != IVAS_ERR_OK )
549 : {
550 0 : return error;
551 : }
552 :
553 3820 : return IVAS_ERR_OK;
554 : }
555 :
556 :
557 3820 : static void clearInputSplitRend(
558 : input_split_post_rend *inputSplitRend )
559 : {
560 : rendering_context_isar rendCtx;
561 :
562 3820 : rendCtx = inputSplitRend->base.ctx;
563 :
564 3820 : freeInputBaseBufferData( &inputSplitRend->bufferData );
565 :
566 3820 : initRendInputBase( &inputSplitRend->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
567 :
568 3820 : if ( inputSplitRend->splitPostRendWrapper.hBinHrSplitPostRend != NULL )
569 : {
570 3820 : isar_splitBinPostRendClose( &inputSplitRend->splitPostRendWrapper.hBinHrSplitPostRend );
571 : }
572 :
573 3820 : if ( inputSplitRend->splitPostRendWrapper.hSplitBinLCLDDec != NULL )
574 : {
575 2149 : isar_splitBinLCLDDecClose( &inputSplitRend->splitPostRendWrapper.hSplitBinLCLDDec );
576 : }
577 :
578 3820 : if ( inputSplitRend->splitPostRendWrapper.hLc3plusDec != NULL )
579 : {
580 1624 : ISAR_LC3PLUS_DEC_Close( &inputSplitRend->splitPostRendWrapper.hLc3plusDec );
581 : }
582 :
583 3820 : return;
584 : }
585 :
586 :
587 : /*-------------------------------------------------------------------------
588 : * ISAR_POST_REND_open()
589 : *
590 : *
591 : *------------------------------------------------------------------------*/
592 :
593 3820 : 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 3820 : if ( phIvasRend == NULL )
614 : {
615 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
616 : }
617 :
618 3820 : if ( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ) != IVAS_ERR_OK )
619 : {
620 0 : return error;
621 : }
622 :
623 3820 : *phIvasRend = (ISAR_POST_REND_HANDLE) malloc( sizeof( struct ISAR_POST_REND ) );
624 3820 : if ( *phIvasRend == NULL )
625 : {
626 0 : return IVAS_ERR_FAILED_ALLOC;
627 : }
628 :
629 3820 : hIvasRend = *phIvasRend;
630 3820 : hIvasRend->sampleRateOut = outputSampleRate;
631 3820 : hIvasRend->outputConfig = outConfig;
632 3820 : hIvasRend->hLimiter = NULL;
633 3820 : hIvasRend->num_subframes = 1;
634 : #ifdef DEBUGGING
635 : hIvasRend->numClipping = 0;
636 : #endif
637 3820 : hIvasRend->num_subframes = num_subframes;
638 :
639 : /* Initialize limiter */
640 3820 : if ( ( error = ISAR_POST_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
641 : {
642 0 : return error;
643 : }
644 :
645 3820 : if ( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ) != IVAS_ERR_OK )
646 : {
647 0 : return error;
648 : }
649 :
650 : /* Initialize headrotation data */
651 3820 : if ( ( error = initHeadRotation( hIvasRend ) ) != IVAS_ERR_OK )
652 : {
653 0 : return error;
654 : }
655 :
656 : /* Initialize inputs */
657 :
658 7640 : for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; ++i )
659 : {
660 3820 : initRendInputBase( &hIvasRend->inputsSplitPost[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
661 :
662 3820 : isar_init_split_post_rend_handles( &hIvasRend->inputsSplitPost[i].splitPostRendWrapper );
663 :
664 3820 : hIvasRend->splitRendBFI = 0;
665 3820 : hIvasRend->inputsSplitPost[i].bufferData = NULL;
666 : }
667 :
668 3820 : return IVAS_ERR_OK;
669 : }
670 :
671 :
672 : /*-------------------------------------------------------------------*
673 : * ISAR_POST_REND_NumOutChannels()
674 : *
675 : *
676 : *-------------------------------------------------------------------*/
677 :
678 743416 : 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 743416 : if ( hIvasRend == NULL || numOutChannels == NULL )
685 : {
686 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
687 : }
688 :
689 743416 : *numOutChannels = 2;
690 :
691 743416 : return IVAS_ERR_OK;
692 : }
693 :
694 :
695 3820 : 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 3820 : return (IVAS_REND_InputId) ( ( ( (uint32_t) isar_getAudioConfigType( config ) ) << 8 ) | ( inputIndex + 1 ) );
703 : }
704 :
705 :
706 1307052 : 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 1307052 : inputIndex = ( inputId & 0xFF ) - 1;
717 1307052 : configType = ( inputId & 0xFF00 ) >> 8;
718 :
719 : /* Validate values derived from input ID */
720 1307052 : if ( inputIndex < 0 )
721 : {
722 0 : return IVAS_ERR_INVALID_INPUT_ID;
723 : }
724 1307052 : switch ( configType )
725 : {
726 1307052 : case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
727 1307052 : if ( inputIndex > RENDERER_MAX_BIN_INPUTS )
728 : {
729 0 : return IVAS_ERR_INVALID_INPUT_ID;
730 : }
731 1307052 : pInputBase = &hIvasRend->inputsSplitPost[inputIndex].base;
732 1307052 : 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 1307052 : 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 1307052 : *ppInput = pInputBase;
745 :
746 1307052 : 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 : return error;
774 : }
775 :
776 0 : inputBase->gain = gain;
777 :
778 0 : return IVAS_ERR_OK;
779 : }
780 :
781 :
782 657346 : static ivas_error getConstInputById(
783 : ISAR_POST_REND_CONST_HANDLE hIvasRend,
784 : const ISAR_POST_REND_InputId inputId,
785 : const void **ppInput )
786 : {
787 : int32_t inputIndex;
788 : IVAS_REND_AudioConfigType configType;
789 : const input_base_isar *pInputBase;
790 :
791 : /* Reverse makeInputId() */
792 657346 : inputIndex = ( inputId & 0xFF ) - 1;
793 657346 : configType = ( inputId & 0xFF00 ) >> 8;
794 :
795 : /* Validate values derived from input ID */
796 657346 : if ( inputIndex < 0 )
797 : {
798 0 : return IVAS_ERR_INVALID_INPUT_ID;
799 : }
800 657346 : switch ( configType )
801 : {
802 657346 : case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
803 657346 : if ( inputIndex > RENDERER_MAX_BIN_INPUTS )
804 : {
805 0 : return IVAS_ERR_INVALID_INPUT_ID;
806 : }
807 657346 : pInputBase = &hIvasRend->inputsSplitPost[inputIndex].base;
808 657346 : break;
809 0 : default:
810 0 : return IVAS_ERR_INVALID_INPUT_ID;
811 : }
812 :
813 : /* Ensure input ID matches and that input is active */
814 657346 : if ( pInputBase->id != inputId || pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
815 : {
816 0 : return IVAS_ERR_INVALID_INPUT_ID;
817 : }
818 :
819 : /* Validation done, set value via output parameter */
820 657346 : *ppInput = pInputBase;
821 :
822 657346 : return IVAS_ERR_OK;
823 : }
824 :
825 :
826 3820 : static ivas_error findFreeInputSlot(
827 : const void *inputs,
828 : const int32_t inputStructSize,
829 : const int32_t maxInputs,
830 : int32_t *inputIndex )
831 : {
832 : /* Using a void pointer and a separately provided size is a hack for this function
833 : to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
834 : Assumptions:
835 : - input_base_isar is always the first member in the input struct
836 : - provided size is correct
837 : */
838 :
839 : int32_t i;
840 : bool canAddInput;
841 : const uint8_t *pByte;
842 : const input_base_isar *pInputBase;
843 :
844 3820 : canAddInput = false;
845 :
846 : /* Find first unused input in array */
847 3820 : for ( i = 0, pByte = inputs; i < maxInputs; ++i, pByte += inputStructSize )
848 : {
849 3820 : pInputBase = (const input_base_isar *) pByte;
850 :
851 3820 : if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
852 : {
853 3820 : *inputIndex = i;
854 3820 : canAddInput = true;
855 3820 : break;
856 : }
857 : }
858 :
859 3820 : if ( !canAddInput )
860 : {
861 0 : return IVAS_ERR_TOO_MANY_INPUTS;
862 : }
863 :
864 3820 : return IVAS_ERR_OK;
865 : }
866 :
867 :
868 : /*-------------------------------------------------------------------*
869 : * ISAR_POST_REND_AddInput()
870 : *
871 : *
872 : *-------------------------------------------------------------------*/
873 :
874 3820 : ivas_error ISAR_POST_REND_AddInput(
875 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
876 : const IVAS_AUDIO_CONFIG inConfig, /* i : audio config for a new input */
877 : ISAR_POST_REND_InputId *inputId /* o : ID of the new input */
878 : )
879 : {
880 : ivas_error error;
881 : int32_t maxNumInputsOfType;
882 : void *inputsArray;
883 : int32_t inputStructSize;
884 :
885 : ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, ISAR_SPLIT_REND_CONFIG_DATA * );
886 : int32_t inputIndex;
887 :
888 : /* Validate function arguments */
889 3820 : if ( hIvasRend == NULL || inputId == NULL )
890 : {
891 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
892 : }
893 :
894 3820 : switch ( isar_getAudioConfigType( inConfig ) )
895 : {
896 3820 : case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
897 3820 : maxNumInputsOfType = RENDERER_MAX_BIN_INPUTS;
898 3820 : inputsArray = hIvasRend->inputsSplitPost;
899 3820 : inputStructSize = sizeof( *hIvasRend->inputsSplitPost );
900 3820 : activateInput = setRendInputActiveSplitPostRend;
901 3820 : break;
902 0 : default:
903 0 : return IVAS_ERR_INVALID_INPUT_FORMAT;
904 : }
905 :
906 : /* Find first free input in array corresponding to input type */
907 3820 : if ( ( error = findFreeInputSlot( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
908 : {
909 0 : return error;
910 : }
911 :
912 3820 : *inputId = makeInputId( inConfig, inputIndex );
913 :
914 3820 : if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, &hIvasRend->splitRenderConfig ) ) != IVAS_ERR_OK )
915 : {
916 0 : return error;
917 : }
918 :
919 3820 : return IVAS_ERR_OK;
920 : }
921 :
922 :
923 : /*-------------------------------------------------------------------*
924 : * ISAR_POST_REND_GetInputNumChannels()
925 : *
926 : *
927 : *-------------------------------------------------------------------*/
928 :
929 657346 : ivas_error ISAR_POST_REND_GetInputNumChannels(
930 : ISAR_POST_REND_CONST_HANDLE hIvasRend, /* i : Renderer handle */
931 : const ISAR_POST_REND_InputId inputId, /* i : ID of the input */
932 : int16_t *numChannels /* o : number of channels of the input */
933 : )
934 : {
935 : ivas_error error;
936 : const input_base_isar *pInput;
937 :
938 : /* Validate function arguments */
939 657346 : if ( hIvasRend == NULL || numChannels == NULL )
940 : {
941 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
942 : }
943 :
944 657346 : if ( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ) != IVAS_ERR_OK )
945 : {
946 0 : return error;
947 : }
948 :
949 657346 : if ( ( error = getRendInputNumChannels( pInput, numChannels ) ) != IVAS_ERR_OK )
950 : {
951 0 : return error;
952 : }
953 :
954 657346 : return IVAS_ERR_OK;
955 : }
956 :
957 :
958 : /*-------------------------------------------------------------------*
959 : * ISAR_POST_REND_GetDelay()
960 : *
961 : *
962 : *-------------------------------------------------------------------*/
963 :
964 3820 : ivas_error ISAR_POST_REND_GetDelay(
965 : ISAR_POST_REND_CONST_HANDLE hIvasRend, /* i : Renderer state */
966 : int16_t *nSamples, /* o : Renderer delay in samples */
967 : int32_t *timeScale /* o : Time scale of the delay, equal to renderer output sampling rate */
968 : )
969 : {
970 : int16_t i;
971 : int32_t latency_ns;
972 : int32_t max_latency_ns;
973 :
974 : /* Validate function arguments */
975 3820 : if ( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
976 : {
977 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
978 : }
979 :
980 3820 : *timeScale = hIvasRend->sampleRateOut;
981 3820 : *nSamples = 0;
982 3820 : max_latency_ns = 0;
983 :
984 : /* Compute the maximum delay across all inputs */
985 7640 : for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; i++ )
986 : {
987 3820 : if ( hIvasRend->inputsSplitPost[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
988 : {
989 3820 : latency_ns = 0;
990 3820 : if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hLc3plusDec != NULL )
991 : {
992 : int32_t lc3plusDelaySamples;
993 1624 : ISAR_LC3PLUS_DEC_GetDelay( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hLc3plusDec, &lc3plusDelaySamples );
994 1624 : latency_ns = (int32_t) roundf( lc3plusDelaySamples * 1000000000.f / *timeScale );
995 : }
996 3820 : if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
997 : {
998 2590 : latency_ns += IVAS_FB_DEC_DELAY_NS;
999 : }
1000 1230 : else if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hSplitBinLCLDDec != NULL )
1001 : {
1002 780 : latency_ns += IVAS_FB_DEC_DELAY_NS;
1003 : }
1004 3820 : max_latency_ns = max( max_latency_ns, latency_ns );
1005 : }
1006 : }
1007 :
1008 3820 : *nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
1009 :
1010 3820 : return IVAS_ERR_OK;
1011 : }
1012 :
1013 :
1014 : /*-------------------------------------------------------------------*
1015 : * ISAR_POST_REND_FeedInputAudio()
1016 : *
1017 : *
1018 : *-------------------------------------------------------------------*/
1019 :
1020 653526 : ivas_error ISAR_POST_REND_FeedInputAudio(
1021 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1022 : const ISAR_POST_REND_InputId inputId, /* i : ID of the input */
1023 : const ISAR_POST_REND_ReadOnlyAudioBuffer inputAudio /* i : buffer with input audio */
1024 : )
1025 : {
1026 : ivas_error error;
1027 : input_base_isar *inputBase;
1028 : int16_t numInputChannels;
1029 : int16_t cldfb2tdSampleFact;
1030 :
1031 : /* Validate function arguments */
1032 653526 : if ( hIvasRend == NULL || inputAudio.data == NULL )
1033 : {
1034 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1035 : }
1036 :
1037 653526 : cldfb2tdSampleFact = ( inputAudio.config.is_cldfb ) ? 2 : 1;
1038 :
1039 653526 : if ( inputAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
1040 653526 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 1 ) )
1041 : {
1042 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
1043 : }
1044 :
1045 653526 : if ( inputAudio.config.numChannels <= 0 || MAX_INPUT_CHANNELS < inputAudio.config.numChannels )
1046 : {
1047 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1048 : }
1049 :
1050 653526 : if ( isar_getAudioConfigType( hIvasRend->outputConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
1051 653526 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
1052 653526 : hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
1053 653526 : ( inputAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( BINAURAL_RENDERING_FRAME_SIZE_MS * hIvasRend->num_subframes ) * hIvasRend->sampleRateOut )
1054 : {
1055 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
1056 : }
1057 :
1058 653526 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
1059 : {
1060 0 : return error;
1061 : }
1062 :
1063 653526 : if ( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ) != IVAS_ERR_OK )
1064 : {
1065 0 : return error;
1066 : }
1067 :
1068 653526 : if ( numInputChannels != inputAudio.config.numChannels )
1069 : {
1070 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1071 : }
1072 :
1073 653526 : inputBase->inputBuffer.config = inputAudio.config;
1074 :
1075 653526 : mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
1076 :
1077 653526 : inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact;
1078 :
1079 653526 : return IVAS_ERR_OK;
1080 : }
1081 :
1082 :
1083 : /*-------------------------------------------------------------------*
1084 : * ISAR_POST_REND_InitConfig()
1085 : *
1086 : *
1087 : *-------------------------------------------------------------------*/
1088 :
1089 3820 : ivas_error ISAR_POST_REND_InitConfig(
1090 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1091 : const AUDIO_CONFIG outAudioConfig /* i : output audioConfig */
1092 : )
1093 : {
1094 : bool rendererConfigEnabled;
1095 :
1096 3820 : rendererConfigEnabled = ( isar_getAudioConfigType( outAudioConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL );
1097 :
1098 3820 : if ( rendererConfigEnabled )
1099 : {
1100 3820 : hIvasRend->rendererConfigEnabled = 1;
1101 : }
1102 : else
1103 : {
1104 0 : hIvasRend->rendererConfigEnabled = 0;
1105 : }
1106 :
1107 3820 : if ( rendererConfigEnabled )
1108 : {
1109 3820 : hIvasRend->splitRenderConfig.splitRendBitRate = SPLIT_REND_768k;
1110 3820 : hIvasRend->splitRenderConfig.dof = 3;
1111 3820 : hIvasRend->splitRenderConfig.hq_mode = 0;
1112 3820 : hIvasRend->splitRenderConfig.codec_delay_ms = 0;
1113 3820 : hIvasRend->splitRenderConfig.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1114 3820 : hIvasRend->splitRenderConfig.isar_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1115 3820 : hIvasRend->splitRenderConfig.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
1116 3820 : hIvasRend->splitRenderConfig.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
1117 3820 : hIvasRend->splitRenderConfig.rendererSelection = IVAS_BIN_RENDERER_TYPE_DEFAULT;
1118 : }
1119 :
1120 3820 : return IVAS_ERR_OK;
1121 : }
1122 :
1123 :
1124 : /*-------------------------------------------------------------------*
1125 : * ISAR_POST_REND_GetRenderConfig()
1126 : *
1127 : *
1128 : *-------------------------------------------------------------------*/
1129 :
1130 0 : int16_t ISAR_POST_REND_GetRenderConfig(
1131 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: IVAS decoder handle */
1132 : const ISAR_SPLIT_REND_CONFIG_HANDLE splitRenderConfig /* o : Render configuration handle */
1133 : )
1134 : {
1135 : ISAR_SPLIT_REND_CONFIG_DATA hRCin;
1136 :
1137 0 : if ( hIvasRend == NULL )
1138 : {
1139 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1140 : }
1141 :
1142 0 : hRCin = hIvasRend->splitRenderConfig;
1143 :
1144 0 : splitRenderConfig->splitRendBitRate = SPLIT_REND_768k;
1145 0 : splitRenderConfig->dof = 3;
1146 0 : splitRenderConfig->hq_mode = 0;
1147 0 : splitRenderConfig->codec_delay_ms = 0;
1148 0 : splitRenderConfig->codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1149 0 : splitRenderConfig->isar_frame_size_ms = 0; /* 0 means "use default for selected codec" */
1150 0 : splitRenderConfig->codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
1151 0 : splitRenderConfig->poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
1152 0 : splitRenderConfig->rendererSelection = hRCin.rendererSelection;
1153 :
1154 0 : return IVAS_ERR_OK;
1155 : }
1156 :
1157 :
1158 : /*-------------------------------------------------------------------*
1159 : * ISAR_POST_REND_FeedSplitBinauralBitstream()
1160 : *
1161 : *
1162 : *-------------------------------------------------------------------*/
1163 :
1164 653526 : ivas_error ISAR_POST_REND_FeedSplitBinauralBitstream(
1165 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1166 : const IVAS_REND_InputId inputId, /* i : ID of the input */
1167 : ISAR_POST_REND_BitstreamBuffer *hBits /* i : buffer for input bitstream */
1168 : )
1169 : {
1170 : ivas_error error;
1171 : input_base_isar *inputBase;
1172 : input_split_post_rend *inputSplitPostRend;
1173 :
1174 : /* Validate function arguments */
1175 653526 : if ( hIvasRend == NULL || hBits == NULL )
1176 : {
1177 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1178 : }
1179 :
1180 653526 : if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
1181 : {
1182 0 : return error;
1183 : }
1184 :
1185 653526 : inputSplitPostRend = (input_split_post_rend *) inputBase;
1186 653526 : inputSplitPostRend->hBits = hBits;
1187 :
1188 653526 : return IVAS_ERR_OK;
1189 : }
1190 :
1191 :
1192 : /*-------------------------------------------------------------------*
1193 : * ISAR_POST_REND_SetHeadRotation()
1194 : *
1195 : *
1196 : *-------------------------------------------------------------------*/
1197 :
1198 2476380 : ivas_error ISAR_POST_REND_SetHeadRotation(
1199 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1200 : const IVAS_QUATERNION headRot, /* i : head orientations for next rendering call */
1201 : const IVAS_VECTOR3 Pos, /* i : listener positions for next rendering call */
1202 : const ISAR_SPLIT_REND_ROT_AXIS rot_axis, /* i : external control for rotation axis for split rendering */
1203 : const int16_t sf_idx /* i : subframe index */
1204 : )
1205 : {
1206 : IVAS_QUATERNION rotQuat;
1207 :
1208 : /* Validate function arguments */
1209 2476380 : if ( hIvasRend == NULL )
1210 : {
1211 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1212 : }
1213 :
1214 2476380 : if ( isar_getAudioConfigType( hIvasRend->outputConfig ) != ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL )
1215 : {
1216 : /* Head rotation can be set only with binaural output */
1217 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
1218 : }
1219 :
1220 2476380 : hIvasRend->headRotData.headRotEnabled = 1;
1221 :
1222 : /* check for Euler angle signaling */
1223 2476380 : if ( headRot.w == -3.0f )
1224 : {
1225 1959980 : Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat );
1226 : }
1227 : else
1228 : {
1229 516400 : rotQuat = headRot;
1230 : }
1231 :
1232 2476380 : hIvasRend->headRotData.headPositions[sf_idx] = rotQuat;
1233 2476380 : hIvasRend->headRotData.Pos[sf_idx] = Pos;
1234 2476380 : hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
1235 :
1236 2476380 : return IVAS_ERR_OK;
1237 : }
1238 :
1239 :
1240 : /*-------------------------------------------------------------------*
1241 : * ISAR_POST_REND_SetSplitRendBFI()
1242 : *
1243 : *
1244 : *-------------------------------------------------------------------*/
1245 :
1246 668140 : ivas_error ISAR_POST_REND_SetSplitRendBFI(
1247 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1248 : const int16_t bfi /* i : BFI flag */
1249 : )
1250 : {
1251 668140 : hIvasRend->splitRendBFI = bfi;
1252 :
1253 668140 : return IVAS_ERR_OK;
1254 : }
1255 :
1256 :
1257 : /*-------------------------------------------------------------------*
1258 : * Local functions
1259 : *-------------------------------------------------------------------*/
1260 :
1261 292074 : static ivas_error splitBinLc3plusDecode(
1262 : ISAR_SPLIT_POST_REND_WRAPPER *hSplitBin,
1263 : ISAR_SPLIT_REND_BITS_HANDLE bits,
1264 : float outputBuffer[BINAURAL_CHANNELS][L_FRAME48k],
1265 : const int16_t SplitRendBFI )
1266 : {
1267 : ivas_error error;
1268 : float *channel_ptrs[MAX_HEAD_ROT_POSES * 2];
1269 : int32_t lc3plusBitstreamSize;
1270 :
1271 292074 : push_wmops( "splitBinLc3plusDecode" );
1272 292074 : assert( hSplitBin->hLc3plusDec != NULL );
1273 :
1274 3334598 : for ( int16_t i = 0; i < BINAURAL_CHANNELS * hSplitBin->multiBinPoseData.num_poses; ++i )
1275 : {
1276 3042524 : channel_ptrs[i] = outputBuffer[i];
1277 : }
1278 :
1279 292074 : if ( SplitRendBFI == 0 )
1280 : {
1281 : /* Find next byte boundary */
1282 968390 : while ( bits->bits_read % 8 != 0 )
1283 : {
1284 678168 : ++bits->bits_read;
1285 : }
1286 :
1287 : /* Size is in bytes */
1288 290222 : assert( ( bits->bits_written - bits->bits_read ) % 8 == 0 );
1289 290222 : lc3plusBitstreamSize = ( bits->bits_written - bits->bits_read ) / 8;
1290 :
1291 290222 : if ( ( error = ISAR_LC3PLUS_DEC_Decode( hSplitBin->hLc3plusDec, &bits->bits_buf[bits->bits_read / 8], lc3plusBitstreamSize, channel_ptrs ) ) != IVAS_ERR_OK )
1292 : {
1293 0 : return error;
1294 : }
1295 : }
1296 : else
1297 : {
1298 1852 : if ( ( error = ISAR_LC3PLUS_DEC_Conceal( hSplitBin->hLc3plusDec, channel_ptrs ) ) != IVAS_ERR_OK )
1299 : {
1300 0 : return error;
1301 : }
1302 : }
1303 :
1304 292074 : pop_wmops();
1305 292074 : return IVAS_ERR_OK;
1306 : }
1307 :
1308 :
1309 739596 : static ivas_error renderSplitBinauralWithPostRot(
1310 : input_split_post_rend *splitBinInput,
1311 : IVAS_REND_AudioBuffer outAudio,
1312 : const int16_t SplitRendBFI,
1313 : const int16_t num_subframes )
1314 : {
1315 : float Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
1316 : float Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
1317 : ivas_error error;
1318 : float Cldfb_RealBuffer_Binaural_5ms[MAX_PARAM_SPATIAL_SUBFRAMES][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX];
1319 : float Cldfb_ImagBuffer_Binaural_5ms[MAX_PARAM_SPATIAL_SUBFRAMES][BINAURAL_CHANNELS][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX];
1320 : IVAS_QUATERNION QuaternionsPost[MAX_PARAM_SPATIAL_SUBFRAMES];
1321 : int16_t sf_idx, ch_idx;
1322 : ISAR_SPLIT_REND_BITS_DATA bits;
1323 : float tmpCrendBuffer[BINAURAL_CHANNELS][L_FRAME48k];
1324 : float tmpCrendBuffer_sf[BINAURAL_CHANNELS][L_FRAME48k];
1325 : ISAR_SPLIT_POST_REND_WRAPPER *hSplitBin;
1326 : int8_t isPostRendInputCldfb;
1327 : int16_t chnlIdx, slotIdx, smplIdx;
1328 : int16_t preRendFrameSize_ms;
1329 : int16_t outBufNumSamplesPerChannel, outBufNumColPerChannel;
1330 : int16_t numSamplesPerChannelCacheSize, numColPerChannelCacheSize;
1331 : float *readPtr, *writePtr;
1332 : int16_t iNumBlocksPerFrame, iNumLCLDIterationsPerFrame;
1333 : const ISAR_POST_REND_HeadRotData *pHeadRotData;
1334 :
1335 739596 : isPostRendInputCldfb = 0;
1336 739596 : push_wmops( "renderSplitBinauralWithPostRot" );
1337 739596 : error = IVAS_ERR_OK;
1338 :
1339 739596 : if ( outAudio.config.numSamplesPerChannel / *splitBinInput->base.ctx.pOutSampleRate > splitBinInput->hBits->config.isar_frame_size_ms )
1340 : {
1341 0 : return IVAS_ERR_INTERNAL_FATAL;
1342 : }
1343 :
1344 739596 : pHeadRotData = splitBinInput->base.ctx.pHeadRotData;
1345 739596 : hSplitBin = &splitBinInput->splitPostRendWrapper;
1346 739596 : convertBitsBufferToInternalBitsBuff( *splitBinInput->hBits, &bits );
1347 :
1348 739596 : iNumLCLDIterationsPerFrame = 1;
1349 739596 : iNumBlocksPerFrame = CLDFB_NO_COL_MAX;
1350 739596 : if ( splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec != NULL )
1351 : {
1352 373837 : iNumBlocksPerFrame = splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec->iNumBlocks;
1353 373837 : iNumLCLDIterationsPerFrame = splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec->iNumIterations;
1354 : }
1355 :
1356 739596 : outBufNumSamplesPerChannel = outAudio.config.numSamplesPerChannel / num_subframes;
1357 3215976 : for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
1358 : {
1359 2476380 : QuaternionsPost[sf_idx] = pHeadRotData->headPositions[sf_idx];
1360 : }
1361 :
1362 739596 : if ( !SplitRendBFI )
1363 : {
1364 721032 : hSplitBin->first_good_frame_received = 1;
1365 : }
1366 :
1367 739596 : if ( hSplitBin->first_good_frame_received == 1 )
1368 : {
1369 723357 : if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
1370 : {
1371 443013 : if ( !SplitRendBFI )
1372 : {
1373 : #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG
1374 : isar_splitBinPostRendMdDec( &bits, hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData, hSplitBin->hBinHrSplitPreRend );
1375 : #else
1376 440688 : isar_splitBinPostRendMdDec( &bits, hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData );
1377 : #endif
1378 : }
1379 : }
1380 :
1381 : /*copy pose correction after MD is parsed*/
1382 723357 : hSplitBin->multiBinPoseData.poseCorrectionMode = bits.pose_correction;
1383 :
1384 : /* decode audio */
1385 723357 : if ( splitBinInput->base.inConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
1386 : {
1387 712428 : if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
1388 : {
1389 364054 : isPostRendInputCldfb = 1;
1390 : }
1391 :
1392 712428 : numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outBufNumSamplesPerChannel;
1393 :
1394 712428 : outBufNumColPerChannel = MAX_PARAM_SPATIAL_SUBFRAMES;
1395 712428 : numColPerChannelCacheSize = ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ) - outBufNumColPerChannel;
1396 :
1397 3089208 : for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
1398 : {
1399 2376780 : if ( splitBinInput->numCachedSamples == 0 )
1400 : {
1401 627978 : if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
1402 : {
1403 335904 : isar_splitBinLCLDDecProcess( hSplitBin->hSplitBinLCLDDec, &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, SplitRendBFI );
1404 :
1405 : /* copy data over to 5ms buffer */
1406 1007712 : for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
1407 : {
1408 3359040 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; ++slotIdx )
1409 : {
1410 2687232 : mvr2r( Cldfb_RealBuffer_Binaural[chnlIdx][slotIdx], Cldfb_RealBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx], CLDFB_NO_CHANNELS_MAX );
1411 2687232 : mvr2r( Cldfb_ImagBuffer_Binaural[chnlIdx][slotIdx], Cldfb_ImagBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx], CLDFB_NO_CHANNELS_MAX );
1412 : }
1413 : }
1414 :
1415 : /* cache the remaining 15ms */
1416 335904 : splitBinInput->numCachedSamples = numColPerChannelCacheSize;
1417 335904 : writePtr = splitBinInput->bufferData;
1418 4141528 : for ( slotIdx = CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; slotIdx < ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ); ++slotIdx )
1419 : {
1420 11416872 : for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
1421 : {
1422 464286128 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1423 : {
1424 456674880 : *writePtr++ = Cldfb_RealBuffer_Binaural[chnlIdx][slotIdx][smplIdx];
1425 : }
1426 464286128 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1427 : {
1428 456674880 : *writePtr++ = Cldfb_ImagBuffer_Binaural[chnlIdx][slotIdx][smplIdx];
1429 : }
1430 : }
1431 : }
1432 : }
1433 : else
1434 : {
1435 292074 : if ( ( error = splitBinLc3plusDecode( hSplitBin, &bits, tmpCrendBuffer, SplitRendBFI ) ) != IVAS_ERR_OK )
1436 : {
1437 0 : return error;
1438 : }
1439 :
1440 : /* cache the remaining decoded audio */
1441 292074 : splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
1442 292074 : mvr2r( &tmpCrendBuffer[0][outBufNumSamplesPerChannel], splitBinInput->bufferData, numSamplesPerChannelCacheSize );
1443 292074 : mvr2r( &tmpCrendBuffer[1][outBufNumSamplesPerChannel], splitBinInput->bufferData + numSamplesPerChannelCacheSize, numSamplesPerChannelCacheSize );
1444 : }
1445 : }
1446 : else
1447 : {
1448 : /* copy from cache */
1449 1748802 : if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
1450 : {
1451 951406 : int16_t readOffset = ( numColPerChannelCacheSize - splitBinInput->numCachedSamples );
1452 951406 : readPtr = splitBinInput->bufferData;
1453 951406 : isPostRendInputCldfb = 1;
1454 :
1455 951406 : readPtr += 2 * readOffset * CLDFB_NO_CHANNELS_MAX * BINAURAL_CHANNELS;
1456 4757030 : for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; ++slotIdx )
1457 : {
1458 11416872 : for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
1459 : {
1460 464286128 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1461 : {
1462 456674880 : Cldfb_RealBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx][smplIdx] = *readPtr++;
1463 : }
1464 464286128 : for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
1465 : {
1466 456674880 : Cldfb_ImagBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx][smplIdx] = *readPtr++;
1467 : }
1468 : }
1469 : }
1470 :
1471 951406 : splitBinInput->numCachedSamples -= outBufNumColPerChannel;
1472 : }
1473 : else
1474 : {
1475 797396 : int16_t readOffset = numSamplesPerChannelCacheSize - splitBinInput->numCachedSamples;
1476 797396 : mvr2r( splitBinInput->bufferData + readOffset, &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1477 797396 : mvr2r( splitBinInput->bufferData + readOffset + numSamplesPerChannelCacheSize, &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1478 797396 : splitBinInput->numCachedSamples -= outBufNumSamplesPerChannel;
1479 : }
1480 : }
1481 : }
1482 : }
1483 : else
1484 : {
1485 10929 : copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer );
1486 10929 : if ( splitBinInput->numCachedSamples == 0 )
1487 : {
1488 10929 : preRendFrameSize_ms = splitBinInput->base.ctx.pSplitRenderConfig->isar_frame_size_ms;
1489 10929 : numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * preRendFrameSize_ms / 1000 );
1490 10929 : numSamplesPerChannelCacheSize -= outAudio.config.numSamplesPerChannel;
1491 10929 : splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
1492 : }
1493 : else
1494 : {
1495 0 : splitBinInput->numCachedSamples -= outAudio.config.numSamplesPerChannel;
1496 : }
1497 : }
1498 :
1499 : /* apply pose correction if enabled */
1500 3143853 : for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
1501 : {
1502 2420496 : if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE && isPostRendInputCldfb )
1503 466102 : {
1504 : /* 0DOF with LCLD codec requires CLDFB synthesis */
1505 : int16_t slot_idx;
1506 :
1507 1398306 : for ( ch_idx = 0; ch_idx < BINAURAL_CHANNELS; ch_idx++ )
1508 : {
1509 : float *RealBuffer[CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES];
1510 : float *ImagBuffer[CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES];
1511 :
1512 4661020 : for ( slot_idx = 0; slot_idx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; slot_idx++ )
1513 : {
1514 3728816 : RealBuffer[slot_idx] = Cldfb_RealBuffer_Binaural_5ms[sf_idx][ch_idx][slot_idx];
1515 3728816 : ImagBuffer[slot_idx] = Cldfb_ImagBuffer_Binaural_5ms[sf_idx][ch_idx][slot_idx];
1516 : }
1517 :
1518 932204 : cldfbSynthesis( RealBuffer,
1519 : ImagBuffer,
1520 932204 : &( tmpCrendBuffer[ch_idx][sf_idx * outBufNumSamplesPerChannel] ),
1521 932204 : hSplitBin->hBinHrSplitPostRend->cldfbSyn[0]->no_channels * CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
1522 932204 : hSplitBin->hBinHrSplitPostRend->cldfbSyn[ch_idx] );
1523 : }
1524 : }
1525 1954394 : else if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
1526 : {
1527 1636932 : mvr2r( &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], tmpCrendBuffer_sf[0], outBufNumSamplesPerChannel );
1528 1636932 : mvr2r( &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], tmpCrendBuffer_sf[1], outBufNumSamplesPerChannel );
1529 :
1530 1636932 : 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 );
1531 :
1532 1636932 : mvr2r( tmpCrendBuffer_sf[0], &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1533 1636932 : mvr2r( tmpCrendBuffer_sf[1], &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
1534 : }
1535 : }
1536 : }
1537 : else
1538 : {
1539 16239 : if ( splitBinInput->numCachedSamples == 0 )
1540 : {
1541 14619 : numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outAudio.config.numSamplesPerChannel;
1542 14619 : splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
1543 : }
1544 : else
1545 : {
1546 1620 : splitBinInput->numCachedSamples -= outAudio.config.numSamplesPerChannel;
1547 : }
1548 :
1549 16239 : if ( splitBinInput->base.inConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
1550 : {
1551 48276 : for ( ch_idx = 0; ch_idx < BINAURAL_CHANNELS; ch_idx++ )
1552 : {
1553 32184 : set_zero( tmpCrendBuffer[ch_idx], outAudio.config.numSamplesPerChannel );
1554 : }
1555 : }
1556 : else
1557 : {
1558 147 : copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer );
1559 : }
1560 : }
1561 :
1562 739596 : convertInternalBitsBuffToBitsBuffer( splitBinInput->hBits, bits );
1563 739596 : accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
1564 :
1565 739596 : pop_wmops();
1566 739596 : return error;
1567 : }
1568 :
1569 :
1570 739596 : static ivas_error renderInputSplitBin(
1571 : input_split_post_rend *splitBinInput,
1572 : const AUDIO_CONFIG outConfig,
1573 : IVAS_REND_AudioBuffer outAudio,
1574 : const int16_t SplitRendBFI,
1575 : const int16_t num_subframes )
1576 : {
1577 : ivas_error error;
1578 : IVAS_REND_AudioBuffer inAudio;
1579 :
1580 739596 : inAudio = splitBinInput->base.inputBuffer;
1581 :
1582 739596 : splitBinInput->base.numNewSamplesPerChannel = 0;
1583 :
1584 : /* Apply input gain to new audio */
1585 739596 : v_multc( inAudio.data,
1586 : splitBinInput->base.gain,
1587 : inAudio.data,
1588 739596 : inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
1589 739596 : switch ( outConfig )
1590 : {
1591 739596 : case IVAS_AUDIO_CONFIG_BINAURAL:
1592 739596 : error = renderSplitBinauralWithPostRot( splitBinInput, outAudio, SplitRendBFI, num_subframes );
1593 739596 : break;
1594 0 : default:
1595 0 : return IVAS_ERR_INVALID_OUTPUT_FORMAT;
1596 : }
1597 :
1598 739596 : return error;
1599 : }
1600 :
1601 :
1602 739596 : static ivas_error renderActiveInputsSplitBin(
1603 : ISAR_POST_REND_HANDLE hIvasRend,
1604 : IVAS_REND_AudioBuffer outAudio )
1605 : {
1606 : int16_t i;
1607 : input_split_post_rend *pCurrentInput;
1608 : ivas_error error;
1609 :
1610 1479192 : for ( i = 0, pCurrentInput = hIvasRend->inputsSplitPost; i < RENDERER_MAX_BIN_INPUTS; ++i, ++pCurrentInput )
1611 : {
1612 739596 : if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
1613 : {
1614 : /* Skip inactive inputs */
1615 0 : continue;
1616 : }
1617 :
1618 739596 : if ( ( error = renderInputSplitBin( pCurrentInput, hIvasRend->outputConfig, outAudio, hIvasRend->splitRendBFI, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
1619 : {
1620 0 : return error;
1621 : }
1622 : }
1623 :
1624 739596 : return IVAS_ERR_OK;
1625 : }
1626 :
1627 :
1628 : /*-------------------------------------------------------------------*
1629 : * ISAR_POST_REND_getSamples()
1630 : *
1631 : *
1632 : *-------------------------------------------------------------------*/
1633 :
1634 739596 : ivas_error ISAR_POST_REND_getSamples(
1635 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1636 : IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio */
1637 : )
1638 : {
1639 : ivas_error error;
1640 : int16_t numOutChannels;
1641 : int16_t cldfb2tdSampleFact;
1642 :
1643 : /* Validate function arguments */
1644 739596 : if ( hIvasRend == NULL || outAudio.data == NULL )
1645 : {
1646 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1647 : }
1648 :
1649 739596 : cldfb2tdSampleFact = ( outAudio.config.is_cldfb ) ? 2 : 1;
1650 :
1651 739596 : if ( outAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
1652 739596 : ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
1653 : {
1654 0 : return IVAS_ERR_INVALID_BUFFER_SIZE;
1655 : }
1656 :
1657 739596 : if ( outAudio.config.numChannels <= 0 || MAX_OUTPUT_CHANNELS < outAudio.config.numChannels )
1658 : {
1659 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1660 : }
1661 :
1662 739596 : if ( isar_getAudioConfigType( hIvasRend->outputConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
1663 739596 : ( outAudio.config.numSamplesPerChannel * 1000 / cldfb2tdSampleFact ) != ( hIvasRend->num_subframes * BINAURAL_RENDERING_FRAME_SIZE_MS ) * hIvasRend->sampleRateOut )
1664 : {
1665 0 : return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
1666 : }
1667 :
1668 739596 : if ( ( error = ISAR_POST_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
1669 : {
1670 0 : return error;
1671 : }
1672 :
1673 739596 : if ( numOutChannels != outAudio.config.numChannels && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED && hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM )
1674 : {
1675 0 : return IVAS_ERR_WRONG_NUM_CHANNELS;
1676 : }
1677 :
1678 : /* Clear original output buffer */
1679 739596 : set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
1680 :
1681 739596 : if ( ( error = renderActiveInputsSplitBin( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
1682 : {
1683 0 : return error;
1684 : }
1685 :
1686 : #ifndef DISABLE_LIMITER
1687 : #ifdef DEBUGGING
1688 : hIvasRend->numClipping +=
1689 : #endif
1690 739596 : limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
1691 : #endif
1692 :
1693 739596 : return IVAS_ERR_OK;
1694 : }
1695 :
1696 :
1697 : /*-------------------------------------------------------------------*
1698 : * ISAR_POST_REND_GetSplitBinauralSamples()
1699 : *
1700 : *
1701 : *-------------------------------------------------------------------*/
1702 :
1703 739596 : ivas_error ISAR_POST_REND_GetSplitBinauralSamples(
1704 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: Renderer handle */
1705 : IVAS_REND_AudioBuffer outAudio, /* i/o: buffer for output audio */
1706 : bool *needNewFrame )
1707 : {
1708 : ivas_error error;
1709 :
1710 739596 : if ( ( error = ISAR_POST_REND_getSamples( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
1711 : {
1712 0 : return error;
1713 : }
1714 739596 : *needNewFrame = hIvasRend->inputsSplitPost[0].numCachedSamples == 0;
1715 :
1716 739596 : return IVAS_ERR_OK;
1717 : }
1718 :
1719 :
1720 : /*-------------------------------------------------------------------*
1721 : * ISAR_POST_REND_Close()
1722 : *
1723 : *
1724 : *-------------------------------------------------------------------*/
1725 :
1726 3820 : void ISAR_POST_REND_Close(
1727 : ISAR_POST_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
1728 : )
1729 : {
1730 : uint16_t i;
1731 : ISAR_POST_REND_HANDLE hIvasRend;
1732 :
1733 : /* Validate function arguments */
1734 3820 : if ( phIvasRend == NULL || *phIvasRend == NULL )
1735 : {
1736 0 : return;
1737 : }
1738 3820 : hIvasRend = *phIvasRend;
1739 :
1740 7640 : for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; ++i )
1741 : {
1742 3820 : clearInputSplitRend( &hIvasRend->inputsSplitPost[i] );
1743 : }
1744 :
1745 3820 : ivas_limiter_close( &hIvasRend->hLimiter );
1746 :
1747 3820 : free( hIvasRend );
1748 3820 : *phIvasRend = NULL;
1749 :
1750 3820 : return;
1751 : }
1752 :
1753 :
1754 : /*-------------------------------------------------------------------*
1755 : * ISAR_REND_SetSplitRendBitstreamHeader()
1756 : *
1757 : *
1758 : *-------------------------------------------------------------------*/
1759 :
1760 3820 : ivas_error ISAR_REND_SetSplitRendBitstreamHeader(
1761 : ISAR_POST_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle */
1762 : const ISAR_SPLIT_REND_CODEC codec, /* o : codec setting */
1763 : const ISAR_SPLIT_REND_POSE_CORRECTION_MODE poseCorrection, /* o : pose correction mode */
1764 : const int16_t codec_frame_size_ms, /* i : codec frame size setting */
1765 : const int16_t isar_frame_size_ms, /* i : ISAR codec frame size setting */
1766 : const int16_t lc3plus_highres /* i : LC3plus Hig-Res setting. Ignored if codec is not LC3plus */
1767 : )
1768 : {
1769 3820 : if ( hIvasRend == NULL )
1770 : {
1771 0 : return IVAS_ERR_UNEXPECTED_NULL_POINTER;
1772 : }
1773 :
1774 3820 : hIvasRend->splitRenderConfig.codec = codec;
1775 3820 : hIvasRend->splitRenderConfig.isar_frame_size_ms = isar_frame_size_ms;
1776 3820 : hIvasRend->splitRenderConfig.codec_frame_size_ms = codec_frame_size_ms;
1777 3820 : hIvasRend->splitRenderConfig.poseCorrectionMode = poseCorrection;
1778 3820 : hIvasRend->splitRenderConfig.lc3plus_highres = lc3plus_highres;
1779 :
1780 3820 : return IVAS_ERR_OK;
1781 : }
1782 :
1783 : #ifdef DEBUGGING
1784 : /*-------------------------------------------------------------------*
1785 : * ISAR_POST_REND_GetNoCLipping()
1786 : *
1787 : *
1788 : *-------------------------------------------------------------------*/
1789 :
1790 : int32_t ISAR_POST_REND_GetNoCLipping(
1791 : ISAR_POST_REND_HANDLE hIvasRend )
1792 : {
1793 : return hIvasRend->numClipping;
1794 : }
1795 :
1796 :
1797 : /*-------------------------------------------------------------------*
1798 : * ISAR_POST_REND_GetCntFramesLimited()
1799 : *
1800 : *
1801 : *-------------------------------------------------------------------*/
1802 :
1803 : int32_t ISAR_POST_REND_GetCntFramesLimited(
1804 : ISAR_POST_REND_HANDLE hIvasRend )
1805 : {
1806 : if ( hIvasRend->hLimiter == NULL )
1807 : {
1808 : return 0;
1809 : }
1810 :
1811 : return hIvasRend->hLimiter->cnt_frames_limited;
1812 : }
1813 : #endif
|