LCOV - code coverage report
Current view: top level - lib_rend - lib_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ ce3afad1c76ae62bc18a70c8b764ccf68a4a905a Lines: 2673 3260 82.0 %
Date: 2025-10-16 04:54:04 Functions: 170 185 91.9 %

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

Generated by: LCOV version 1.14