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

Generated by: LCOV version 1.14