LCOV - code coverage report
Current view: top level - lib_isar - lib_isar_post_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 315f7421ae713fcc5638c2d754c52d449e763731 Lines: 457 556 82.2 %
Date: 2025-12-09 06:48:19 Functions: 40 42 95.2 %

          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     2229786 : ISAR_POST_REND_AudioConfigType isar_getAudioConfigType(
     123             :     const AUDIO_CONFIG config /* i  : audio configuration   */
     124             : )
     125             : {
     126             :     ISAR_POST_REND_AudioConfigType type;
     127             : 
     128     2229786 :     switch ( config )
     129             :     {
     130     2229786 :         case IVAS_AUDIO_CONFIG_BINAURAL:
     131             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
     132             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
     133     2229786 :             type = ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL;
     134     2229786 :             break;
     135           0 :         default:
     136           0 :             type = ISAR_POST_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
     137           0 :             break;
     138             :     }
     139             : 
     140     2229786 :     return type;
     141             : }
     142             : 
     143             : 
     144             : /*-------------------------------------------------------------------*
     145             :  * Local functions
     146             :  *-------------------------------------------------------------------*/
     147             : 
     148        2552 : static ivas_error allocateInputBaseBufferData(
     149             :     float **data,
     150             :     const int16_t data_size )
     151             : {
     152        2552 :     *data = (float *) malloc( data_size * sizeof( float ) );
     153        2552 :     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        2552 :     return IVAS_ERR_OK;
     159             : }
     160             : 
     161             : 
     162        2552 : static void freeInputBaseBufferData(
     163             :     float **data )
     164             : {
     165        2552 :     if ( *data != NULL )
     166             :     {
     167        2552 :         free( *data );
     168        2552 :         *data = NULL;
     169             :     }
     170             : 
     171        2552 :     return;
     172             : }
     173             : 
     174             : 
     175        9698 : static IVAS_QUATERNION quaternionInit(
     176             :     void )
     177             : {
     178             :     IVAS_QUATERNION q;
     179        9698 :     q.w = 1.0f;
     180        9698 :     q.x = q.y = q.z = 0.0f;
     181        9698 :     return q;
     182             : }
     183             : 
     184      422991 : static void convertBitsBufferToInternalBitsBuff(
     185             :     const ISAR_POST_REND_BitstreamBuffer outBits,
     186             :     ISAR_SPLIT_REND_BITS_HANDLE hBits )
     187             : {
     188      422991 :     hBits->bits_buf = outBits.bits;
     189      422991 :     hBits->bits_read = outBits.config.bitsRead;
     190      422991 :     hBits->bits_written = outBits.config.bitsWritten;
     191      422991 :     hBits->buf_len = outBits.config.bufLenInBytes;
     192      422991 :     hBits->codec = outBits.config.codec;
     193      422991 :     hBits->pose_correction = outBits.config.poseCorrection;
     194      422991 :     hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
     195      422991 :     hBits->isar_frame_size_ms = outBits.config.isar_frame_size_ms;
     196      422991 :     hBits->lc3plus_highres = outBits.config.lc3plusHighRes;
     197             : 
     198      422991 :     return;
     199             : }
     200             : 
     201             : 
     202      422991 : static void convertInternalBitsBuffToBitsBuffer(
     203             :     ISAR_POST_REND_BitstreamBuffer *hOutBits,
     204             :     const ISAR_SPLIT_REND_BITS_DATA bits )
     205             : {
     206      422991 :     hOutBits->bits = bits.bits_buf;
     207      422991 :     hOutBits->config.bitsRead = bits.bits_read;
     208      422991 :     hOutBits->config.bitsWritten = bits.bits_written;
     209      422991 :     hOutBits->config.bufLenInBytes = bits.buf_len;
     210      422991 :     hOutBits->config.codec = bits.codec;
     211      422991 :     hOutBits->config.poseCorrection = bits.pose_correction;
     212      422991 :     hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
     213      422991 :     hOutBits->config.isar_frame_size_ms = bits.isar_frame_size_ms;
     214      422991 :     hOutBits->config.lc3plusHighRes = bits.lc3plus_highres;
     215             : 
     216      422991 :     return;
     217             : }
     218             : 
     219             : 
     220        8363 : 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        8363 :     assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
     229        8363 :     readPtr = buffer.data;
     230             : 
     231       25089 :     for ( chnlIdx = 0; chnlIdx < (uint32_t) buffer.config.numChannels; ++chnlIdx )
     232             :     {
     233    16073686 :         for ( smplIdx = 0; smplIdx < (uint32_t) buffer.config.numSamplesPerChannel; ++smplIdx )
     234             :         {
     235    16056960 :             array[chnlIdx][smplIdx] = *readPtr++;
     236             :         }
     237             :     }
     238             : 
     239        8363 :     return;
     240             : }
     241             : 
     242             : 
     243      422991 : 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      422991 :     writePtr = buffer->data;
     251     1268973 :     for ( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
     252             :     {
     253   684365022 :         for ( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
     254             :         {
     255   683519040 :             *writePtr++ += array[chnlIdx][smplIdx];
     256             :         }
     257             :     }
     258             : 
     259      422991 :     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      422991 : 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      422991 :     int32_t numClipping = 0;
     282             : 
     283             :     /* return early if given bad parameters */
     284      422991 :     if ( hLimiter == NULL || output == NULL || output_frame <= 0 )
     285             :     {
     286           0 :         return 0;
     287             :     }
     288             : 
     289      422991 :     channels = hLimiter->channel_ptrs;
     290      422991 :     num_channels = hLimiter->num_channels;
     291             : 
     292     1268973 :     for ( i = 0; i < num_channels; ++i )
     293             :     {
     294      845982 :         channels[i] = output + i * output_frame;
     295             :     }
     296             : 
     297      422991 :     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   683942031 :     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   683519040 :         output[i] = min( max( INT16_MIN, output[i] ), INT16_MAX );
     310             :     }
     311             : 
     312      422991 :     return numClipping;
     313             : }
     314             : 
     315             : #endif
     316             : 
     317             : /*-------------------------------------------------------------------*
     318             :  * validateOutputSampleRate()
     319             :  *
     320             :  *
     321             :  *-------------------------------------------------------------------*/
     322             : 
     323        2552 : static ivas_error validateOutputSampleRate(
     324             :     const int32_t sampleRate,
     325             :     const AUDIO_CONFIG outConfig )
     326             : {
     327        2552 :     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        2552 :         switch ( sampleRate )
     335             :         {
     336        2552 :             case 8000:
     337             :             case 16000:
     338             :             case 32000:
     339             :             case 48000:
     340        2552 :                 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        2552 : 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        2552 :     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        2552 :     if ( *phLimiter != NULL )
     367             :     {
     368           0 :         ivas_limiter_close( phLimiter );
     369             :     }
     370             : 
     371        2552 :     if ( ( error = ivas_limiter_open( phLimiter, numChannels, sampleRate ) ) != IVAS_ERR_OK )
     372             :     {
     373           0 :         return error;
     374             :     }
     375             : 
     376        2552 :     return IVAS_ERR_OK;
     377             : }
     378             : 
     379             : 
     380        2552 : 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        2552 :     hIvasRend->headRotData.headRotEnabled = 1;
     388             : 
     389             :     /* Initialize 5ms crossfade */
     390        2552 :     crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
     391        2552 :     tmp = 1.f / ( crossfade_len - 1 );
     392      615032 :     for ( i = 0; i < crossfade_len; i++ )
     393             :     {
     394      612480 :         hIvasRend->headRotData.crossfade[i] = i * tmp;
     395             :     }
     396             : 
     397             :     /* Initialize with unit quaternions */
     398       12250 :     for ( i = 0; i < hIvasRend->num_subframes; ++i )
     399             :     {
     400        9698 :         hIvasRend->headRotData.headPositions[i] = quaternionInit();
     401             :     }
     402             : 
     403        2552 :     hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
     404             : 
     405        2552 :     return IVAS_ERR_OK;
     406             : }
     407             : 
     408             : 
     409        7656 : 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        7656 :     inputBase->inConfig = inConfig;
     418        7656 :     inputBase->id = id;
     419        7656 :     inputBase->gain = 1.0f;
     420        7656 :     inputBase->ctx = rendCtx;
     421        7656 :     inputBase->numNewSamplesPerChannel = 0;
     422             : 
     423        7656 :     inputBase->inputBuffer.config.numSamplesPerChannel = 0;
     424        7656 :     inputBase->inputBuffer.config.numChannels = 0;
     425        7656 :     inputBase->inputBuffer.data = dataBuf;
     426        7656 :     if ( inputBase->inputBuffer.data != NULL )
     427             :     {
     428        2552 :         set_zero( inputBase->inputBuffer.data, dataBufSize );
     429             :     }
     430             : 
     431        7656 :     return;
     432             : }
     433             : 
     434             : 
     435        2552 : 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        2552 :     ctx.pOutConfig = &hIvasRend->outputConfig;
     444        2552 :     ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
     445        2552 :     ctx.pHeadRotData = &hIvasRend->headRotData;
     446        2552 :     ctx.pSplitRendBFI = &hIvasRend->splitRendBFI;
     447        2552 :     ctx.pSplitRenderConfig = &hIvasRend->splitRenderConfig;
     448             : 
     449        2552 :     return ctx;
     450             : }
     451             : 
     452             : 
     453      752834 : 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      752834 :     *numInChannels = 2;
     462             : 
     463      752834 :     return IVAS_ERR_OK;
     464             : }
     465             : 
     466             : 
     467        2552 : 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        2552 :     rendCtx = inputSplitPostRend->base.ctx;
     480        2552 :     isar_renderSplitGetMultiBinPoseData( hRendCfg, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, rendCtx.pHeadRotData->sr_pose_pred_axis );
     481             : 
     482        2552 :     config.high_res_mode_enabled = ( hRendCfg->lc3plus_highres != 0 );
     483        2552 :     config.lc3plus_frame_duration_us = hRendCfg->codec_frame_size_ms * 1000;
     484        2552 :     config.isar_frame_duration_us = hRendCfg->isar_frame_size_ms * 1000;
     485             : 
     486        2552 :     if ( hRendCfg->codec_frame_size_ms > 0 )
     487             :     {
     488        2552 :         iNumLCLDIterationsPerFrame = (int16_t) config.isar_frame_duration_us / ( 1000 * hRendCfg->codec_frame_size_ms );
     489        2552 :         iNumLCLDIterationsPerFrame = max( 1, iNumLCLDIterationsPerFrame );
     490        2552 :         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        2552 :     config.channels = BINAURAL_CHANNELS;
     499        2552 :     config.samplerate = *inputSplitPostRend->base.ctx.pOutSampleRate;
     500             : 
     501        2552 :     if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LCLD )
     502             :     {
     503        1434 :         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        1118 :     else if ( hRendCfg->codec == ISAR_SPLIT_REND_CODEC_LC3PLUS )
     509             :     {
     510        1084 :         if ( ( error = ISAR_LC3PLUS_DEC_Open( config, &inputSplitPostRend->splitPostRendWrapper.hLc3plusDec ) ) != IVAS_ERR_OK )
     511             :         {
     512           0 :             return error;
     513             :         }
     514             :     }
     515             : 
     516        2552 :     if ( ( error = isar_splitBinPostRendOpen( &inputSplitPostRend->splitPostRendWrapper.hBinHrSplitPostRend, &inputSplitPostRend->splitPostRendWrapper.multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
     517             :     {
     518           0 :         return error;
     519             :     }
     520             : 
     521        2552 :     return IVAS_ERR_OK;
     522             : }
     523             : 
     524             : 
     525        2552 : 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        2552 :     inputSplitPostRend = (input_split_post_rend *) input;
     537        2552 :     rendCtx = inputSplitPostRend->base.ctx;
     538        2552 :     outConfig = *rendCtx.pOutConfig;
     539             : 
     540        2552 :     if ( ( error = allocateInputBaseBufferData( &inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH ) ) != IVAS_ERR_OK )
     541             :     {
     542           0 :         return error;
     543             :     }
     544             : 
     545        2552 :     initRendInputBase( &inputSplitPostRend->base, inConfig, id, rendCtx, inputSplitPostRend->bufferData, MAX_CLDFB_BIN_BUFFER_LENGTH );
     546        2552 :     inputSplitPostRend->numCachedSamples = 0;
     547             : 
     548        2552 :     if ( ( error = updateSplitPostRendPanGains( inputSplitPostRend, outConfig, hRendCfg ) ) != IVAS_ERR_OK )
     549             :     {
     550           0 :         return error;
     551             :     }
     552             : 
     553        2552 :     return IVAS_ERR_OK;
     554             : }
     555             : 
     556             : 
     557        2552 : static void clearInputSplitRend(
     558             :     input_split_post_rend *inputSplitRend )
     559             : {
     560             :     rendering_context_isar rendCtx;
     561             : 
     562        2552 :     rendCtx = inputSplitRend->base.ctx;
     563             : 
     564        2552 :     freeInputBaseBufferData( &inputSplitRend->bufferData );
     565             : 
     566        2552 :     initRendInputBase( &inputSplitRend->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
     567             : 
     568        2552 :     if ( inputSplitRend->splitPostRendWrapper.hBinHrSplitPostRend != NULL )
     569             :     {
     570        2552 :         isar_splitBinPostRendClose( &inputSplitRend->splitPostRendWrapper.hBinHrSplitPostRend );
     571             :     }
     572             : 
     573        2552 :     if ( inputSplitRend->splitPostRendWrapper.hSplitBinLCLDDec != NULL )
     574             :     {
     575        1434 :         isar_splitBinLCLDDecClose( &inputSplitRend->splitPostRendWrapper.hSplitBinLCLDDec );
     576             :     }
     577             : 
     578        2552 :     if ( inputSplitRend->splitPostRendWrapper.hLc3plusDec != NULL )
     579             :     {
     580        1084 :         ISAR_LC3PLUS_DEC_Close( &inputSplitRend->splitPostRendWrapper.hLc3plusDec );
     581             :     }
     582             : 
     583        2552 :     return;
     584             : }
     585             : 
     586             : 
     587             : /*-------------------------------------------------------------------------
     588             :  * ISAR_POST_REND_open()
     589             :  *
     590             :  *
     591             :  *------------------------------------------------------------------------*/
     592             : 
     593        2552 : 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        2552 :     if ( phIvasRend == NULL )
     614             :     {
     615           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     616             :     }
     617             : 
     618        2552 :     if ( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ) != IVAS_ERR_OK )
     619             :     {
     620           0 :         return error;
     621             :     }
     622             : 
     623        2552 :     *phIvasRend = (ISAR_POST_REND_HANDLE) malloc( sizeof( struct ISAR_POST_REND ) );
     624        2552 :     if ( *phIvasRend == NULL )
     625             :     {
     626           0 :         return IVAS_ERR_FAILED_ALLOC;
     627             :     }
     628             : 
     629        2552 :     hIvasRend = *phIvasRend;
     630        2552 :     hIvasRend->sampleRateOut = outputSampleRate;
     631        2552 :     hIvasRend->outputConfig = outConfig;
     632        2552 :     hIvasRend->hLimiter = NULL;
     633        2552 :     hIvasRend->num_subframes = 1;
     634             : #ifdef DEBUGGING
     635             :     hIvasRend->numClipping = 0;
     636             : #endif
     637        2552 :     hIvasRend->num_subframes = num_subframes;
     638             : 
     639             :     /* Initialize limiter */
     640        2552 :     if ( ( error = ISAR_POST_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
     641             :     {
     642           0 :         return error;
     643             :     }
     644             : 
     645        2552 :     if ( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ) != IVAS_ERR_OK )
     646             :     {
     647           0 :         return error;
     648             :     }
     649             : 
     650             :     /* Initialize headrotation data */
     651        2552 :     if ( ( error = initHeadRotation( hIvasRend ) ) != IVAS_ERR_OK )
     652             :     {
     653           0 :         return error;
     654             :     }
     655             : 
     656             :     /* Initialize inputs */
     657             : 
     658        5104 :     for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; ++i )
     659             :     {
     660        2552 :         initRendInputBase( &hIvasRend->inputsSplitPost[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
     661             : 
     662        2552 :         isar_init_split_post_rend_handles( &hIvasRend->inputsSplitPost[i].splitPostRendWrapper );
     663             : 
     664        2552 :         hIvasRend->splitRendBFI = 0;
     665        2552 :         hIvasRend->inputsSplitPost[i].bufferData = NULL;
     666             :     }
     667             : 
     668        2552 :     return IVAS_ERR_OK;
     669             : }
     670             : 
     671             : 
     672             : /*-------------------------------------------------------------------*
     673             :  * ISAR_POST_REND_NumOutChannels()
     674             :  *
     675             :  *
     676             :  *-------------------------------------------------------------------*/
     677             : 
     678      425543 : 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      425543 :     if ( hIvasRend == NULL || numOutChannels == NULL )
     685             :     {
     686           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     687             :     }
     688             : 
     689      425543 :     *numOutChannels = 2;
     690             : 
     691      425543 :     return IVAS_ERR_OK;
     692             : }
     693             : 
     694             : 
     695        2552 : 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        2552 :     return (IVAS_REND_InputId) ( ( ( (uint32_t) isar_getAudioConfigType( config ) ) << 8 ) | ( inputIndex + 1 ) );
     703             : }
     704             : 
     705             : 
     706      750282 : 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      750282 :     inputIndex = ( inputId & 0xFF ) - 1;
     717      750282 :     configType = ( inputId & 0xFF00 ) >> 8;
     718             : 
     719             :     /* Validate values derived from input ID */
     720      750282 :     if ( inputIndex < 0 )
     721             :     {
     722           0 :         return IVAS_ERR_INVALID_INPUT_ID;
     723             :     }
     724      750282 :     switch ( configType )
     725             :     {
     726      750282 :         case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
     727      750282 :             if ( inputIndex > RENDERER_MAX_BIN_INPUTS )
     728             :             {
     729           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
     730             :             }
     731      750282 :             pInputBase = &hIvasRend->inputsSplitPost[inputIndex].base;
     732      750282 :             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      750282 :     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      750282 :     *ppInput = pInputBase;
     745             : 
     746      750282 :     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      377693 : 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      377693 :     inputIndex = ( inputId & 0xFF ) - 1;
     794      377693 :     configType = ( inputId & 0xFF00 ) >> 8;
     795             : 
     796             :     /* Validate values derived from input ID */
     797      377693 :     if ( inputIndex < 0 )
     798             :     {
     799           0 :         return IVAS_ERR_INVALID_INPUT_ID;
     800             :     }
     801      377693 :     switch ( configType )
     802             :     {
     803      377693 :         case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
     804      377693 :             if ( inputIndex > RENDERER_MAX_BIN_INPUTS )
     805             :             {
     806           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
     807             :             }
     808      377693 :             pInputBase = &hIvasRend->inputsSplitPost[inputIndex].base;
     809      377693 :             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      377693 :     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      377693 :     *ppInput = pInputBase;
     822             : 
     823      377693 :     return IVAS_ERR_OK;
     824             : }
     825             : 
     826             : 
     827        2552 : 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        2552 :     canAddInput = false;
     846             : 
     847             :     /* Find first unused input in array */
     848        2552 :     for ( i = 0, pByte = inputs; i < maxInputs; ++i, pByte += inputStructSize )
     849             :     {
     850        2552 :         pInputBase = (const input_base_isar *) pByte;
     851             : 
     852        2552 :         if ( pInputBase->inConfig == IVAS_AUDIO_CONFIG_INVALID )
     853             :         {
     854        2552 :             *inputIndex = i;
     855        2552 :             canAddInput = true;
     856        2552 :             break;
     857             :         }
     858             :     }
     859             : 
     860        2552 :     if ( !canAddInput )
     861             :     {
     862           0 :         return IVAS_ERR_TOO_MANY_INPUTS;
     863             :     }
     864             : 
     865        2552 :     return IVAS_ERR_OK;
     866             : }
     867             : 
     868             : 
     869             : /*-------------------------------------------------------------------*
     870             :  * ISAR_POST_REND_AddInput()
     871             :  *
     872             :  *
     873             :  *-------------------------------------------------------------------*/
     874             : 
     875        2552 : 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        2552 :     if ( hIvasRend == NULL || inputId == NULL )
     891             :     {
     892           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     893             :     }
     894             : 
     895        2552 :     switch ( isar_getAudioConfigType( inConfig ) )
     896             :     {
     897        2552 :         case ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL:
     898        2552 :             maxNumInputsOfType = RENDERER_MAX_BIN_INPUTS;
     899        2552 :             inputsArray = hIvasRend->inputsSplitPost;
     900        2552 :             inputStructSize = sizeof( *hIvasRend->inputsSplitPost );
     901        2552 :             activateInput = setRendInputActiveSplitPostRend;
     902        2552 :             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        2552 :     if ( ( error = findFreeInputSlot( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ) != IVAS_ERR_OK )
     909             :     {
     910           0 :         return error;
     911             :     }
     912             : 
     913        2552 :     *inputId = makeInputId( inConfig, inputIndex );
     914             : 
     915        2552 :     if ( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, &hIvasRend->splitRenderConfig ) ) != IVAS_ERR_OK )
     916             :     {
     917           0 :         return error;
     918             :     }
     919             : 
     920        2552 :     return IVAS_ERR_OK;
     921             : }
     922             : 
     923             : 
     924             : /*-------------------------------------------------------------------*
     925             :  * ISAR_POST_REND_GetInputNumChannels()
     926             :  *
     927             :  *
     928             :  *-------------------------------------------------------------------*/
     929             : 
     930      377693 : 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      377693 :     if ( hIvasRend == NULL || numChannels == NULL )
     941             :     {
     942           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     943             :     }
     944             : 
     945      377693 :     if ( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ) != IVAS_ERR_OK )
     946             :     {
     947           0 :         return error;
     948             :     }
     949             : 
     950      377693 :     if ( ( error = getRendInputNumChannels( pInput, numChannels ) ) != IVAS_ERR_OK )
     951             :     {
     952           0 :         return error;
     953             :     }
     954             : 
     955      377693 :     return IVAS_ERR_OK;
     956             : }
     957             : 
     958             : 
     959             : /*-------------------------------------------------------------------*
     960             :  * ISAR_POST_REND_GetDelay()
     961             :  *
     962             :  *
     963             :  *-------------------------------------------------------------------*/
     964             : 
     965        2552 : 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        2552 :     if ( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
     977             :     {
     978           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     979             :     }
     980             : 
     981        2552 :     *timeScale = hIvasRend->sampleRateOut;
     982        2552 :     *nSamples = 0;
     983        2552 :     max_latency_ns = 0;
     984             : 
     985             :     /* Compute the maximum delay across all inputs */
     986        5104 :     for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; i++ )
     987             :     {
     988        2552 :         if ( hIvasRend->inputsSplitPost[i].base.inConfig != IVAS_AUDIO_CONFIG_INVALID )
     989             :         {
     990        2552 :             latency_ns = 0;
     991        2552 :             if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hLc3plusDec != NULL )
     992             :             {
     993             :                 int32_t lc3plusDelaySamples;
     994        1084 :                 ISAR_LC3PLUS_DEC_GetDelay( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hLc3plusDec, &lc3plusDelaySamples );
     995        1084 :                 latency_ns = (int32_t) roundf( lc3plusDelaySamples * 1000000000.f / *timeScale );
     996             :             }
     997        2552 :             if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.multiBinPoseData.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
     998             :             {
     999        1732 :                 latency_ns += IVAS_FB_DEC_DELAY_NS;
    1000             :             }
    1001         820 :             else if ( hIvasRend->inputsSplitPost[i].splitPostRendWrapper.hSplitBinLCLDDec != NULL )
    1002             :             {
    1003         520 :                 latency_ns += IVAS_FB_DEC_DELAY_NS;
    1004             :             }
    1005        2552 :             max_latency_ns = max( max_latency_ns, latency_ns );
    1006             :         }
    1007             :     }
    1008             : 
    1009        2552 :     *nSamples = (int16_t) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
    1010             : 
    1011        2552 :     return IVAS_ERR_OK;
    1012             : }
    1013             : 
    1014             : 
    1015             : /*-------------------------------------------------------------------*
    1016             :  * ISAR_POST_REND_FeedInputAudio()
    1017             :  *
    1018             :  *
    1019             :  *-------------------------------------------------------------------*/
    1020             : 
    1021      375141 : 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      375141 :     if ( hIvasRend == NULL || inputAudio.data == NULL )
    1034             :     {
    1035           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    1036             :     }
    1037             : 
    1038      375141 :     cldfb2tdSampleFact = ( inputAudio.config.is_cldfb ) ? 2 : 1;
    1039             : 
    1040      375141 :     if ( inputAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
    1041      375141 :          ( ( 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      375141 :     if ( inputAudio.config.numChannels <= 0 || MAX_INPUT_CHANNELS < inputAudio.config.numChannels )
    1047             :     {
    1048           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    1049             :     }
    1050             : 
    1051      375141 :     if ( isar_getAudioConfigType( hIvasRend->outputConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
    1052      375141 :          hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED &&
    1053      375141 :          hIvasRend->outputConfig != IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM &&
    1054      375141 :          ( 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      375141 :     if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
    1060             :     {
    1061           0 :         printf( "Foo\n" );
    1062           0 :         return error;
    1063             :     }
    1064             : 
    1065      375141 :     if ( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ) != IVAS_ERR_OK )
    1066             :     {
    1067           0 :         return error;
    1068             :     }
    1069             : 
    1070      375141 :     if ( numInputChannels != inputAudio.config.numChannels )
    1071             :     {
    1072           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    1073             :     }
    1074             : 
    1075      375141 :     inputBase->inputBuffer.config = inputAudio.config;
    1076             : 
    1077      375141 :     mvr2r( inputAudio.data, inputBase->inputBuffer.data, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
    1078             : 
    1079      375141 :     inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel / cldfb2tdSampleFact;
    1080             : 
    1081      375141 :     return IVAS_ERR_OK;
    1082             : }
    1083             : 
    1084             : 
    1085             : /*-------------------------------------------------------------------*
    1086             :  * ISAR_POST_REND_InitConfig()
    1087             :  *
    1088             :  *
    1089             :  *-------------------------------------------------------------------*/
    1090             : 
    1091        2552 : 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        2552 :     rendererConfigEnabled = ( isar_getAudioConfigType( outAudioConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL );
    1099             : 
    1100        2552 :     if ( rendererConfigEnabled )
    1101             :     {
    1102        2552 :         hIvasRend->rendererConfigEnabled = 1;
    1103             :     }
    1104             :     else
    1105             :     {
    1106           0 :         hIvasRend->rendererConfigEnabled = 0;
    1107             :     }
    1108             : 
    1109        2552 :     if ( rendererConfigEnabled )
    1110             :     {
    1111        2552 :         hIvasRend->splitRenderConfig.splitRendBitRate = SPLIT_REND_768k;
    1112        2552 :         hIvasRend->splitRenderConfig.dof = 3;
    1113        2552 :         hIvasRend->splitRenderConfig.hq_mode = 0;
    1114        2552 :         hIvasRend->splitRenderConfig.codec_delay_ms = 0;
    1115        2552 :         hIvasRend->splitRenderConfig.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
    1116        2552 :         hIvasRend->splitRenderConfig.isar_frame_size_ms = 0;  /* 0 means "use default for selected codec" */
    1117        2552 :         hIvasRend->splitRenderConfig.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
    1118        2552 :         hIvasRend->splitRenderConfig.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
    1119        2552 :         hIvasRend->splitRenderConfig.rendererSelection = IVAS_BIN_RENDERER_TYPE_DEFAULT;
    1120             :     }
    1121             : 
    1122        2552 :     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      375141 : 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      375141 :     if ( hIvasRend == NULL || hBits == NULL )
    1178             :     {
    1179           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    1180             :     }
    1181             : 
    1182      375141 :     if ( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ) != IVAS_ERR_OK )
    1183             :     {
    1184           0 :         printf( "Goo\n" );
    1185           0 :         return error;
    1186             :     }
    1187             : 
    1188      375141 :     inputSplitPostRend = (input_split_post_rend *) inputBase;
    1189      375141 :     inputSplitPostRend->hBits = hBits;
    1190             : 
    1191      375141 :     return IVAS_ERR_OK;
    1192             : }
    1193             : 
    1194             : 
    1195             : /*-------------------------------------------------------------------*
    1196             :  * ISAR_POST_REND_SetHeadRotation()
    1197             :  *
    1198             :  *
    1199             :  *-------------------------------------------------------------------*/
    1200             : 
    1201     1423998 : 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     1423998 :     if ( hIvasRend == NULL )
    1213             :     {
    1214           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    1215             :     }
    1216             : 
    1217     1423998 :     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     1423998 :     hIvasRend->headRotData.headRotEnabled = 1;
    1224             : 
    1225             :     /* check for Euler angle signaling */
    1226     1423998 :     if ( headRot.w == -3.0f )
    1227             :     {
    1228     1161198 :         Euler2Quat( deg2rad( headRot.x ), deg2rad( headRot.y ), deg2rad( headRot.z ), &rotQuat );
    1229             :     }
    1230             :     else
    1231             :     {
    1232      262800 :         rotQuat = headRot;
    1233             :     }
    1234             : 
    1235     1423998 :     hIvasRend->headRotData.headPositions[sf_idx] = rotQuat;
    1236     1423998 :     hIvasRend->headRotData.Pos[sf_idx] = Pos;
    1237     1423998 :     hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
    1238             : 
    1239     1423998 :     return IVAS_ERR_OK;
    1240             : }
    1241             : 
    1242             : 
    1243             : /*-------------------------------------------------------------------*
    1244             :  * ISAR_POST_REND_SetSplitRendBFI()
    1245             :  *
    1246             :  *
    1247             :  *-------------------------------------------------------------------*/
    1248             : 
    1249      384892 : 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      384892 :     hIvasRend->splitRendBFI = bfi;
    1255             : 
    1256      384892 :     return IVAS_ERR_OK;
    1257             : }
    1258             : 
    1259             : 
    1260             : /*-------------------------------------------------------------------*
    1261             :  * Local functions
    1262             :  *-------------------------------------------------------------------*/
    1263             : 
    1264      165448 : 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      165448 :     push_wmops( "splitBinLc3plusDecode" );
    1275      165448 :     assert( hSplitBin->hLc3plusDec != NULL );
    1276             : 
    1277     1889784 :     for ( int16_t i = 0; i < BINAURAL_CHANNELS * hSplitBin->multiBinPoseData.num_poses; ++i )
    1278             :     {
    1279     1724336 :         channel_ptrs[i] = outputBuffer[i];
    1280             :     }
    1281             : 
    1282      165448 :     if ( SplitRendBFI == 0 )
    1283             :     {
    1284             :         /* Find next byte boundary */
    1285      552355 :         while ( bits->bits_read % 8 != 0 )
    1286             :         {
    1287      387931 :             ++bits->bits_read;
    1288             :         }
    1289             : 
    1290             :         /* Size is in bytes */
    1291      164424 :         assert( ( bits->bits_written - bits->bits_read ) % 8 == 0 );
    1292      164424 :         lc3plusBitstreamSize = ( bits->bits_written - bits->bits_read ) / 8;
    1293             : 
    1294      164424 :         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      165448 :     pop_wmops();
    1308      165448 :     return IVAS_ERR_OK;
    1309             : }
    1310             : 
    1311             : 
    1312      422991 : 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      422991 :     isPostRendInputCldfb = 0;
    1339      422991 :     push_wmops( "renderSplitBinauralWithPostRot" );
    1340      422991 :     error = IVAS_ERR_OK;
    1341             : 
    1342      422991 :     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      422991 :     pHeadRotData = splitBinInput->base.ctx.pHeadRotData;
    1348      422991 :     hSplitBin = &splitBinInput->splitPostRendWrapper;
    1349      422991 :     convertBitsBufferToInternalBitsBuff( *splitBinInput->hBits, &bits );
    1350             : 
    1351      422991 :     iNumLCLDIterationsPerFrame = 1;
    1352      422991 :     iNumBlocksPerFrame = CLDFB_NO_COL_MAX;
    1353      422991 :     if ( splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec != NULL )
    1354             :     {
    1355      213792 :         iNumBlocksPerFrame = splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec->iNumBlocks;
    1356      213792 :         iNumLCLDIterationsPerFrame = splitBinInput->splitPostRendWrapper.hSplitBinLCLDDec->iNumIterations;
    1357             :     }
    1358             : 
    1359      422991 :     outBufNumSamplesPerChannel = outAudio.config.numSamplesPerChannel / num_subframes;
    1360     1846989 :     for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
    1361             :     {
    1362     1423998 :         QuaternionsPost[sf_idx] = pHeadRotData->headPositions[sf_idx];
    1363             :     }
    1364             : 
    1365      422991 :     if ( !SplitRendBFI )
    1366             :     {
    1367      410870 :         hSplitBin->first_good_frame_received = 1;
    1368             :     }
    1369             : 
    1370      422991 :     if ( hSplitBin->first_good_frame_received == 1 )
    1371             :     {
    1372      412157 :         if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
    1373             :         {
    1374      255002 :             if ( !SplitRendBFI )
    1375             :             {
    1376             : #ifdef SPLIT_REND_WITH_HEAD_ROT_DEBUG
    1377             :                 isar_splitBinPostRendMdDec( &bits, hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData, hSplitBin->hBinHrSplitPreRend );
    1378             : #else
    1379      253715 :                 isar_splitBinPostRendMdDec( &bits, hSplitBin->hBinHrSplitPostRend, &hSplitBin->multiBinPoseData );
    1380             : #endif
    1381             :             }
    1382             :         }
    1383             : 
    1384             :         /*copy pose correction after MD is parsed*/
    1385      412157 :         hSplitBin->multiBinPoseData.poseCorrectionMode = bits.pose_correction;
    1386             : 
    1387             :         /* decode audio */
    1388      412157 :         if ( splitBinInput->base.inConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
    1389             :         {
    1390      403896 :             if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
    1391             :             {
    1392      207268 :                 isPostRendInputCldfb = 1;
    1393             :             }
    1394             : 
    1395      403896 :             numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outBufNumSamplesPerChannel;
    1396             : 
    1397      403896 :             outBufNumColPerChannel = MAX_PARAM_SPATIAL_SUBFRAMES;
    1398      403896 :             numColPerChannelCacheSize = ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ) - outBufNumColPerChannel;
    1399             : 
    1400     1757562 :             for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
    1401             :             {
    1402     1353666 :                 if ( splitBinInput->numCachedSamples == 0 )
    1403             :                 {
    1404      357126 :                     if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
    1405             :                     {
    1406      191678 :                         isar_splitBinLCLDDecProcess( hSplitBin->hSplitBinLCLDDec, &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, SplitRendBFI );
    1407             : 
    1408             :                         /* copy data over to 5ms buffer */
    1409      575034 :                         for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
    1410             :                         {
    1411     1916780 :                             for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; ++slotIdx )
    1412             :                             {
    1413     1533424 :                                 mvr2r( Cldfb_RealBuffer_Binaural[chnlIdx][slotIdx], Cldfb_RealBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx], CLDFB_NO_CHANNELS_MAX );
    1414     1533424 :                                 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      191678 :                         splitBinInput->numCachedSamples = numColPerChannelCacheSize;
    1420      191678 :                         writePtr = splitBinInput->bufferData;
    1421     2367082 :                         for ( slotIdx = CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; slotIdx < ( iNumBlocksPerFrame * iNumLCLDIterationsPerFrame ); ++slotIdx )
    1422             :                         {
    1423     6526212 :                             for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
    1424             :                             {
    1425   265399288 :                                 for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
    1426             :                                 {
    1427   261048480 :                                     *writePtr++ = Cldfb_RealBuffer_Binaural[chnlIdx][slotIdx][smplIdx];
    1428             :                                 }
    1429   265399288 :                                 for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
    1430             :                                 {
    1431   261048480 :                                     *writePtr++ = Cldfb_ImagBuffer_Binaural[chnlIdx][slotIdx][smplIdx];
    1432             :                                 }
    1433             :                             }
    1434             :                         }
    1435             :                     }
    1436             :                     else
    1437             :                     {
    1438      165448 :                         if ( ( error = splitBinLc3plusDecode( hSplitBin, &bits, tmpCrendBuffer, SplitRendBFI ) ) != IVAS_ERR_OK )
    1439             :                         {
    1440           0 :                             return error;
    1441             :                         }
    1442             : 
    1443             :                         /* cache the remaining decoded audio */
    1444      165448 :                         splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
    1445      165448 :                         mvr2r( &tmpCrendBuffer[0][outBufNumSamplesPerChannel], splitBinInput->bufferData, numSamplesPerChannelCacheSize );
    1446      165448 :                         mvr2r( &tmpCrendBuffer[1][outBufNumSamplesPerChannel], splitBinInput->bufferData + numSamplesPerChannelCacheSize, numSamplesPerChannelCacheSize );
    1447             :                     }
    1448             :                 }
    1449             :                 else
    1450             :                 {
    1451             :                     /* copy from cache */
    1452      996540 :                     if ( bits.codec == ISAR_SPLIT_REND_CODEC_LCLD )
    1453             :                     {
    1454      543851 :                         int16_t readOffset = ( numColPerChannelCacheSize - splitBinInput->numCachedSamples );
    1455      543851 :                         readPtr = splitBinInput->bufferData;
    1456      543851 :                         isPostRendInputCldfb = 1;
    1457             : 
    1458      543851 :                         readPtr += 2 * readOffset * CLDFB_NO_CHANNELS_MAX * BINAURAL_CHANNELS;
    1459     2719255 :                         for ( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; ++slotIdx )
    1460             :                         {
    1461     6526212 :                             for ( chnlIdx = 0; chnlIdx < BINAURAL_CHANNELS; ++chnlIdx )
    1462             :                             {
    1463   265399288 :                                 for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
    1464             :                                 {
    1465   261048480 :                                     Cldfb_RealBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx][smplIdx] = *readPtr++;
    1466             :                                 }
    1467   265399288 :                                 for ( smplIdx = 0; smplIdx < CLDFB_NO_CHANNELS_MAX; ++smplIdx )
    1468             :                                 {
    1469   261048480 :                                     Cldfb_ImagBuffer_Binaural_5ms[sf_idx][chnlIdx][slotIdx][smplIdx] = *readPtr++;
    1470             :                                 }
    1471             :                             }
    1472             :                         }
    1473             : 
    1474      543851 :                         splitBinInput->numCachedSamples -= outBufNumColPerChannel;
    1475             :                     }
    1476             :                     else
    1477             :                     {
    1478      452689 :                         int16_t readOffset = numSamplesPerChannelCacheSize - splitBinInput->numCachedSamples;
    1479      452689 :                         mvr2r( splitBinInput->bufferData + readOffset, &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
    1480      452689 :                         mvr2r( splitBinInput->bufferData + readOffset + numSamplesPerChannelCacheSize, &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
    1481      452689 :                         splitBinInput->numCachedSamples -= outBufNumSamplesPerChannel;
    1482             :                     }
    1483             :                 }
    1484             :             }
    1485             :         }
    1486             :         else
    1487             :         {
    1488        8261 :             copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer );
    1489        8261 :             if ( splitBinInput->numCachedSamples == 0 )
    1490             :             {
    1491        8261 :                 preRendFrameSize_ms = splitBinInput->base.ctx.pSplitRenderConfig->isar_frame_size_ms;
    1492        8261 :                 numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * preRendFrameSize_ms / 1000 );
    1493        8261 :                 numSamplesPerChannelCacheSize -= outAudio.config.numSamplesPerChannel;
    1494        8261 :                 splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
    1495             :             }
    1496             :             else
    1497             :             {
    1498           0 :                 splitBinInput->numCachedSamples -= outAudio.config.numSamplesPerChannel;
    1499             :             }
    1500             :         }
    1501             : 
    1502             :         /* apply pose correction if enabled */
    1503     1798867 :         for ( sf_idx = 0; sf_idx < num_subframes; sf_idx++ )
    1504             :         {
    1505     1386710 :             if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE && isPostRendInputCldfb )
    1506      264637 :             {
    1507             :                 /* 0DOF with LCLD codec requires CLDFB synthesis */
    1508             :                 int16_t slot_idx;
    1509             : 
    1510      793911 :                 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     2646370 :                     for ( slot_idx = 0; slot_idx < CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES; slot_idx++ )
    1516             :                     {
    1517     2117096 :                         RealBuffer[slot_idx] = Cldfb_RealBuffer_Binaural_5ms[sf_idx][ch_idx][slot_idx];
    1518     2117096 :                         ImagBuffer[slot_idx] = Cldfb_ImagBuffer_Binaural_5ms[sf_idx][ch_idx][slot_idx];
    1519             :                     }
    1520             : 
    1521      529274 :                     cldfbSynthesis( RealBuffer,
    1522             :                                     ImagBuffer,
    1523      529274 :                                     &( tmpCrendBuffer[ch_idx][sf_idx * outBufNumSamplesPerChannel] ),
    1524      529274 :                                     hSplitBin->hBinHrSplitPostRend->cldfbSyn[0]->no_channels * CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES,
    1525      529274 :                                     hSplitBin->hBinHrSplitPostRend->cldfbSyn[ch_idx] );
    1526             :                 }
    1527             :             }
    1528     1122073 :             else if ( bits.pose_correction == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB )
    1529             :             {
    1530      945176 :                 mvr2r( &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], tmpCrendBuffer_sf[0], outBufNumSamplesPerChannel );
    1531      945176 :                 mvr2r( &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], tmpCrendBuffer_sf[1], outBufNumSamplesPerChannel );
    1532             : 
    1533      945176 :                 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      945176 :                 mvr2r( tmpCrendBuffer_sf[0], &tmpCrendBuffer[0][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
    1536      945176 :                 mvr2r( tmpCrendBuffer_sf[1], &tmpCrendBuffer[1][sf_idx * outBufNumSamplesPerChannel], outBufNumSamplesPerChannel );
    1537             :             }
    1538             :         }
    1539             :     }
    1540             :     else
    1541             :     {
    1542       10834 :         if ( splitBinInput->numCachedSamples == 0 )
    1543             :         {
    1544        9754 :             numSamplesPerChannelCacheSize = (int16_t) ( *splitBinInput->base.ctx.pOutSampleRate * bits.isar_frame_size_ms / 1000 ) - outAudio.config.numSamplesPerChannel;
    1545        9754 :             splitBinInput->numCachedSamples = numSamplesPerChannelCacheSize;
    1546             :         }
    1547             :         else
    1548             :         {
    1549        1080 :             splitBinInput->numCachedSamples -= outAudio.config.numSamplesPerChannel;
    1550             :         }
    1551             : 
    1552       10834 :         if ( splitBinInput->base.inConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED )
    1553             :         {
    1554       32196 :             for ( ch_idx = 0; ch_idx < BINAURAL_CHANNELS; ch_idx++ )
    1555             :             {
    1556       21464 :                 set_zero( tmpCrendBuffer[ch_idx], outAudio.config.numSamplesPerChannel );
    1557             :             }
    1558             :         }
    1559             :         else
    1560             :         {
    1561         102 :             copyBufferTo2dArray( splitBinInput->base.inputBuffer, tmpCrendBuffer );
    1562             :         }
    1563             :     }
    1564             : 
    1565      422991 :     convertInternalBitsBuffToBitsBuffer( splitBinInput->hBits, bits );
    1566      422991 :     accumulate2dArrayToBuffer( tmpCrendBuffer, &outAudio );
    1567             : 
    1568      422991 :     pop_wmops();
    1569      422991 :     return error;
    1570             : }
    1571             : 
    1572             : 
    1573      422991 : 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      422991 :     inAudio = splitBinInput->base.inputBuffer;
    1584             : 
    1585      422991 :     splitBinInput->base.numNewSamplesPerChannel = 0;
    1586             : 
    1587             :     /* Apply input gain to new audio */
    1588      422991 :     v_multc( inAudio.data,
    1589             :              splitBinInput->base.gain,
    1590             :              inAudio.data,
    1591      422991 :              inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
    1592      422991 :     switch ( outConfig )
    1593             :     {
    1594      422991 :         case IVAS_AUDIO_CONFIG_BINAURAL:
    1595      422991 :             error = renderSplitBinauralWithPostRot( splitBinInput, outAudio, SplitRendBFI, num_subframes );
    1596      422991 :             break;
    1597           0 :         default:
    1598           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    1599             :     }
    1600             : 
    1601      422991 :     return error;
    1602             : }
    1603             : 
    1604             : 
    1605      422991 : 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      845982 :     for ( i = 0, pCurrentInput = hIvasRend->inputsSplitPost; i < RENDERER_MAX_BIN_INPUTS; ++i, ++pCurrentInput )
    1614             :     {
    1615      422991 :         if ( pCurrentInput->base.inConfig == IVAS_AUDIO_CONFIG_INVALID )
    1616             :         {
    1617             :             /* Skip inactive inputs */
    1618           0 :             continue;
    1619             :         }
    1620             : 
    1621      422991 :         if ( ( error = renderInputSplitBin( pCurrentInput, hIvasRend->outputConfig, outAudio, hIvasRend->splitRendBFI, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
    1622             :         {
    1623           0 :             return error;
    1624             :         }
    1625             :     }
    1626             : 
    1627      422991 :     return IVAS_ERR_OK;
    1628             : }
    1629             : 
    1630             : 
    1631             : /*-------------------------------------------------------------------*
    1632             :  * ISAR_POST_REND_getSamples()
    1633             :  *
    1634             :  *
    1635             :  *-------------------------------------------------------------------*/
    1636             : 
    1637      422991 : 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      422991 :     if ( hIvasRend == NULL || outAudio.data == NULL )
    1648             :     {
    1649           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    1650             :     }
    1651             : 
    1652      422991 :     cldfb2tdSampleFact = ( outAudio.config.is_cldfb ) ? 2 : 1;
    1653             : 
    1654      422991 :     if ( outAudio.config.numSamplesPerChannel <= 0 || ( L_FRAME_MAX < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
    1655      422991 :          ( ( L_FRAME_MAX * cldfb2tdSampleFact ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
    1656             :     {
    1657           0 :         return IVAS_ERR_INVALID_BUFFER_SIZE;
    1658             :     }
    1659             : 
    1660      422991 :     if ( outAudio.config.numChannels <= 0 || MAX_OUTPUT_CHANNELS < outAudio.config.numChannels )
    1661             :     {
    1662           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    1663             :     }
    1664             : 
    1665      422991 :     if ( isar_getAudioConfigType( hIvasRend->outputConfig ) == ISAR_POST_REND_AUDIO_CONFIG_TYPE_BINAURAL &&
    1666      422991 :          ( 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      422991 :     if ( ( error = ISAR_POST_REND_NumOutChannels( hIvasRend, &numOutChannels ) ) != IVAS_ERR_OK )
    1672             :     {
    1673           0 :         return error;
    1674             :     }
    1675             : 
    1676      422991 :     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      422991 :     set_zero( outAudio.data, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
    1683             : 
    1684      422991 :     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      422991 :         limitRendererOutput( hIvasRend->hLimiter, outAudio.data, outAudio.config.numSamplesPerChannel, IVAS_LIMITER_THRESHOLD );
    1694             : #endif
    1695             : 
    1696      422991 :     return IVAS_ERR_OK;
    1697             : }
    1698             : 
    1699             : 
    1700             : /*-------------------------------------------------------------------*
    1701             :  * ISAR_POST_REND_GetSplitBinauralSamples()
    1702             :  *
    1703             :  *
    1704             :  *-------------------------------------------------------------------*/
    1705             : 
    1706      422991 : 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      422991 :     if ( ( error = ISAR_POST_REND_getSamples( hIvasRend, outAudio ) ) != IVAS_ERR_OK )
    1714             :     {
    1715           0 :         return error;
    1716             :     }
    1717      422991 :     *needNewFrame = hIvasRend->inputsSplitPost[0].numCachedSamples == 0;
    1718             : 
    1719      422991 :     return IVAS_ERR_OK;
    1720             : }
    1721             : 
    1722             : 
    1723             : /*-------------------------------------------------------------------*
    1724             :  * ISAR_POST_REND_Close()
    1725             :  *
    1726             :  *
    1727             :  *-------------------------------------------------------------------*/
    1728             : 
    1729        2552 : 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        2552 :     if ( phIvasRend == NULL || *phIvasRend == NULL )
    1738             :     {
    1739           0 :         return;
    1740             :     }
    1741        2552 :     hIvasRend = *phIvasRend;
    1742             : 
    1743        5104 :     for ( i = 0; i < RENDERER_MAX_BIN_INPUTS; ++i )
    1744             :     {
    1745        2552 :         clearInputSplitRend( &hIvasRend->inputsSplitPost[i] );
    1746             :     }
    1747             : 
    1748        2552 :     ivas_limiter_close( &hIvasRend->hLimiter );
    1749             : 
    1750        2552 :     free( hIvasRend );
    1751        2552 :     *phIvasRend = NULL;
    1752             : 
    1753        2552 :     return;
    1754             : }
    1755             : 
    1756             : 
    1757             : /*-------------------------------------------------------------------*
    1758             :  * ISAR_REND_SetSplitRendBitstreamHeader()
    1759             :  *
    1760             :  *
    1761             :  *-------------------------------------------------------------------*/
    1762             : 
    1763        2552 : 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        2552 :     if ( hIvasRend == NULL )
    1773             :     {
    1774           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    1775             :     }
    1776             : 
    1777        2552 :     hIvasRend->splitRenderConfig.codec = codec;
    1778        2552 :     hIvasRend->splitRenderConfig.isar_frame_size_ms = isar_frame_size_ms;
    1779        2552 :     hIvasRend->splitRenderConfig.codec_frame_size_ms = codec_frame_size_ms;
    1780        2552 :     hIvasRend->splitRenderConfig.poseCorrectionMode = poseCorrection;
    1781        2552 :     hIvasRend->splitRenderConfig.lc3plus_highres = lc3plus_highres;
    1782             : 
    1783        2552 :     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

Generated by: LCOV version 1.14