LCOV - code coverage report
Current view: top level - lib_rend - lib_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 4a0546bde3a9a24d9bdb5bc9651456dab75c07ac Lines: 2782 3368 82.6 %
Date: 2026-01-23 05:20:12 Functions: 174 189 92.1 %

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

Generated by: LCOV version 1.14