LCOV - code coverage report
Current view: top level - lib_rend - lib_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main -- merged total coverage @ 9b04ec3cb36f5e8dc438cf854fa3e349998fa1e9 Lines: 2673 3260 82.0 %
Date: 2025-10-31 05:45:46 Functions: 170 185 91.9 %

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

Generated by: LCOV version 1.14