LCOV - code coverage report
Current view: top level - lib_rend - lib_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 03e3344c44a402d0c8b0bc96fcb37d7d6ad79076 Lines: 2748 3335 82.4 %
Date: 2025-11-18 06:47:09 Functions: 172 188 91.5 %

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

Generated by: LCOV version 1.14