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 @ d176c83da2faa7909092a44e56f1ca151bc1abea Lines: 2116 3137 67.5 %
Date: 2025-07-15 08:36:59 Functions: 133 171 77.8 %

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

Generated by: LCOV version 1.14