LCOV - code coverage report
Current view: top level - lib_rend - lib_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main -- merged total coverage @ 0c62f5312a76f89f3e6d6ab9a8d50516c9ab4059 Lines: 2748 3335 82.4 %
Date: 2025-12-17 10:49:08 Functions: 172 188 91.5 %

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

Generated by: LCOV version 1.14