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 @ 0cd7d42dabc5060fab661f1bb61691d00471dffd Lines: 2748 3335 82.4 %
Date: 2025-12-02 06:46:41 Functions: 172 188 91.5 %

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

Generated by: LCOV version 1.14