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 @ 6941acb1e9c9972134cc7f21f6593b4f4612f789 Lines: 2782 3371 82.5 %
Date: 2025-12-19 05:18:47 Functions: 174 190 91.6 %

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

Generated by: LCOV version 1.14