LCOV - code coverage report
Current view: top level - lib_rend - lib_rend_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 3134 4455 70.3 %
Date: 2025-08-23 01:22:27 Functions: 135 170 79.4 %

          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 "basop_util.h"
      34             : #include "options.h"
      35             : #include "lib_rend.h"
      36             : #include "prot_fx.h"
      37             : #include "ivas_prot_fx.h"
      38             : #include "ivas_prot_rend_fx.h"
      39             : #include "isar_prot.h"
      40             : #include "isar_stat.h"
      41             : #include "lib_isar_pre_rend.h"
      42             : #include "ivas_cnst.h"
      43             : #include "ivas_rom_com.h"
      44             : #include "ivas_rom_com_fx.h"
      45             : #include "ivas_rom_rend.h"
      46             : #include <assert.h>
      47             : #include <math.h>
      48             : #include <stdbool.h>
      49             : #include "wmc_auto.h"
      50             : #ifdef DEBUGGING
      51             : #include "debug.h"
      52             : #endif
      53             : 
      54             : /*-------------------------------------------------------------------*
      55             :  * Local constants
      56             :  *-------------------------------------------------------------------*/
      57             : 
      58             : /* Maximum buffer length (total) in samples. */
      59             : #define MAX_BUFFER_LENGTH     ( MAX_BUFFER_LENGTH_PER_CHANNEL * MAX_INPUT_CHANNELS )
      60             : #define MAX_BIN_DELAY_SAMPLES 150 /* Maximum supported rendering latency for binaural IRs */
      61             : 
      62             : /*-------------------------------------------------------------------*
      63             :  * Local types
      64             :  *-------------------------------------------------------------------*/
      65             : 
      66             : typedef float pan_vector[MAX_OUTPUT_CHANNELS];
      67             : typedef float pan_matrix[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
      68             : typedef float rotation_gains[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
      69             : typedef Word32 pan_vector_fx[MAX_OUTPUT_CHANNELS];
      70             : typedef Word32 pan_matrix_fx[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS];
      71             : typedef Word16 rotation_gains_fx[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
      72             : typedef Word32 rotation_gains_Word32[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS];
      73             : typedef Word32 rotation_matrix_fx[3][3];
      74             : typedef float rotation_matrix[3][3];
      75             : 
      76             : /* EFAP wrapper to simplify writing panning gains to a vector that includes LFE channels */
      77             : typedef struct
      78             : {
      79             :     EFAP_HANDLE hEfap;
      80             :     AUDIO_CONFIG speakerConfig;
      81             :     const LSSETUP_CUSTOM_STRUCT *pCustomLsSetup; /* Pointer to main custom LS struct from renderer handle - doesn't need freeing */
      82             : } EFAP_WRAPPER;
      83             : 
      84             : /* Lightweight helper struct that gathers all information required for rendering
      85             :  * any config to any other config. Used to simplify signatures of rendering functions.
      86             :  *
      87             :  * This struct should store ONLY CONST POINTERS to data existing elsewhere.
      88             :  * Storing pointers instead of data itself ensures that no additional updates
      89             :  * are required when any of these are changed in the renderer. Making the pointers
      90             :  * const ensures that this data is only read, but not modified by the rendering functions. */
      91             : typedef struct
      92             : {
      93             :     const Word32 *pOutSampleRate;
      94             :     const AUDIO_CONFIG *pOutConfig;
      95             :     const LSSETUP_CUSTOM_STRUCT *pCustomLsOut;
      96             :     const EFAP_WRAPPER *pEfapOutWrapper;
      97             :     IVAS_REND_HeadRotData *pHeadRotData; // for now removing the const qualifier TODO: will modify later
      98             :     const RENDER_CONFIG_HANDLE *hhRendererConfig;
      99             :     const Word16 *pSplitRendBFI;
     100             :     const SPLIT_REND_WRAPPER *pSplitRendWrapper;
     101             :     const COMBINED_ORIENTATION_HANDLE *pCombinedOrientationData;
     102             : } rendering_context;
     103             : 
     104             : /* Common base for input structs */
     105             : typedef struct
     106             : {
     107             :     AUDIO_CONFIG inConfig;
     108             :     IVAS_REND_InputId id;
     109             :     IVAS_REND_AudioBuffer inputBuffer;
     110             :     Word32 gain_fx; /* Linear, not in dB Q30 */
     111             :     rendering_context ctx;
     112             :     Word32 numNewSamplesPerChannel; /* Used to keep track how much new audio was fed before rendering current frame */
     113             : } input_base;
     114             : 
     115             : typedef struct
     116             : {
     117             :     input_base base;
     118             :     IVAS_ISM_METADATA currentPos;
     119             :     IVAS_ISM_METADATA previousPos;
     120             :     TDREND_WRAPPER tdRendWrapper;
     121             :     CREND_WRAPPER_HANDLE crendWrapper;
     122             :     REVERB_HANDLE hReverb;
     123             :     rotation_matrix_fx rot_mat_prev;
     124             :     pan_vector_fx prev_pan_gains_fx;
     125             :     rotation_matrix_fx rot_mat_prev_fx;
     126             :     pan_vector prev_pan_gains;
     127             :     Word8 firstFrameRendered;
     128             :     TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */
     129             :     Word32 *bufferData_fx;
     130             :     Word16 nonDiegeticPan;
     131             :     Word32 nonDiegeticPanGain_fx; /* Q31 */
     132             :     OMASA_ANA_HANDLE hOMasa;
     133             :     UWord16 total_num_objects;
     134             :     Word32 ism_metadata_delay_ms_fx; /* Q0 */
     135             : } input_ism;
     136             : 
     137             : typedef struct
     138             : {
     139             :     Word16 numLfeChannels;
     140             :     bool pan_lfe;
     141             :     // float lfeInputGain;
     142             :     Word32 lfeInputGain_fx; /* Q31 */
     143             :     // float lfeOutputAzimuth;
     144             :     Word16 lfeOutputAzimuth_fx;
     145             :     // float lfeOutputElevation;
     146             :     Word16 lfeOutputElevation_fx;
     147             :     // IVAS_REND_LfePanMtx lfePanMtx;
     148             :     IVAS_REND_LfePanMtx_fx lfePanMtx_fx; /* Q31 */
     149             : } lfe_routing;
     150             : 
     151             : typedef struct
     152             : {
     153             :     input_base base;
     154             : 
     155             :     /* Full panning matrix. 1st index is input channel, 2nd index is output channel.
     156             :        All LFE channels should be included, both for inputs and outputs */
     157             :     pan_matrix_fx panGains_fx; /* Q31 */
     158             : 
     159             :     LSSETUP_CUSTOM_STRUCT customLsInput;
     160             :     EFAP_WRAPPER efapInWrapper;
     161             :     TDREND_WRAPPER tdRendWrapper;
     162             :     CREND_WRAPPER_HANDLE crendWrapper;
     163             :     TDREND_WRAPPER splitTdRendWrappers[MAX_HEAD_ROT_POSES - 1]; /* Additional TD Rend instances used for split rendering */
     164             :     REVERB_HANDLE hReverb;
     165             :     rotation_gains_Word32 rot_gains_prev_fx[MAX_HEAD_ROT_POSES];
     166             :     Word16 nonDiegeticPan;
     167             :     Word32 nonDiegeticPanGain_fx;
     168             :     lfe_routing lfeRouting;
     169             :     Word32 *bufferData_fx;
     170             :     Word16 binauralDelaySmp;
     171             :     Word32 *lfeDelayBuffer_fx;
     172             :     MCMASA_ANA_HANDLE hMcMasa;
     173             : } input_mc;
     174             : 
     175             : typedef struct
     176             : {
     177             :     input_base base;
     178             :     // pan_matrix hoaDecMtx;
     179             :     pan_matrix_fx hoaDecMtx_fx;
     180             :     CLDFB_REND_WRAPPER cldfbRendWrapper;
     181             :     CREND_WRAPPER_HANDLE crendWrapper;
     182             :     rotation_gains_fx rot_gains_prev_fx[MAX_HEAD_ROT_POSES];
     183             :     Word32 *bufferData_fx;
     184             :     DIRAC_ANA_HANDLE hDirAC;
     185             : } input_sba;
     186             : 
     187             : typedef struct
     188             : {
     189             :     input_base base;
     190             :     MASA_METADATA_FRAME masaMetadata;
     191             :     bool metadataHasBeenFed;
     192             :     Word32 *bufferData_fx;
     193             :     MASA_EXT_REND_HANDLE hMasaExtRend;
     194             :     MASA_PREREND_HANDLE hMasaPrerend;
     195             : } input_masa;
     196             : 
     197             : typedef struct hrtf_handles
     198             : {
     199             :     IVAS_DEC_HRTF_CREND_HANDLE hSetOfHRTF;
     200             :     IVAS_DEC_HRTF_FASTCONV_HANDLE hHrtfFastConv;
     201             :     IVAS_DEC_HRTF_PARAMBIN_HANDLE hHrtfParambin;
     202             :     IVAS_DEC_HRTF_HANDLE hHrtfTD;
     203             :     IVAS_DEC_HRTF_STATISTICS_HANDLE hHrtfStatistics;
     204             : } hrtf_handles;
     205             : 
     206             : 
     207             : struct IVAS_REND
     208             : {
     209             :     Word32 sampleRateOut;
     210             :     IVAS_LIMITER_HANDLE hLimiter;
     211             : 
     212             :     input_ism inputsIsm[RENDERER_MAX_ISM_INPUTS];
     213             :     input_mc inputsMc[RENDERER_MAX_MC_INPUTS];
     214             :     input_sba inputsSba[RENDERER_MAX_SBA_INPUTS];
     215             :     input_masa inputsMasa[RENDERER_MAX_MASA_INPUTS];
     216             : 
     217             :     AUDIO_CONFIG inputConfig;
     218             :     AUDIO_CONFIG outputConfig;
     219             :     EFAP_WRAPPER efapOutWrapper;
     220             :     IVAS_LSSETUP_CUSTOM_STRUCT customLsOut;
     221             : 
     222             :     SPLIT_REND_WRAPPER *splitRendWrapper;
     223             :     IVAS_REND_AudioBuffer splitRendEncBuffer;
     224             :     IVAS_REND_HeadRotData headRotData;
     225             :     Word16 splitRendBFI;
     226             : 
     227             :     EXTERNAL_ORIENTATION_HANDLE hExternalOrientationData;
     228             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData;
     229             : 
     230             :     Word8 rendererConfigEnabled;
     231             :     RENDER_CONFIG_DATA *hRendererConfig; /* Renderer config pointer */
     232             : 
     233             :     Word16 num_subframes;
     234             :     hrtf_handles hHrtfs;
     235             : };
     236             : 
     237             : 
     238             : /*-------------------------------------------------------------------*
     239             :  * Local function prototypes
     240             :  *-------------------------------------------------------------------*/
     241             : 
     242             : static ivas_error initMasaExtRenderer( input_masa *inputMasa, const AUDIO_CONFIG outConfig, const RENDER_CONFIG_DATA *hRendCfg, hrtf_handles *hHrtfs );
     243             : 
     244             : static void freeMasaExtRenderer( MASA_EXT_REND_HANDLE *hMasaExtRendOut );
     245             : 
     246             : static void intermidiate_ext_dirac_render( MASA_EXT_REND_HANDLE hMasaExtRend, Word16 to_fix );
     247             : 
     248             : static ivas_error renderSbaToMultiBinauralCldfb( input_sba *sbaInput, Word32 Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], Word32 Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX], const Word16 low_res_pre_rend_rot, const Word16 num_subframes, const Word16 Q_in );
     249             : #ifdef FIX_1843_IO_QFACTOR_INIT
     250             : static ivas_error renderSbaToMultiBinaural( input_sba *sbaInput, const AUDIO_CONFIG outConfig, Word32 out[][L_FRAME48k], const Word16 *pq_fact );
     251             : #else
     252             : static ivas_error renderSbaToMultiBinaural( input_sba *sbaInput, const AUDIO_CONFIG outConfig, Word32 out[][L_FRAME48k] );
     253             : #endif
     254             : 
     255             : 
     256             : /*-------------------------------------------------------------------*
     257             :  * Local functions
     258             :  *-------------------------------------------------------------------*/
     259             : 
     260         973 : static ivas_error allocateInputBaseBufferData_fx(
     261             :     Word32 **data, /* Qx */
     262             :     const Word16 data_size )
     263             : {
     264         973 :     *data = (Word32 *) malloc( data_size * sizeof( Word32 ) );
     265         973 :     IF( *data == NULL )
     266             :     {
     267           0 :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for input base buffer data" );
     268             :     }
     269             : 
     270         973 :     return IVAS_ERR_OK;
     271             : }
     272        4662 : static void freeInputBaseBufferData_fx(
     273             :     Word32 **data /* Qx */ )
     274             : {
     275        4662 :     IF( *data != NULL )
     276             :     {
     277         973 :         free( *data );
     278         973 :         *data = NULL;
     279             :     }
     280             : 
     281        4662 :     return;
     282             : }
     283         372 : static ivas_error allocateMcLfeDelayBuffer_fx(
     284             :     Word32 **lfeDelayBuffer, /* Qx */
     285             :     const Word16 data_size )
     286             : {
     287         372 :     *lfeDelayBuffer = (Word32 *) malloc( data_size * sizeof( Word32 ) );
     288         372 :     IF( *lfeDelayBuffer == NULL )
     289             :     {
     290           0 :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for LFE delay buffer" );
     291             :     }
     292             : 
     293         372 :     return IVAS_ERR_OK;
     294             : }
     295         666 : static void freeMcLfeDelayBuffer_fx(
     296             :     Word32 **lfeDelayBuffer /* Qx */ )
     297             : {
     298         666 :     IF( *lfeDelayBuffer != NULL )
     299             :     {
     300         372 :         free( *lfeDelayBuffer );
     301         372 :         *lfeDelayBuffer = NULL;
     302             :     }
     303             : 
     304         666 :     return;
     305             : }
     306             : 
     307             : 
     308         235 : static IVAS_QUATERNION quaternionInit_fx(
     309             :     void )
     310             : {
     311             :     IVAS_QUATERNION q;
     312         235 :     q.w_fx = ONE_IN_Q29;
     313         235 :     move32();
     314         235 :     q.x_fx = q.y_fx = q.z_fx = 0;
     315         235 :     move32();
     316         235 :     move32();
     317         235 :     move32();
     318             : 
     319         235 :     q.q_fact = Q29;
     320         235 :     move16();
     321         235 :     move16();
     322         235 :     move16();
     323         235 :     move16();
     324             : 
     325         235 :     return q;
     326             : }
     327             : 
     328   221694105 : static Word32 *getSmplPtr_fx(
     329             :     IVAS_REND_AudioBuffer buffer,
     330             :     const UWord32 chnlIdx,
     331             :     const UWord32 smplIdx )
     332             : {
     333   221694105 :     return buffer.data_fx + chnlIdx * buffer.config.numSamplesPerChannel + smplIdx;
     334             : }
     335             : 
     336           0 : static void convertBitsBufferToInternalBitsBuff(
     337             :     const IVAS_REND_BitstreamBuffer outBits,
     338             :     ISAR_SPLIT_REND_BITS_HANDLE hBits )
     339             : {
     340           0 :     hBits->bits_buf = outBits.bits;
     341           0 :     hBits->bits_read = outBits.config.bitsRead;
     342           0 :     hBits->bits_written = outBits.config.bitsWritten;
     343           0 :     hBits->buf_len = outBits.config.bufLenInBytes;
     344           0 :     hBits->codec = outBits.config.codec;
     345           0 :     hBits->pose_correction = outBits.config.poseCorrection;
     346           0 :     hBits->codec_frame_size_ms = outBits.config.codec_frame_size_ms;
     347             : 
     348           0 :     move16();
     349           0 :     move32();
     350           0 :     move32();
     351           0 :     move32();
     352           0 :     move32();
     353           0 :     move32();
     354           0 :     move32();
     355             : 
     356           0 :     return;
     357             : }
     358             : 
     359           0 : static void convertInternalBitsBuffToBitsBuffer(
     360             :     IVAS_REND_BitstreamBuffer *hOutBits,
     361             :     const ISAR_SPLIT_REND_BITS_DATA bits )
     362             : {
     363           0 :     hOutBits->bits = bits.bits_buf;
     364           0 :     hOutBits->config.bitsRead = bits.bits_read;
     365           0 :     hOutBits->config.bitsWritten = bits.bits_written;
     366           0 :     hOutBits->config.bufLenInBytes = bits.buf_len;
     367           0 :     hOutBits->config.codec = bits.codec;
     368           0 :     hOutBits->config.poseCorrection = bits.pose_correction;
     369           0 :     hOutBits->config.codec_frame_size_ms = bits.codec_frame_size_ms;
     370             : 
     371           0 :     return;
     372             : }
     373             : 
     374           0 : static void copyBufferToCLDFBarray_fx(
     375             :     const IVAS_REND_AudioBuffer buffer,
     376             :     Word32 re[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
     377             :     Word32 im[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX] )
     378             : {
     379             :     UWord32 smplIdx, slotIdx;
     380             :     UWord32 numCldfbSamples, num_bands;
     381             :     UWord32 chnlIdx;
     382             :     const Word32 *readPtr;
     383             : 
     384           0 :     assert( ( buffer.config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
     385           0 :     readPtr = buffer.data_fx;
     386           0 :     numCldfbSamples = (UWord32) shr( buffer.config.numSamplesPerChannel, 1 );
     387           0 :     num_bands = (UWord32) Mpy_32_32( numCldfbSamples, ONE_BY_CLDFB_NO_COL_MAX_Q31 );
     388           0 :     FOR( chnlIdx = 0; chnlIdx < (UWord32) buffer.config.numChannels; ++chnlIdx )
     389             :     {
     390           0 :         FOR( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
     391             :         {
     392           0 :             FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
     393             :             {
     394           0 :                 re[chnlIdx][slotIdx][smplIdx] = *readPtr++;
     395             :             }
     396           0 :             FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
     397             :             {
     398           0 :                 im[chnlIdx][slotIdx][smplIdx] = *readPtr++;
     399             :             }
     400             :         }
     401             :     }
     402             : 
     403           0 :     return;
     404             : }
     405             : 
     406           0 : static void accumulateCLDFBArrayToBuffer_fx(
     407             :     Word32 re[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
     408             :     Word32 im[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
     409             :     IVAS_REND_AudioBuffer *buffer )
     410             : {
     411             :     UWord32 smplIdx, slotIdx;
     412             :     UWord32 numCldfbSamples, num_bands;
     413             :     Word16 chnlIdx;
     414             :     Word32 *writePtr;
     415             : 
     416           0 :     assert( ( buffer->config.is_cldfb == 1 ) && "for time domain input call copyBufferTo2dArray()" );
     417           0 :     writePtr = buffer->data_fx;
     418           0 :     numCldfbSamples = (UWord32) shr( buffer->config.numSamplesPerChannel, 1 );
     419           0 :     num_bands = (UWord32) Mpy_32_32( numCldfbSamples, ONE_BY_CLDFB_NO_COL_MAX_Q31 );
     420             : 
     421           0 :     FOR( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
     422             :     {
     423           0 :         FOR( slotIdx = 0; slotIdx < CLDFB_NO_COL_MAX; ++slotIdx )
     424             :         {
     425           0 :             FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
     426             :             {
     427           0 :                 *writePtr++ += re[chnlIdx][slotIdx][smplIdx];
     428             :             }
     429           0 :             FOR( smplIdx = 0; smplIdx < num_bands; ++smplIdx )
     430             :             {
     431           0 :                 *writePtr++ += im[chnlIdx][slotIdx][smplIdx];
     432             :             }
     433             :         }
     434             :     }
     435             : 
     436           0 :     return;
     437             : }
     438             : 
     439      645648 : static void copyBufferTo2dArray_fx(
     440             :     const IVAS_REND_AudioBuffer buffer,
     441             :     Word32 array[][L_FRAME48k] )
     442             : {
     443             :     UWord32 smplIdx;
     444             :     UWord32 chnlIdx;
     445             :     const Word32 *readPtr;
     446             : 
     447      645648 :     assert( ( buffer.config.is_cldfb == 0 ) && "for CLDFB input call copyBufferToCLDFBarray()" );
     448             : 
     449      645648 :     readPtr = buffer.data_fx;
     450             : 
     451     4639512 :     FOR( chnlIdx = 0; chnlIdx < (UWord32) buffer.config.numChannels; ++chnlIdx )
     452             :     {
     453  1539660264 :         FOR( smplIdx = 0; smplIdx < (UWord32) buffer.config.numSamplesPerChannel; ++smplIdx )
     454             :         {
     455  1535666400 :             array[chnlIdx][smplIdx] = *readPtr++;
     456  1535666400 :             move32();
     457             :         }
     458             :     }
     459             : 
     460      645648 :     return;
     461             : }
     462      645648 : static void accumulate2dArrayToBuffer_fx(
     463             :     Word32 array[][L_FRAME48k],
     464             :     const IVAS_REND_AudioBuffer *buffer )
     465             : {
     466             :     Word16 smplIdx, chnlIdx;
     467             :     Word32 *writePtr;
     468             : 
     469      645648 :     writePtr = buffer->data_fx;
     470     2020944 :     FOR( chnlIdx = 0; chnlIdx < buffer->config.numChannels; ++chnlIdx )
     471             :     {
     472   530200896 :         FOR( smplIdx = 0; smplIdx < buffer->config.numSamplesPerChannel; ++smplIdx )
     473             :         {
     474   528825600 :             *writePtr = L_add( *writePtr, array[chnlIdx][smplIdx] );
     475   528825600 :             move32();
     476   528825600 :             writePtr++;
     477             :         }
     478             :     }
     479             : 
     480      645648 :     return;
     481             : }
     482             : /*-------------------------------------------------------------------*
     483             :  * limitRendererOutput()
     484             :  *
     485             :  * In-place saturation control for multichannel buffers with adaptive release time
     486             :  *-------------------------------------------------------------------*/
     487             : 
     488             : #ifndef DISABLE_LIMITER
     489             : /*! r: number of clipped output samples */
     490     1126140 : static Word32 limitRendererOutput_fx(
     491             :     IVAS_LIMITER_HANDLE hLimiter, /* i/o: limiter struct handle                                           */
     492             :     Word32 *output,               /* i/o: I/O buffer                                          Q(q_factor) */
     493             :     const Word16 output_frame,    /* i  : number of samples per channel in the buffer                     */
     494             :     const Word32 threshold,       /* i  : signal amplitude above which limiting starts to be applied      */
     495             :     Word16 q_factor )             /* i : q factor of output samples */
     496             : {
     497             :     Word16 i;
     498             :     Word32 **channels;
     499             :     Word16 num_channels;
     500     1126140 :     Word32 numClipping = 0;
     501     1126140 :     move32();
     502             : 
     503             :     /* return early if given bad parameters */
     504     1126140 :     test();
     505     1126140 :     test();
     506     1126140 :     IF( hLimiter == NULL || output == NULL || output_frame <= 0 )
     507             :     {
     508           0 :         return 0;
     509             :     }
     510             : 
     511     1126140 :     channels = hLimiter->channel_ptrs_fx;
     512     1126140 :     num_channels = hLimiter->num_channels;
     513     1126140 :     move16();
     514             : 
     515     7755488 :     FOR( i = 0; i < num_channels; ++i )
     516             :     {
     517     6629348 :         channels[i] = output + imult1616( i, output_frame );
     518             :     }
     519             : 
     520     1126140 :     limiter_process_fx( hLimiter, output_frame, threshold, 0, NULL, q_factor );
     521             : 
     522             :     /* Apply clipping to buffer in case the limiter let through some samples > 1.0f */
     523  2809398780 :     FOR( i = 0; i < output_frame * num_channels; ++i )
     524             :     {
     525             : 
     526  2808272640 :         output[i] = L_min( L_max( L_shl( INT16_MIN, q_factor ), output[i] ), L_shl( INT16_MAX, q_factor ) );
     527  2808272640 :         move32();
     528             :     }
     529             : 
     530     1126140 :     return numClipping;
     531             : }
     532             : #endif
     533             : 
     534             : /*-------------------------------------------------------------------*
     535             :  * validateOutputAudioConfig()
     536             :  *
     537             :  *
     538             :  *-------------------------------------------------------------------*/
     539             : 
     540         666 : static ivas_error validateOutputAudioConfig(
     541             :     const AUDIO_CONFIG outConfig )
     542             : {
     543         666 :     SWITCH( outConfig )
     544             :     {
     545         666 :         case IVAS_AUDIO_CONFIG_MONO:
     546             :         case IVAS_AUDIO_CONFIG_STEREO:
     547             :         case IVAS_AUDIO_CONFIG_5_1:
     548             :         case IVAS_AUDIO_CONFIG_7_1:
     549             :         case IVAS_AUDIO_CONFIG_5_1_2:
     550             :         case IVAS_AUDIO_CONFIG_5_1_4:
     551             :         case IVAS_AUDIO_CONFIG_7_1_4:
     552             :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
     553             :         case IVAS_AUDIO_CONFIG_FOA:
     554             :         case IVAS_AUDIO_CONFIG_HOA2:
     555             :         case IVAS_AUDIO_CONFIG_HOA3:
     556             :         case IVAS_AUDIO_CONFIG_BINAURAL:
     557             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
     558             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
     559             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
     560             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
     561             :         case IVAS_AUDIO_CONFIG_MASA1:
     562             :         case IVAS_AUDIO_CONFIG_MASA2:
     563         666 :             return IVAS_ERR_OK;
     564           0 :         default:
     565           0 :             BREAK;
     566             :     }
     567             : 
     568           0 :     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
     569             : }
     570             : 
     571             : /*-------------------------------------------------------------------*
     572             :  * getAudioConfigType()
     573             :  *
     574             :  *
     575             :  *-------------------------------------------------------------------*/
     576             : 
     577     8577259 : IVAS_REND_AudioConfigType getAudioConfigType(
     578             :     const AUDIO_CONFIG config )
     579             : {
     580             :     IVAS_REND_AudioConfigType type;
     581             : 
     582     8577259 :     SWITCH( config )
     583             :     {
     584     4296568 :         case IVAS_AUDIO_CONFIG_MONO:
     585             :         case IVAS_AUDIO_CONFIG_STEREO:
     586             :         case IVAS_AUDIO_CONFIG_5_1:
     587             :         case IVAS_AUDIO_CONFIG_7_1:
     588             :         case IVAS_AUDIO_CONFIG_5_1_2:
     589             :         case IVAS_AUDIO_CONFIG_5_1_4:
     590             :         case IVAS_AUDIO_CONFIG_7_1_4:
     591             :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
     592     4296568 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
     593     4296568 :             move16();
     594     4296568 :             BREAK;
     595     1433563 :         case IVAS_AUDIO_CONFIG_FOA:
     596             :         case IVAS_AUDIO_CONFIG_HOA2:
     597             :         case IVAS_AUDIO_CONFIG_HOA3:
     598     1433563 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS;
     599     1433563 :             move16();
     600     1433563 :             BREAK;
     601      301983 :         case IVAS_AUDIO_CONFIG_OBA:
     602      301983 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
     603      301983 :             move16();
     604      301983 :             BREAK;
     605     2536040 :         case IVAS_AUDIO_CONFIG_BINAURAL:
     606             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
     607             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
     608             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
     609             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
     610     2536040 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL;
     611     2536040 :             move16();
     612     2536040 :             BREAK;
     613        9105 :         case IVAS_AUDIO_CONFIG_MASA1:
     614             :         case IVAS_AUDIO_CONFIG_MASA2:
     615        9105 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_MASA;
     616        9105 :             move16();
     617        9105 :             BREAK;
     618           0 :         default:
     619           0 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN;
     620           0 :             move16();
     621           0 :             BREAK;
     622             :     }
     623             : 
     624     8577259 :     return type;
     625             : }
     626             : 
     627             : /*-------------------------------------------------------------------*
     628             :  * validateOutputSampleRate()
     629             :  *
     630             :  *
     631             :  *-------------------------------------------------------------------*/
     632             : 
     633         666 : static ivas_error validateOutputSampleRate(
     634             :     const Word32 sampleRate,
     635             :     const AUDIO_CONFIG outConfig )
     636             : {
     637             : 
     638         666 :     IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
     639             :     {
     640             :         /* If no binaural rendering, any sampling rate is supported */
     641         478 :         return IVAS_ERR_OK;
     642             :     }
     643         188 :     ELSE IF( ( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) && NE_32( sampleRate, 48000 ) )
     644             :     {
     645           0 :         return IVAS_ERROR( IVAS_ERR_INVALID_SAMPLING_RATE, "Error: Only 48kHz output sampling rate is supported for split rendering." );
     646             :     }
     647             :     ELSE
     648             :     {
     649             : 
     650             :         /* Otherwise rendering to binaural, support the same set as IVAS decoder */
     651         188 :         SWITCH( sampleRate )
     652             :         {
     653         188 :             case 16000:
     654             :             case 32000:
     655             :             case 48000:
     656         188 :                 return IVAS_ERR_OK;
     657             :         }
     658             : 
     659           0 :         return IVAS_ERR_INVALID_SAMPLING_RATE;
     660             :     }
     661             : }
     662             : 
     663             : /*-------------------------------------------------------------------*
     664             :  * getAudioConfigNumChannels()
     665             :  *
     666             :  *
     667             :  *-------------------------------------------------------------------*/
     668             : 
     669     6162551 : ivas_error getAudioConfigNumChannels(
     670             :     const AUDIO_CONFIG config,
     671             :     Word16 *numChannels )
     672             : {
     673     6162551 :     SWITCH( config )
     674             :     {
     675     1484449 :         case IVAS_AUDIO_CONFIG_MONO:
     676             :         case IVAS_AUDIO_CONFIG_OBA:
     677             :         case IVAS_AUDIO_CONFIG_MASA1:
     678     1484449 :             *numChannels = 1;
     679     1484449 :             move16();
     680     1484449 :             BREAK;
     681     1558128 :         case IVAS_AUDIO_CONFIG_STEREO:
     682             :         case IVAS_AUDIO_CONFIG_BINAURAL:
     683             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
     684             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
     685             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
     686             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
     687             :         case IVAS_AUDIO_CONFIG_MASA2:
     688     1558128 :             *numChannels = 2;
     689     1558128 :             move16();
     690     1558128 :             BREAK;
     691      345290 :         case IVAS_AUDIO_CONFIG_FOA:
     692      345290 :             *numChannels = 4;
     693      345290 :             move16();
     694      345290 :             BREAK;
     695      403308 :         case IVAS_AUDIO_CONFIG_5_1:
     696      403308 :             *numChannels = 6;
     697      403308 :             move16();
     698      403308 :             BREAK;
     699      278307 :         case IVAS_AUDIO_CONFIG_7_1:
     700             :         case IVAS_AUDIO_CONFIG_5_1_2:
     701      278307 :             *numChannels = 8;
     702      278307 :             move16();
     703      278307 :             BREAK;
     704      339969 :         case IVAS_AUDIO_CONFIG_HOA2:
     705      339969 :             *numChannels = 9;
     706      339969 :             move16();
     707      339969 :             BREAK;
     708      149099 :         case IVAS_AUDIO_CONFIG_5_1_4:
     709      149099 :             *numChannels = 10;
     710      149099 :             move16();
     711      149099 :             BREAK;
     712     1263131 :         case IVAS_AUDIO_CONFIG_7_1_4:
     713     1263131 :             *numChannels = 12;
     714     1263131 :             move16();
     715     1263131 :             BREAK;
     716      340870 :         case IVAS_AUDIO_CONFIG_HOA3:
     717      340870 :             *numChannels = 16;
     718      340870 :             move16();
     719      340870 :             BREAK;
     720           0 :         default:
     721           0 :             return IVAS_ERR_NUM_CHANNELS_UNKNOWN;
     722             :     }
     723             : 
     724     6162551 :     move16();
     725     6162551 :     return IVAS_ERR_OK;
     726             : }
     727             : 
     728             : /*-------------------------------------------------------------------*
     729             :  * Local functions
     730             :  *-------------------------------------------------------------------*/
     731             : 
     732         713 : static ivas_error initLimiter(
     733             :     IVAS_LIMITER_HANDLE *phLimiter,
     734             :     const Word16 numChannels,
     735             :     const Word32 sampleRate )
     736             : {
     737             :     ivas_error error;
     738             : 
     739             :     /* If re-initializing with unchanged values, return early */
     740         713 :     test();
     741         713 :     test();
     742         713 :     IF( *phLimiter != NULL && EQ_16( ( *phLimiter )->num_channels, numChannels ) && EQ_32( ( *phLimiter )->sampling_rate, sampleRate ) )
     743             :     {
     744           0 :         return IVAS_ERR_OK;
     745             :     }
     746             : 
     747             :     /* Support re-init: close if already allocated */
     748         713 :     IF( *phLimiter != NULL )
     749             :     {
     750          47 :         ivas_limiter_close_fx( phLimiter );
     751             :     }
     752             : 
     753         713 :     IF( NE_32( ( error = ivas_limiter_open_fx( phLimiter, numChannels, sampleRate ) ), IVAS_ERR_OK ) )
     754             :     {
     755           0 :         return error;
     756             :     }
     757             : 
     758         713 :     return IVAS_ERR_OK;
     759             : }
     760        1038 : static LSSETUP_CUSTOM_STRUCT defaultCustomLs(
     761             :     void )
     762             : {
     763             :     LSSETUP_CUSTOM_STRUCT ls;
     764             : 
     765             :     /* Set mono by default. This simplifies initialization,
     766             :        since output config is never in an undefined state. */
     767        1038 :     ls.is_planar_setup = 1;
     768        1038 :     ls.num_spk = 1;
     769        1038 :     move16();
     770        1038 :     move16();
     771        1038 :     set32_fx( ls.ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS );
     772        1038 :     set32_fx( ls.ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS );
     773        1038 :     ls.num_lfe = 0;
     774        1038 :     move16();
     775        1038 :     set16_fx( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
     776        1038 :     ls.separate_ch_found = 0;
     777        1038 :     move16();
     778        1038 :     set16_fx( ls.separate_ch_gains_fx, 0, MAX_OUTPUT_CHANNELS );
     779             : 
     780        1038 :     return ls;
     781             : }
     782             : 
     783             : 
     784       13041 : static ivas_error getSpeakerAzimuths_fx(
     785             :     AUDIO_CONFIG config,
     786             :     const Word32 **azimuths /* Q22 */ )
     787             : {
     788       13041 :     SWITCH( config )
     789             :     {
     790          63 :         case IVAS_AUDIO_CONFIG_MONO:
     791          63 :             *azimuths = ls_azimuth_CICP1_fx;
     792          63 :             BREAK;
     793          67 :         case IVAS_AUDIO_CONFIG_STEREO:
     794          67 :             *azimuths = ls_azimuth_CICP2_fx;
     795          67 :             BREAK;
     796        5057 :         case IVAS_AUDIO_CONFIG_5_1:
     797        5057 :             *azimuths = ls_azimuth_CICP6_fx;
     798        5057 :             BREAK;
     799         807 :         case IVAS_AUDIO_CONFIG_7_1:
     800         807 :             *azimuths = ls_azimuth_CICP12_fx;
     801         807 :             BREAK;
     802        2307 :         case IVAS_AUDIO_CONFIG_5_1_2:
     803        2307 :             *azimuths = ls_azimuth_CICP14_fx;
     804        2307 :             BREAK;
     805        2313 :         case IVAS_AUDIO_CONFIG_5_1_4:
     806        2313 :             *azimuths = ls_azimuth_CICP16_fx;
     807        2313 :             BREAK;
     808        2427 :         case IVAS_AUDIO_CONFIG_7_1_4:
     809        2427 :             *azimuths = ls_azimuth_CICP19_fx;
     810        2427 :             BREAK;
     811           0 :         default:
     812           0 :             return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
     813             :     }
     814             : 
     815       13041 :     return IVAS_ERR_OK;
     816             : }
     817             : 
     818       13041 : static ivas_error getSpeakerElevations_fx(
     819             :     AUDIO_CONFIG config,
     820             :     const Word32 **elevations /* Q22 */ )
     821             : {
     822       13041 :     SWITCH( config )
     823             :     {
     824          63 :         case IVAS_AUDIO_CONFIG_MONO:
     825          63 :             *elevations = ls_elevation_CICP1_fx;
     826          63 :             BREAK;
     827          67 :         case IVAS_AUDIO_CONFIG_STEREO:
     828          67 :             *elevations = ls_elevation_CICP2_fx;
     829          67 :             BREAK;
     830        5057 :         case IVAS_AUDIO_CONFIG_5_1:
     831        5057 :             *elevations = ls_elevation_CICP6_fx;
     832        5057 :             BREAK;
     833         807 :         case IVAS_AUDIO_CONFIG_7_1:
     834         807 :             *elevations = ls_elevation_CICP12_fx;
     835         807 :             BREAK;
     836        2307 :         case IVAS_AUDIO_CONFIG_5_1_2:
     837        2307 :             *elevations = ls_elevation_CICP14_fx;
     838        2307 :             BREAK;
     839        2313 :         case IVAS_AUDIO_CONFIG_5_1_4:
     840        2313 :             *elevations = ls_elevation_CICP16_fx;
     841        2313 :             BREAK;
     842        2427 :         case IVAS_AUDIO_CONFIG_7_1_4:
     843        2427 :             *elevations = ls_elevation_CICP19_fx;
     844        2427 :             BREAK;
     845           0 :         default:
     846           0 :             return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
     847             :     }
     848             : 
     849       13041 :     return IVAS_ERR_OK;
     850             : }
     851             : 
     852      273197 : static ivas_error getAmbisonicsOrder_fx(
     853             :     AUDIO_CONFIG config,
     854             :     Word16 *order )
     855             : {
     856      273197 :     SWITCH( config )
     857             :     {
     858       91075 :         case IVAS_AUDIO_CONFIG_FOA:
     859       91075 :             *order = 1;
     860       91075 :             move16();
     861       91075 :             BREAK;
     862       91061 :         case IVAS_AUDIO_CONFIG_HOA2:
     863       91061 :             *order = 2;
     864       91061 :             move16();
     865       91061 :             BREAK;
     866       91061 :         case IVAS_AUDIO_CONFIG_HOA3:
     867       91061 :             *order = 3;
     868       91061 :             move16();
     869       91061 :             BREAK;
     870           0 :         default:
     871           0 :             return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unsupported audio config" );
     872             :     }
     873             : 
     874      273197 :     return IVAS_ERR_OK;
     875             : }
     876             : 
     877             : 
     878           0 : static Word16 getNumLfeChannels(
     879             :     input_mc *inputMc )
     880             : {
     881           0 :     SWITCH( inputMc->base.inConfig )
     882             :     {
     883           0 :         case IVAS_AUDIO_CONFIG_5_1:
     884             :         case IVAS_AUDIO_CONFIG_7_1:
     885             :         case IVAS_AUDIO_CONFIG_5_1_2:
     886             :         case IVAS_AUDIO_CONFIG_5_1_4:
     887             :         case IVAS_AUDIO_CONFIG_7_1_4:
     888           0 :             return 1;
     889           0 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
     890           0 :             return inputMc->customLsInput.num_lfe;
     891           0 :         default:
     892           0 :             BREAK;
     893             :     }
     894             : 
     895           0 :     return 0;
     896             : }
     897         541 : static ivas_error getNumNonLfeChannelsInSpeakerLayout(
     898             :     AUDIO_CONFIG config,
     899             :     Word16 *numNonLfeChannels )
     900             : {
     901         541 :     SWITCH( config )
     902             :     {
     903          63 :         case IVAS_AUDIO_CONFIG_MONO:
     904          63 :             *numNonLfeChannels = 1;
     905          63 :             move16();
     906          63 :             BREAK;
     907          67 :         case IVAS_AUDIO_CONFIG_STEREO:
     908          67 :             *numNonLfeChannels = 2;
     909          67 :             move16();
     910          67 :             BREAK;
     911          57 :         case IVAS_AUDIO_CONFIG_5_1:
     912          57 :             *numNonLfeChannels = 5;
     913          57 :             move16();
     914          57 :             BREAK;
     915         114 :         case IVAS_AUDIO_CONFIG_5_1_2:
     916             :         case IVAS_AUDIO_CONFIG_7_1:
     917         114 :             *numNonLfeChannels = 7;
     918         114 :             move16();
     919         114 :             BREAK;
     920          63 :         case IVAS_AUDIO_CONFIG_5_1_4:
     921          63 :             *numNonLfeChannels = 9;
     922          63 :             move16();
     923          63 :             BREAK;
     924         177 :         case IVAS_AUDIO_CONFIG_7_1_4:
     925         177 :             *numNonLfeChannels = 11;
     926         177 :             move16();
     927         177 :             BREAK;
     928           0 :         default:
     929           0 :             return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Unexpected audio config" );
     930             :     }
     931             : 
     932         541 :     return IVAS_ERR_OK;
     933             : }
     934       25504 : static ivas_error getMcConfigValues_fx(
     935             :     AUDIO_CONFIG inConfig,
     936             :     const LSSETUP_CUSTOM_STRUCT *pInCustomLs,
     937             :     const Word32 **azimuth,   /* Q22 */
     938             :     const Word32 **elevation, /* Q22 */
     939             :     Word16 *lfe_idx,
     940             :     Word16 *is_planar )
     941             : {
     942             :     Word16 i;
     943             :     ivas_error error;
     944             : 
     945       25504 :     *lfe_idx = -1;
     946       25504 :     *is_planar = 1;
     947       25504 :     move16();
     948       25504 :     move16();
     949       25504 :     SWITCH( inConfig )
     950             :     {
     951       13004 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
     952       13004 :             *azimuth = (const Word32 *) &pInCustomLs->ls_azimuth_fx;
     953       13004 :             *elevation = (const Word32 *) &pInCustomLs->ls_elevation_fx;
     954       13004 :             IF( pInCustomLs->num_lfe > 0 )
     955             :             {
     956           0 :                 *lfe_idx = pInCustomLs->lfe_idx[0];
     957           0 :                 move16();
     958             :             }
     959       99036 :             FOR( i = 0; i < pInCustomLs->num_spk; i++ )
     960             :             {
     961       99036 :                 IF( pInCustomLs->ls_elevation_fx[i] != 0 )
     962             :                 {
     963       13004 :                     *is_planar = 0;
     964       13004 :                     move16();
     965       13004 :                     BREAK;
     966             :                 }
     967             :             }
     968       13004 :             BREAK;
     969           0 :         case IVAS_AUDIO_CONFIG_MONO:
     970             :         case IVAS_AUDIO_CONFIG_STEREO:
     971           0 :             IF( NE_32( ( error = getSpeakerAzimuths_fx( inConfig, azimuth ) ), IVAS_ERR_OK ) )
     972             :             {
     973           0 :                 return error;
     974             :             }
     975           0 :             IF( NE_32( error = getSpeakerElevations_fx( inConfig, elevation ), IVAS_ERR_OK ) )
     976             :             {
     977           0 :                 return error;
     978             :             }
     979           0 :             BREAK;
     980       12500 :         case IVAS_AUDIO_CONFIG_5_1:
     981             :         case IVAS_AUDIO_CONFIG_7_1:
     982             :         case IVAS_AUDIO_CONFIG_5_1_2:
     983             :         case IVAS_AUDIO_CONFIG_5_1_4:
     984             :         case IVAS_AUDIO_CONFIG_7_1_4:
     985       12500 :             IF( NE_32( ( error = getSpeakerAzimuths_fx( inConfig, azimuth ) ), IVAS_ERR_OK ) )
     986             :             {
     987           0 :                 return error;
     988             :             }
     989       12500 :             IF( NE_32( ( error = getSpeakerElevations_fx( inConfig, elevation ) ), IVAS_ERR_OK ) )
     990             :             {
     991           0 :                 return error;
     992             :             }
     993       12500 :             *lfe_idx = LFE_CHANNEL;
     994       12500 :             move16();
     995             : 
     996       12500 :             test();
     997       12500 :             IF( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
     998             :             {
     999        5750 :                 *is_planar = 1;
    1000        5750 :                 move16();
    1001             :             }
    1002             :             ELSE
    1003             :             {
    1004        6750 :                 *is_planar = 0;
    1005        6750 :                 move16();
    1006             :             }
    1007       12500 :             BREAK;
    1008           0 :         default:
    1009           0 :             assert( !"Invalid speaker config" );
    1010             :             return IVAS_ERR_WRONG_PARAMS;
    1011             :     }
    1012             : 
    1013       25504 :     return IVAS_ERR_OK;
    1014             : }
    1015         848 : static ivas_error initEfap(
    1016             :     EFAP_WRAPPER *pEfapWrapper,
    1017             :     AUDIO_CONFIG outConfig,
    1018             :     const LSSETUP_CUSTOM_STRUCT *pCustomLsOut )
    1019             : {
    1020             :     ivas_error error;
    1021             :     const Word32 *azimuths;   /* Q22 */
    1022             :     const Word32 *elevations; /* Q22 */
    1023             :     Word16 numNonLfeChannels;
    1024             : 
    1025         848 :     test();
    1026         848 :     IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
    1027             :     {
    1028         120 :         pEfapWrapper->speakerConfig = IVAS_AUDIO_CONFIG_7_1_4;
    1029         120 :         move32();
    1030             :     }
    1031             :     ELSE
    1032             :     {
    1033         728 :         pEfapWrapper->speakerConfig = outConfig;
    1034         728 :         move32();
    1035             :     }
    1036         848 :     pEfapWrapper->pCustomLsSetup = pCustomLsOut;
    1037             : 
    1038             :     /* If re-initializing, free existing EFAP handle. */
    1039         848 :     IF( pEfapWrapper->hEfap != NULL )
    1040             :     {
    1041          47 :         efap_free_data_fx( &pEfapWrapper->hEfap );
    1042             :     }
    1043             : 
    1044             :     /* Only initialize EFAP handle if output config is channel-based */
    1045         848 :     IF( NE_32( getAudioConfigType( pEfapWrapper->speakerConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    1046             :     {
    1047         195 :         pEfapWrapper->hEfap = NULL;
    1048         195 :         return IVAS_ERR_OK;
    1049             :     }
    1050             : 
    1051         653 :     IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1052             :     {
    1053         199 :         IF( NE_32( ( error = efap_init_data_fx( &pEfapWrapper->hEfap, pCustomLsOut->ls_azimuth_fx, pCustomLsOut->ls_elevation_fx, pCustomLsOut->num_spk, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) )
    1054             :         {
    1055           0 :             return error;
    1056             :         }
    1057             :     }
    1058             :     ELSE
    1059             :     {
    1060         454 :         IF( NE_32( ( error = getSpeakerAzimuths_fx( pEfapWrapper->speakerConfig, &azimuths ) ), IVAS_ERR_OK ) )
    1061             :         {
    1062           0 :             return error;
    1063             :         }
    1064             : 
    1065         454 :         IF( NE_32( ( error = getSpeakerElevations_fx( pEfapWrapper->speakerConfig, &elevations ) ), IVAS_ERR_OK ) )
    1066             :         {
    1067           0 :             return error;
    1068             :         }
    1069             : 
    1070         454 :         IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( pEfapWrapper->speakerConfig, &numNonLfeChannels ) ), IVAS_ERR_OK ) )
    1071             :         {
    1072           0 :             return error;
    1073             :         }
    1074         454 :         IF( NE_32( ( error = efap_init_data_fx( &pEfapWrapper->hEfap, azimuths, elevations, numNonLfeChannels, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) )
    1075             :         {
    1076           0 :             return error;
    1077             :         }
    1078             :     }
    1079             : 
    1080         653 :     return IVAS_ERR_OK;
    1081             : }
    1082             : 
    1083      423262 : static ivas_error getEfapGains_fx(
    1084             :     EFAP_WRAPPER efapWrapper,
    1085             :     const Word32 azi, /* Q22 */
    1086             :     const Word32 ele, /* Q22 */
    1087             :     pan_vector_fx panGains /* Q31 */ )
    1088             : {
    1089             :     pan_vector_fx tmpPanGains; /* tmp pan gain buffer without LFE channels */ /* Q30 */
    1090             :     Word32 *readPtr;
    1091             :     Word16 i;
    1092             :     Word16 lfeCount;
    1093             :     Word16 numChannels;
    1094             :     ivas_error error;
    1095             : 
    1096             :     /* EFAP returns an array of gains only for non-LFE speakers */
    1097      423262 :     efap_determine_gains_fx( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
    1098             : 
    1099             :     /* Now copy to buffer that includes LFE channels */
    1100      423262 :     IF( EQ_32( efapWrapper.speakerConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1101             :     {
    1102       29835 :         numChannels = add( efapWrapper.pCustomLsSetup->num_spk, efapWrapper.pCustomLsSetup->num_lfe );
    1103       29835 :         readPtr = tmpPanGains;
    1104       29835 :         lfeCount = 0;
    1105       29835 :         move16();
    1106      387823 :         FOR( i = 0; i < numChannels; ++i )
    1107             :         {
    1108      357988 :             test();
    1109      357988 :             IF( LT_16( lfeCount, efapWrapper.pCustomLsSetup->num_lfe ) && EQ_16( i, efapWrapper.pCustomLsSetup->lfe_idx[lfeCount] ) )
    1110             :             {
    1111           0 :                 panGains[i] = 0;
    1112           0 :                 move32();
    1113           0 :                 lfeCount = add( lfeCount, 1 );
    1114             :             }
    1115             :             ELSE
    1116             :             {
    1117      357988 :                 IF( EQ_32( *readPtr, ONE_IN_Q30 ) )
    1118             :                 {
    1119           0 :                     panGains[i] = ONE_IN_Q31;
    1120             :                 }
    1121             :                 ELSE
    1122             :                 {
    1123      357988 :                     panGains[i] = L_shl( *readPtr, 1 );
    1124             :                 }
    1125      357988 :                 move32();
    1126      357988 :                 ++readPtr;
    1127             :             }
    1128             :         }
    1129             :     }
    1130             :     ELSE
    1131             :     {
    1132      393427 :         IF( NE_32( ( error = getAudioConfigNumChannels( efapWrapper.speakerConfig, &numChannels ) ), IVAS_ERR_OK ) )
    1133             :         {
    1134           0 :             return error;
    1135             :         }
    1136             : 
    1137      393427 :         readPtr = tmpPanGains;
    1138             : 
    1139     4311225 :         FOR( i = 0; i < numChannels; ++i )
    1140             :         {
    1141     3917798 :             IF( EQ_16( i, LFE_CHANNEL ) )
    1142             :             {
    1143      363625 :                 panGains[i] = 0;
    1144      363625 :                 move32();
    1145             :             }
    1146             :             ELSE
    1147             :             {
    1148     3554173 :                 IF( GE_32( *readPtr, ONE_IN_Q30 ) )
    1149             :                 {
    1150       14998 :                     panGains[i] = ONE_IN_Q31;
    1151             :                 }
    1152             :                 ELSE
    1153             :                 {
    1154     3539175 :                     panGains[i] = L_shl( *readPtr, 1 );
    1155             :                 }
    1156             : 
    1157     3554173 :                 move32();
    1158     3554173 :                 ++readPtr;
    1159             :             }
    1160             :         }
    1161             :     }
    1162             : 
    1163      423262 :     return IVAS_ERR_OK;
    1164             : }
    1165             : 
    1166          94 : static ivas_error initHeadRotation_fx(
    1167             :     IVAS_REND_HANDLE hIvasRend )
    1168             : {
    1169             :     Word16 i, crossfade_len;
    1170             :     Word32 tmp_fx; /* Q31 */
    1171             :     ivas_error error;
    1172             : 
    1173             :     /* Head rotation is enabled by default */
    1174          94 :     hIvasRend->headRotData.headRotEnabled = 1;
    1175          94 :     move16();
    1176             : 
    1177             :     /* Initialize 5ms crossfade */
    1178          94 :     crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
    1179          94 :     move16();
    1180          94 :     tmp_fx = Q31_BY_SUB_FRAME_240;
    1181          94 :     move16();
    1182             : 
    1183       22654 :     FOR( i = 0; i < crossfade_len; i++ )
    1184             :     {
    1185       22560 :         hIvasRend->headRotData.crossfade_fx[i] = UL_Mpy_32_32( i, tmp_fx );
    1186       22560 :         move32();
    1187             :     }
    1188             : 
    1189             :     /* Initialize with unit quaternions */
    1190         329 :     FOR( i = 0; i < hIvasRend->num_subframes; ++i )
    1191             :     {
    1192         235 :         hIvasRend->headRotData.headPositions[i] = quaternionInit_fx();
    1193             :     }
    1194             : 
    1195          94 :     hIvasRend->headRotData.sr_pose_pred_axis = DEFAULT_AXIS;
    1196          94 :     move32();
    1197             : 
    1198          94 :     IF( ( hIvasRend->headRotData.hOrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ) ) == NULL )
    1199             :     {
    1200           0 :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Orientation tracking" );
    1201             :     }
    1202             : 
    1203          94 :     IF( NE_32( ( error = ivas_orient_trk_Init_fx( hIvasRend->headRotData.hOrientationTracker ) ), IVAS_ERR_OK ) )
    1204             :     {
    1205           0 :         return error;
    1206             :     }
    1207             : 
    1208          94 :     return IVAS_ERR_OK;
    1209             : }
    1210             : 
    1211             : 
    1212         666 : static void closeHeadRotation(
    1213             :     IVAS_REND_HANDLE hIvasRend )
    1214             : {
    1215         666 :     test();
    1216             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    1217         666 :     test();
    1218         666 :     IF( hIvasRend != NULL && hIvasRend->headRotData.headRotEnabled && hIvasRend->headRotData.hOrientationTracker != NULL )
    1219             : #else
    1220             :     IF( ( hIvasRend != NULL ) && ( hIvasRend->headRotData.hOrientationTracker != NULL ) )
    1221             : #endif
    1222             :     {
    1223          94 :         free( hIvasRend->headRotData.hOrientationTracker );
    1224             :     }
    1225             : 
    1226         666 :     return;
    1227             : }
    1228             : 
    1229             : 
    1230         426 : static void initRotMatrix_fx(
    1231             :     rotation_matrix_fx rot_mat )
    1232             : {
    1233             :     Word16 i;
    1234             : 
    1235             :     /* Initialize rotation matrices */
    1236        1704 :     FOR( i = 0; i < 3; i++ )
    1237             :     {
    1238        1278 :         set_zero_fx( rot_mat[i], 3 );
    1239        1278 :         rot_mat[i][i] = ONE_IN_Q30;
    1240        1278 :         move32();
    1241             :     }
    1242             : 
    1243         426 :     return;
    1244             : }
    1245             : 
    1246        1008 : static void initRotGains_fx(
    1247             :     rotation_gains_fx rot_gains )
    1248             : {
    1249             :     Word16 i;
    1250             : 
    1251             :     /* Set gains to passthrough */
    1252       17136 :     FOR( i = 0; i < MAX_INPUT_CHANNELS; i++ )
    1253             :     {
    1254       16128 :         set16_fx( rot_gains[i], 0, MAX_INPUT_CHANNELS );
    1255       16128 :         rot_gains[i][i] = ONE_IN_Q14;
    1256       16128 :         move16();
    1257             :     }
    1258             : 
    1259        1008 :     return;
    1260             : }
    1261             : 
    1262        2976 : static void initRotGainsWord32_fx(
    1263             :     rotation_gains_Word32 rot_gains )
    1264             : {
    1265             :     Word16 i;
    1266             : 
    1267             :     /* Set gains to passthrough */
    1268       50592 :     FOR( i = 0; i < MAX_INPUT_CHANNELS; i++ )
    1269             :     {
    1270       47616 :         set32_fx( rot_gains[i], 0, MAX_INPUT_CHANNELS );
    1271       47616 :         rot_gains[i][i] = ONE_IN_Q30;
    1272       47616 :         move16();
    1273             :     }
    1274             : 
    1275        2976 :     return;
    1276             : }
    1277       10297 : static void initRendInputBase_fx(
    1278             :     input_base *inputBase,
    1279             :     const AUDIO_CONFIG inConfig,
    1280             :     const IVAS_REND_InputId id,
    1281             :     const rendering_context rendCtx,
    1282             :     Word32 *dataBuf,
    1283             :     const Word16 dataBufSize )
    1284             : {
    1285       10297 :     inputBase->inConfig = inConfig;
    1286       10297 :     move32();
    1287       10297 :     inputBase->id = id;
    1288       10297 :     move16();
    1289       10297 :     inputBase->gain_fx = ONE_IN_Q30;
    1290       10297 :     move32();
    1291       10297 :     inputBase->ctx = rendCtx;
    1292       10297 :     inputBase->numNewSamplesPerChannel = 0;
    1293       10297 :     move32();
    1294             : 
    1295       10297 :     inputBase->inputBuffer.config.numSamplesPerChannel = 0;
    1296       10297 :     inputBase->inputBuffer.config.numChannels = 0;
    1297       10297 :     move16();
    1298       10297 :     move16();
    1299       10297 :     inputBase->inputBuffer.data_fx = dataBuf;
    1300       10297 :     IF( inputBase->inputBuffer.data_fx != NULL )
    1301             :     {
    1302         973 :         set32_fx( inputBase->inputBuffer.data_fx, 0, dataBufSize );
    1303             :     }
    1304             : 
    1305       10297 :     return;
    1306             : }
    1307             : 
    1308      300852 : static IVAS_ISM_METADATA defaultObjectPosition(
    1309             :     void )
    1310             : {
    1311             :     IVAS_ISM_METADATA pos;
    1312             : 
    1313      300852 :     pos.azimuth_fx = 0;
    1314      300852 :     move32();
    1315      300852 :     pos.elevation_fx = 0;
    1316      300852 :     move32();
    1317      300852 :     pos.radius_fx = ONE_IN_Q9;
    1318      300852 :     move16();
    1319      300852 :     pos.spread_fx = 0;
    1320      300852 :     move32();
    1321      300852 :     pos.gainFactor_fx = ONE_IN_Q31;
    1322      300852 :     move32();
    1323      300852 :     pos.yaw_fx = 0;
    1324      300852 :     move32();
    1325      300852 :     pos.pitch_fx = 0;
    1326      300852 :     move32();
    1327      300852 :     return pos;
    1328             : }
    1329             : 
    1330             : 
    1331      947155 : static Word8 checkObjectPositionChanged_fx(
    1332             :     IVAS_ISM_METADATA *currentPos,
    1333             :     IVAS_ISM_METADATA *previousPos )
    1334             : {
    1335      947155 :     test();
    1336     1555417 :     return !( LT_32( L_abs( L_sub( currentPos->azimuth_fx, previousPos->azimuth_fx ) ), EPSILLON_FX ) &&
    1337      608262 :               LT_32( L_abs( L_sub( currentPos->elevation_fx, previousPos->elevation_fx ) ), EPSILLON_FX ) );
    1338             : }
    1339             : 
    1340        4662 : static rendering_context getRendCtx(
    1341             :     IVAS_REND_HANDLE hIvasRend )
    1342             : {
    1343             :     rendering_context ctx;
    1344             : 
    1345             :     /* Note: when refactoring this, always take the ADDRESS of a member of the
    1346             :      * renderer struct, so that the context stores a POINTER to the member, even
    1347             :      * if the member is a pointer or handle itself. */
    1348        4662 :     ctx.pOutConfig = &hIvasRend->outputConfig;
    1349        4662 :     ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
    1350        4662 :     ctx.pCustomLsOut = &hIvasRend->customLsOut;
    1351        4662 :     ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
    1352        4662 :     ctx.pHeadRotData = &hIvasRend->headRotData;
    1353        4662 :     ctx.hhRendererConfig = &hIvasRend->hRendererConfig;
    1354        4662 :     ctx.pSplitRendBFI = &hIvasRend->splitRendBFI;
    1355        4662 :     ctx.pSplitRendWrapper = hIvasRend->splitRendWrapper;
    1356        4662 :     ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
    1357             : 
    1358        4662 :     return ctx;
    1359             : }
    1360             : 
    1361             : 
    1362         798 : static TDREND_WRAPPER defaultTdRendWrapper(
    1363             :     void )
    1364             : {
    1365             :     TDREND_WRAPPER w;
    1366             : 
    1367         798 :     w.binaural_latency_ns = 0;
    1368         798 :     move32();
    1369         798 :     w.hBinRendererTd = NULL;
    1370         798 :     w.hHrtfTD = NULL;
    1371             : 
    1372         798 :     return w;
    1373             : }
    1374             : 
    1375             : 
    1376         973 : static bool isIoConfigPairSupported(
    1377             :     const AUDIO_CONFIG inConfig,
    1378             :     const AUDIO_CONFIG outConfig )
    1379             : {
    1380             :     /* Rendering mono or stereo to binaural is not supported */
    1381         973 :     test();
    1382         973 :     test();
    1383         973 :     IF( ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_STEREO ) ) && EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
    1384             :     {
    1385           0 :         return false;
    1386             :     }
    1387             : 
    1388             :     /* If not returned so far, config pair is supported */
    1389         973 :     return true;
    1390             : }
    1391             : 
    1392           1 : static ivas_error initIsmMasaRendering(
    1393             :     input_ism *inputIsm,
    1394             :     const Word32 inSampleRate )
    1395             : {
    1396             :     ivas_error error;
    1397             :     Word16 num_poses;
    1398             : 
    1399           1 :     num_poses = 1;
    1400           1 :     move16();
    1401           1 :     if ( inputIsm->base.ctx.pSplitRendWrapper != NULL )
    1402             :     {
    1403           0 :         num_poses = inputIsm->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    1404           0 :         move16();
    1405             :     }
    1406             : 
    1407           1 :     IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
    1408             :     {
    1409           0 :         ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
    1410             :     }
    1411             : 
    1412           1 :     ivas_rend_closeCrend( &inputIsm->crendWrapper, num_poses );
    1413             : 
    1414           1 :     ivas_reverb_close( &inputIsm->hReverb );
    1415             : 
    1416           1 :     IF( NE_32( ( error = ivas_omasa_ana_open( &inputIsm->hOMasa, inSampleRate, inputIsm->total_num_objects ) ), IVAS_ERR_OK ) )
    1417             :     {
    1418           0 :         return error;
    1419             :     }
    1420             : 
    1421           1 :     return IVAS_ERR_OK;
    1422             : }
    1423             : 
    1424             : 
    1425         426 : static ivas_error setRendInputActiveIsm(
    1426             :     void *input,
    1427             :     const AUDIO_CONFIG inConfig,
    1428             :     const IVAS_REND_InputId id,
    1429             :     RENDER_CONFIG_DATA *hRendCfg,
    1430             :     hrtf_handles *hrtfs )
    1431             : {
    1432             :     ivas_error error;
    1433             :     rendering_context rendCtx;
    1434             :     AUDIO_CONFIG outConfig;
    1435             :     input_ism *inputIsm;
    1436             :     Word16 i;
    1437             :     Word16 SrcInd[MAX_NUM_TDREND_CHANNELS];
    1438             :     Word16 num_src;
    1439             :     Word16 ivas_format;
    1440             :     Word16 num_poses;
    1441             : 
    1442         426 :     IF( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    1443             :     {
    1444           0 :         ivas_format = MC_FORMAT;
    1445             :     }
    1446             :     ELSE
    1447             :     {
    1448         426 :         ivas_format = ISM_FORMAT;
    1449             :     }
    1450             : 
    1451         426 :     inputIsm = (input_ism *) input;
    1452         426 :     rendCtx = inputIsm->base.ctx;
    1453         426 :     outConfig = *rendCtx.pOutConfig;
    1454             : 
    1455         426 :     num_poses = 1;
    1456         426 :     move16();
    1457         426 :     if ( rendCtx.pSplitRendWrapper != NULL )
    1458             :     {
    1459           0 :         num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
    1460           0 :         move16();
    1461             :     }
    1462             : 
    1463         426 :     IF( !isIoConfigPairSupported( inConfig, outConfig ) )
    1464             :     {
    1465           0 :         return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    1466             :     }
    1467             : 
    1468         426 :     IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputIsm->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
    1469             :     {
    1470           0 :         return error;
    1471             :     }
    1472         426 :     initRendInputBase_fx( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData_fx, MAX_BUFFER_LENGTH );
    1473             : 
    1474         426 :     inputIsm->firstFrameRendered = FALSE;
    1475         426 :     move16();
    1476             : 
    1477         426 :     inputIsm->currentPos = defaultObjectPosition();
    1478         426 :     inputIsm->previousPos = defaultObjectPosition();
    1479         426 :     inputIsm->crendWrapper = NULL;
    1480         426 :     inputIsm->hReverb = NULL;
    1481         426 :     inputIsm->tdRendWrapper = defaultTdRendWrapper();
    1482             : 
    1483         426 :     initRotMatrix_fx( inputIsm->rot_mat_prev );
    1484             : 
    1485         426 :     set_zero_fx( inputIsm->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    1486             : 
    1487        3408 :     FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    1488             :     {
    1489        2982 :         inputIsm->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
    1490             :     }
    1491             : 
    1492         426 :     inputIsm->hOMasa = NULL;
    1493             : 
    1494         426 :     error = IVAS_ERR_OK;
    1495         426 :     move32();
    1496             : 
    1497         426 :     inputIsm->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
    1498             : 
    1499         426 :     test();
    1500         426 :     test();
    1501         426 :     test();
    1502         426 :     IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    1503          40 :     {
    1504          40 :         IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
    1505             :         {
    1506           0 :             return error;
    1507             :         }
    1508             : 
    1509          40 :         Word16 nchan_rend = num_src;
    1510          40 :         move16();
    1511             : 
    1512          40 :         test();
    1513          40 :         IF( EQ_16( ivas_format, MC_FORMAT ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1514             :         {
    1515           0 :             nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
    1516             :         }
    1517             : 
    1518          80 :         FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
    1519             :         {
    1520          40 :             TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
    1521          40 :             IF( Src_p != NULL )
    1522             :             {
    1523          40 :                 IF( Src_p->SrcSpatial_p != NULL )
    1524             :                 {
    1525          40 :                     Src_p->SrcSpatial_p->q_Pos_p = Q31;
    1526          40 :                     move16();
    1527             :                 }
    1528          40 :                 TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
    1529          40 :                 SrcSpatial_p->q_Pos_p = Q31;
    1530          40 :                 move16();
    1531             :             }
    1532             :         }
    1533             : 
    1534             :         /* Open TD renderer wrappers */
    1535         320 :         FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    1536             :         {
    1537         280 :             IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->splitTdRendWrappers[i], inConfig, hRendCfg, NULL, *inputIsm->base.ctx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
    1538             :             {
    1539           0 :                 return error;
    1540             :             }
    1541             : 
    1542             :             /* Assert same delay as main TD renderer */
    1543         280 :             assert( inputIsm->splitTdRendWrappers[i].binaural_latency_ns == inputIsm->tdRendWrapper.binaural_latency_ns );
    1544             : 
    1545         560 :             FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
    1546             :             {
    1547         280 :                 TDREND_SRC_t *Src_p = inputIsm->splitTdRendWrappers[i].hBinRendererTd->Sources[SrcInd[nS]];
    1548         280 :                 IF( Src_p != NULL )
    1549             :                 {
    1550         280 :                     IF( Src_p->SrcSpatial_p != NULL )
    1551             :                     {
    1552         280 :                         Src_p->SrcSpatial_p->q_Pos_p = Q31;
    1553         280 :                         move16();
    1554             :                     }
    1555         280 :                     TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->splitTdRendWrappers[i].hBinRendererTd->Sources[nS]->SrcSpatial_p;
    1556         280 :                     SrcSpatial_p->q_Pos_p = Q31;
    1557         280 :                     move16();
    1558             :                 }
    1559             :             }
    1560             :         }
    1561             :     }
    1562         386 :     ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    1563             :     {
    1564           1 :         IF( NE_32( ( error = initIsmMasaRendering( inputIsm, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    1565             :         {
    1566           0 :             return error;
    1567             :         }
    1568             :     }
    1569             :     ELSE
    1570             :     {
    1571         385 :         IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputIsm->tdRendWrapper, inConfig, hRendCfg, NULL, *rendCtx.pOutSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
    1572             :         {
    1573           0 :             return error;
    1574             :         }
    1575             : 
    1576         385 :         Word16 nchan_rend = num_src;
    1577         385 :         move16();
    1578             : 
    1579         385 :         test();
    1580         385 :         IF( EQ_16( ivas_format, MC_FORMAT ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1581             :         {
    1582           0 :             nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
    1583             :         }
    1584             : 
    1585         770 :         FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
    1586             :         {
    1587         385 :             TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
    1588         385 :             IF( Src_p != NULL )
    1589             :             {
    1590         385 :                 IF( Src_p->SrcSpatial_p != NULL )
    1591             :                 {
    1592         385 :                     Src_p->SrcSpatial_p->q_Pos_p = Q31;
    1593         385 :                     move16();
    1594             :                 }
    1595         385 :                 TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
    1596         385 :                 SrcSpatial_p->q_Pos_p = Q31;
    1597         385 :                 move16();
    1598             :             }
    1599             :         }
    1600             : 
    1601         385 :         IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
    1602             :         {
    1603          40 :             IF( NE_32( ( error = ivas_reverb_open_fx( &( inputIsm->hReverb ), hrtfs->hHrtfStatistics, hRendCfg, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    1604             :             {
    1605           0 :                 return error;
    1606             :             }
    1607             :         }
    1608         345 :         ELSE IF( outConfig == IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR )
    1609             :         {
    1610          40 :             IF( NE_32( ( error = ivas_rend_openCrend( &inputIsm->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
    1611             :             {
    1612           0 :                 return error;
    1613             :             }
    1614             :         }
    1615             :     }
    1616             : 
    1617         426 :     return IVAS_ERR_OK;
    1618             : }
    1619             : 
    1620        2664 : static void clearInputIsm(
    1621             :     input_ism *inputIsm )
    1622             : {
    1623             :     rendering_context rendCtx;
    1624             :     Word16 i, num_poses;
    1625             : 
    1626        2664 :     num_poses = 1;
    1627        2664 :     move16();
    1628        2664 :     if ( inputIsm->base.ctx.pSplitRendWrapper != NULL )
    1629             :     {
    1630           0 :         num_poses = inputIsm->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    1631           0 :         move16();
    1632             :     }
    1633             : 
    1634        2664 :     rendCtx = inputIsm->base.ctx;
    1635             : 
    1636        2664 :     freeInputBaseBufferData_fx( &inputIsm->base.inputBuffer.data_fx );
    1637             : 
    1638        2664 :     initRendInputBase_fx( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    1639             : 
    1640             :     /* Free input's internal handles */
    1641        2664 :     ivas_rend_closeCrend( &inputIsm->crendWrapper, num_poses );
    1642             : 
    1643        2664 :     ivas_reverb_close( &inputIsm->hReverb );
    1644             : 
    1645        2664 :     IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
    1646             :     {
    1647         425 :         ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
    1648             :     }
    1649             : 
    1650       21312 :     FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    1651             :     {
    1652       18648 :         ivas_td_binaural_close_fx( &inputIsm->splitTdRendWrappers[i].hBinRendererTd );
    1653             :     }
    1654             : 
    1655        2664 :     ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
    1656             : 
    1657        2664 :     return;
    1658             : }
    1659             : 
    1660          62 : static void copyLsConversionMatrixToPanMatrix_fx(
    1661             :     const LS_CONVERSION_MATRIX_FX *lsConvMatrix,
    1662             :     pan_matrix_fx panMatrix )
    1663             : {
    1664             :     Word16 i;
    1665             :     Word16 inCh, outCh;
    1666             :     Word16 numNonZeroGains;
    1667             :     Word16 numColumns;
    1668             :     Word16 tmp_e, tmp;
    1669             :     /* Index 0 is special and describes the following values */
    1670          62 :     numNonZeroGains = lsConvMatrix[0].index;
    1671          62 :     move16();
    1672          62 :     numColumns = (Word16) lsConvMatrix[0].value;
    1673          62 :     move16();
    1674             : 
    1675         654 :     FOR( i = 1; i < numNonZeroGains + 1; ++i )
    1676             :     {
    1677         592 :         tmp = BASOP_Util_Divide1616_Scale( lsConvMatrix[i].index, numColumns, &tmp_e );
    1678         592 :         move16();
    1679         592 :         tmp = shr( tmp, add( 15, negate( tmp_e ) ) );
    1680         592 :         move16();
    1681         592 :         inCh = tmp;
    1682         592 :         move16();
    1683             :         // inCh = lsConvMatrix[i].index / numColumns;
    1684         592 :         outCh = lsConvMatrix[i].index % numColumns;
    1685         592 :         move16();
    1686             : 
    1687         592 :         IF( EQ_32( lsConvMatrix[i].value, ONE_IN_Q30 ) )
    1688             :         {
    1689         492 :             panMatrix[inCh][outCh] = ONE_IN_Q31;
    1690             :         }
    1691             :         ELSE
    1692             :         {
    1693         100 :             panMatrix[inCh][outCh] = L_shl( lsConvMatrix[i].value, 1 ); /* Q30 + Q1 = Q31 */
    1694             :         }
    1695         592 :         move32();
    1696             :     }
    1697             : 
    1698          62 :     return;
    1699             : }
    1700             : 
    1701        1101 : static void setZeroPanMatrix_fx(
    1702             :     pan_matrix_fx panMatrix )
    1703             : {
    1704             :     Word16 i;
    1705             : 
    1706       18717 :     FOR( i = 0; i < MAX_INPUT_CHANNELS; ++i )
    1707             :     {
    1708       17616 :         set32_fx( panMatrix[i], 0, MAX_OUTPUT_CHANNELS );
    1709             :     }
    1710             : 
    1711        1101 :     return;
    1712             : }
    1713             : 
    1714             : /* Note: this only sets non-zero elements, call setZeroPanMatrix() to init first. */
    1715          91 : static void fillIdentityPanMatrix_fx(
    1716             :     pan_matrix_fx panMatrix )
    1717             : {
    1718             :     Word16 i;
    1719             : 
    1720        1547 :     FOR( i = 0; i < s_min( MAX_INPUT_CHANNELS, MAX_OUTPUT_CHANNELS ); ++i )
    1721             :     {
    1722        1456 :         panMatrix[i][i] = ONE_IN_Q31;
    1723        1456 :         move32();
    1724             :     }
    1725             : 
    1726          91 :     return;
    1727             : }
    1728             : 
    1729          29 : static ivas_error initMcPanGainsWithIdentMatrix(
    1730             :     input_mc *inputMc )
    1731             : {
    1732          29 :     fillIdentityPanMatrix_fx( inputMc->panGains_fx );
    1733             : 
    1734          29 :     return IVAS_ERR_OK;
    1735             : }
    1736             : 
    1737         100 : static ivas_error initMcPanGainsWithConversionMapping_fx(
    1738             :     input_mc *inputMc,
    1739             :     const AUDIO_CONFIG outConfig )
    1740             : {
    1741             :     AUDIO_CONFIG ivasConfigIn, ivasConfigOut;
    1742             :     Word16 i;
    1743             : 
    1744         100 :     ivasConfigIn = inputMc->base.inConfig;
    1745         100 :     move32();
    1746         100 :     ivasConfigOut = outConfig;
    1747         100 :     move32();
    1748             : 
    1749             :     /* Find conversion mapping for current I/O config pair.
    1750             :      * Stay with default panning matrix if conversion_matrix is NULL */
    1751        2580 :     FOR( i = 0; i < LS_SETUP_CONVERSION_NUM_MAPPINGS; ++i )
    1752             :     {
    1753        2580 :         test();
    1754        2580 :         IF( EQ_32( ls_conversion_mapping_fx[i].input_config, ivasConfigIn ) && EQ_32( ls_conversion_mapping_fx[i].output_config, ivasConfigOut ) )
    1755             :         {
    1756             :             /* Mapping found with valid matrix - copy */
    1757         100 :             IF( ls_conversion_mapping_fx[i].conversion_matrix_fx != NULL )
    1758             :             {
    1759          62 :                 copyLsConversionMatrixToPanMatrix_fx( ls_conversion_mapping_fx[i].conversion_matrix_fx, inputMc->panGains_fx );
    1760             :             }
    1761             :             /* Mapping found with NULL matrix - use identity matrix */
    1762             :             ELSE
    1763             :             {
    1764          38 :                 fillIdentityPanMatrix_fx( inputMc->panGains_fx );
    1765             :             }
    1766             : 
    1767         100 :             return IVAS_ERR_OK;
    1768             :         }
    1769             :     }
    1770             : 
    1771           0 :     return IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Missing multichannel conversion mapping" );
    1772             : }
    1773             : 
    1774         180 : static ivas_error initMcPanGainsWithEfap_fx(
    1775             :     input_mc *inputMc,
    1776             :     const AUDIO_CONFIG outConfig )
    1777             : {
    1778             :     Word16 i;
    1779             :     Word16 numNonLfeInChannels;
    1780             :     Word16 inLfeChIdx, outChIdx;
    1781             :     const Word32 *spkAzi, *spkEle; /* Q22 */
    1782             :     ivas_error error;
    1783             : 
    1784         180 :     IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1785             :     {
    1786          33 :         IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ), IVAS_ERR_OK ) )
    1787             :         {
    1788           0 :             return error;
    1789             :         }
    1790             : 
    1791          33 :         IF( NE_32( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi ) ), IVAS_ERR_OK ) )
    1792             :         {
    1793           0 :             return error;
    1794             :         }
    1795             : 
    1796          33 :         IF( NE_32( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle ) ), IVAS_ERR_OK ) )
    1797             :         {
    1798           0 :             return error;
    1799             :         }
    1800             : 
    1801          33 :         inLfeChIdx = LFE_CHANNEL;
    1802          33 :         move16();
    1803             :     }
    1804             :     ELSE
    1805             :     {
    1806         147 :         numNonLfeInChannels = inputMc->customLsInput.num_spk;
    1807         147 :         move16();
    1808         147 :         spkAzi = inputMc->customLsInput.ls_azimuth_fx;
    1809         147 :         move32();
    1810         147 :         spkEle = inputMc->customLsInput.ls_elevation_fx;
    1811         147 :         move32();
    1812         147 :         inLfeChIdx = -1;
    1813         147 :         move16();
    1814         147 :         if ( inputMc->customLsInput.num_lfe > 0 )
    1815             :         {
    1816           0 :             inLfeChIdx = inputMc->customLsInput.lfe_idx[0];
    1817           0 :             move16();
    1818             :         }
    1819             :     }
    1820         180 :     outChIdx = 0;
    1821         180 :     move16();
    1822        1257 :     FOR( i = 0; i < numNonLfeInChannels; ++i )
    1823             :     {
    1824        1077 :         IF( EQ_16( i, inLfeChIdx ) )
    1825             :         {
    1826          15 :             outChIdx = add( outChIdx, 1 );
    1827             :         }
    1828             : 
    1829        1077 :         IF( NE_32( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, spkAzi[i], spkEle[i], inputMc->panGains_fx[outChIdx] ) ), IVAS_ERR_OK ) )
    1830             :         {
    1831           0 :             return error;
    1832             :         }
    1833        1077 :         outChIdx = add( outChIdx, 1 );
    1834             :     }
    1835             : 
    1836         180 :     test();
    1837         180 :     test();
    1838         180 :     IF( NE_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && inLfeChIdx >= 0 )
    1839             :     {
    1840          12 :         inputMc->panGains_fx[inLfeChIdx][LFE_CHANNEL] = ONE_IN_Q31;
    1841          12 :         move32();
    1842             :     }
    1843         168 :     ELSE IF( inputMc->base.ctx.pCustomLsOut->num_lfe > 0 && inLfeChIdx >= 0 )
    1844             :     {
    1845           0 :         inputMc->panGains_fx[inLfeChIdx][inputMc->base.ctx.pCustomLsOut->lfe_idx[0]] = ONE_IN_Q31;
    1846           0 :         move32();
    1847             :     }
    1848         180 :     return IVAS_ERR_OK;
    1849             : }
    1850             : 
    1851     2507531 : static ivas_error getRendInputNumChannels(
    1852             :     const void *rendInput,
    1853             :     Word16 *numInChannels )
    1854             : {
    1855             :     /* Using a void pointer for this function to be reusable for any input type (input_ism, input_mc, input_sba).
    1856             :         Assumptions:        - input_base is always the first member in the input struct    */
    1857             : 
    1858             :     ivas_error error;
    1859             :     const input_base *pInputBase;
    1860             :     const input_mc *pInputMc;
    1861             : 
    1862     2507531 :     pInputBase = (const input_base *) rendInput;
    1863             : 
    1864     2507531 :     IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1865             :     {
    1866      215975 :         pInputMc = (const input_mc *) rendInput;
    1867      215975 :         *numInChannels = add( pInputMc->customLsInput.num_spk, pInputMc->customLsInput.num_lfe );
    1868      215975 :         move16();
    1869             :     }
    1870             :     ELSE
    1871             :     {
    1872     2291556 :         IF( NE_32( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ), IVAS_ERR_OK ) )
    1873             :         {
    1874           0 :             return error;
    1875             :         }
    1876             :     }
    1877             : 
    1878     2507531 :     return IVAS_ERR_OK;
    1879             : }
    1880             : 
    1881          16 : static ivas_error initMcPanGainsWithMonoOut_fx(
    1882             :     input_mc *inputMc )
    1883             : {
    1884             :     Word16 i;
    1885             :     Word16 numInChannels;
    1886             :     Word16 readIdx;
    1887             :     Word16 writeIdx;
    1888             :     bool skipSideSpeakers;
    1889             :     ivas_error error;
    1890             : 
    1891          16 :     IF( NE_32( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ), IVAS_ERR_OK ) )
    1892             :     {
    1893           0 :         return error;
    1894             :     }
    1895             : 
    1896          16 :     IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    1897             :     {
    1898           0 :         FOR( i = 0; i < numInChannels; ++i )
    1899             :         {
    1900             :             /* It's OK to also set gain 1 for LFE input channels here.
    1901             :              * Correct LFE handling will be applied within updateMcPanGains() */
    1902           0 :             inputMc->panGains_fx[i][0] = ONE_IN_Q31;
    1903           0 :             move32();
    1904             :         }
    1905             :     }
    1906          16 :     ELSE IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_STEREO ) )
    1907             :     {
    1908             :         /* Special case for STEREO to MONO: Passive downmix (L+R)/2 */
    1909           4 :         inputMc->panGains_fx[0][0] = ONE_IN_Q30; // Q31(of 0.5)
    1910           4 :         move32();
    1911           4 :         inputMc->panGains_fx[1][0] = ONE_IN_Q30; // Q31(of 0.5)
    1912           4 :         move32();
    1913             :     }
    1914             :     ELSE
    1915             :     {
    1916             :         /* ls_conversion_cicpX_stereo contains gains for side speakers.
    1917             :          * These should be skipped with 5.1+X inputs. */
    1918          12 :         skipSideSpeakers = false;
    1919          12 :         move16();
    1920          12 :         test();
    1921          12 :         if ( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) )
    1922             :         {
    1923           6 :             skipSideSpeakers = true;
    1924           6 :             move16();
    1925             :         }
    1926          12 :         readIdx = 0;
    1927          12 :         move16();
    1928         120 :         FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx )
    1929             :         {
    1930         108 :             test();
    1931         108 :             IF( ( skipSideSpeakers ) && EQ_16( readIdx, 4 ) )
    1932             :             {
    1933             :                 /* Skip gains for side speakers in lookup table */
    1934           6 :                 readIdx = add( readIdx, 2 );
    1935             :             }
    1936             : 
    1937         108 :             IF( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) )
    1938             :             {
    1939          48 :                 inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
    1940             :             }
    1941             :             ELSE
    1942             :             {
    1943          60 :                 inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 );
    1944             :             }
    1945         108 :             move32();
    1946             : 
    1947         108 :             IF( EQ_32( ls_conversion_cicpX_mono_fx[readIdx][0], ONE_IN_Q30 ) )
    1948             :             {
    1949          48 :                 inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
    1950             :             }
    1951             :             ELSE
    1952             :             {
    1953          60 :                 inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_mono_fx[readIdx][0], 1 ); // Q31
    1954             :             }
    1955         108 :             move32();
    1956         108 :             readIdx = add( readIdx, 1 );
    1957             :         }
    1958             :     }
    1959             : 
    1960          16 :     return IVAS_ERR_OK;
    1961             : }
    1962             : 
    1963          12 : static ivas_error initMcPanGainsWithStereoLookup_fx(
    1964             :     input_mc *inputMc )
    1965             : {
    1966             :     Word16 readIdx;
    1967             :     Word16 writeIdx;
    1968             :     bool skipSideSpeakers;
    1969             :     Word16 numInChannels;
    1970             :     ivas_error error;
    1971             : 
    1972             :     /* Special case - MONO input.
    1973             :      * Use gains for center CICP speaker and return early. */
    1974          12 :     IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) )
    1975             :     {
    1976           0 :         inputMc->panGains_fx[0][0] = L_shl( ls_conversion_cicpX_stereo_fx[2][0], 1 ); /* Q30 + Q1 = Q31 */
    1977           0 :         move32();
    1978           0 :         inputMc->panGains_fx[0][1] = L_shl( ls_conversion_cicpX_stereo_fx[2][1], 1 ); /* Q30 + Q1 = Q31 */
    1979           0 :         move32();
    1980           0 :         return IVAS_ERR_OK;
    1981             :     }
    1982             : 
    1983             :     /* ls_conversion_cicpX_stereo contains gains for side speakers.
    1984             :      * These should be skipped with 5.1+X inputs. */
    1985          12 :     skipSideSpeakers = false;
    1986          12 :     move16();
    1987          12 :     test();
    1988          12 :     if ( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_2 ) || EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_5_1_4 ) )
    1989             :     {
    1990           6 :         skipSideSpeakers = true;
    1991           6 :         move16();
    1992             :     }
    1993             : 
    1994          12 :     IF( NE_32( ( error = getRendInputNumChannels( inputMc, &numInChannels ) ), IVAS_ERR_OK ) )
    1995             :     {
    1996           0 :         return error;
    1997             :     }
    1998          12 :     readIdx = 0;
    1999          12 :     move16();
    2000         120 :     FOR( writeIdx = 0; writeIdx < numInChannels; ++writeIdx )
    2001             :     {
    2002         108 :         test();
    2003         108 :         IF( skipSideSpeakers && EQ_16( readIdx, 4 ) )
    2004             :         {
    2005             :             /* Skip gains for side speakers in lookup table */
    2006           6 :             readIdx = add( readIdx, 2 );
    2007             :         }
    2008             : 
    2009         108 :         IF( EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][0], ONE_IN_Q30 ) )
    2010             :         {
    2011          12 :             inputMc->panGains_fx[writeIdx][0] = ONE_IN_Q31;
    2012             :         }
    2013             :         ELSE
    2014             :         {
    2015          96 :             inputMc->panGains_fx[writeIdx][0] = L_shl( ls_conversion_cicpX_stereo_fx[readIdx][0], 1 ); /* Q30 + Q1 = Q31 */
    2016             :         }
    2017         108 :         move32();
    2018             : 
    2019         108 :         IF( EQ_32( ls_conversion_cicpX_stereo_fx[readIdx][1], ONE_IN_Q30 ) )
    2020             :         {
    2021          12 :             inputMc->panGains_fx[writeIdx][1] = ONE_IN_Q31;
    2022             :         }
    2023             :         ELSE
    2024             :         {
    2025          96 :             inputMc->panGains_fx[writeIdx][1] = L_shl( ls_conversion_cicpX_stereo_fx[readIdx][1], 1 ); /* Q30 + Q1 = Q31 */
    2026             :         }
    2027         108 :         move32();
    2028         108 :         readIdx = add( readIdx, 1 );
    2029             :     }
    2030             : 
    2031          12 :     return IVAS_ERR_OK;
    2032             : }
    2033             : 
    2034             : 
    2035             : /* Returns 1 (true) if configs A and B are equal, otherwise returns 0 (false).
    2036             :  * If both configs are custom LS layouts, layout details are compared to determine equality. */
    2037         342 : static bool configsAreEqual(
    2038             :     const AUDIO_CONFIG configA,
    2039             :     const LSSETUP_CUSTOM_STRUCT customLsA,
    2040             :     const AUDIO_CONFIG configB,
    2041             :     const LSSETUP_CUSTOM_STRUCT customLsB )
    2042             : {
    2043             :     Word16 i;
    2044             : 
    2045             :     /* Both input and output are custom LS - compare structs */
    2046         342 :     test();
    2047         342 :     IF( EQ_32( configA, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && EQ_32( configB, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    2048             :     {
    2049          18 :         IF( NE_16( customLsA.num_spk, customLsB.num_spk ) )
    2050             :         {
    2051          15 :             return false;
    2052             :         }
    2053             : 
    2054           3 :         IF( NE_16( customLsA.num_lfe, customLsB.num_lfe ) )
    2055             :         {
    2056           0 :             return false;
    2057             :         }
    2058             : 
    2059           3 :         IF( NE_16( customLsA.is_planar_setup, customLsB.is_planar_setup ) )
    2060             :         {
    2061           0 :             return false;
    2062             :         }
    2063             : 
    2064          39 :         FOR( i = 0; i < customLsA.num_spk; ++i )
    2065             :         {
    2066             :             /* Compare to nearest degree (hence the int16_t cast) */
    2067          36 :             test();
    2068          36 :             IF( NE_32( customLsA.ls_azimuth_fx[i], customLsB.ls_azimuth_fx[i] ) ||
    2069             :                 NE_32( customLsA.ls_elevation_fx[i], customLsB.ls_elevation_fx[i] ) )
    2070             :             {
    2071           0 :                 return false;
    2072             :             }
    2073             :         }
    2074           3 :         FOR( i = 0; i < customLsA.num_lfe; ++i )
    2075             :         {
    2076           0 :             IF( NE_16( customLsA.lfe_idx[i], customLsB.lfe_idx[i] ) )
    2077             :             {
    2078           0 :                 return false;
    2079             :             }
    2080             :         }
    2081             : 
    2082           3 :         return true;
    2083             :     }
    2084             : 
    2085             :     /* Otherwise it's enough to compare config enums */
    2086         324 :     return configA == configB;
    2087             : }
    2088         342 : static ivas_error updateLfePanGainsForMcOut(
    2089             :     input_mc *inputMc,
    2090             :     const AUDIO_CONFIG outConfig )
    2091             : {
    2092             :     Word16 i, numLfeIn, numOutChannels;
    2093             :     ivas_error error;
    2094         342 :     error = IVAS_ERR_OK;
    2095         342 :     move32();
    2096             : 
    2097             :     /* If panning is not required, simply return */
    2098         342 :     IF( !inputMc->lfeRouting.pan_lfe )
    2099             :     {
    2100         342 :         return error;
    2101             :     }
    2102             : 
    2103           0 :     numLfeIn = getNumLfeChannels( inputMc );
    2104             : 
    2105           0 :     IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    2106             :     {
    2107           0 :         numOutChannels = add( inputMc->base.ctx.pCustomLsOut->num_spk, inputMc->base.ctx.pCustomLsOut->num_lfe );
    2108             :     }
    2109             :     ELSE
    2110             :     {
    2111           0 :         IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
    2112             :         {
    2113           0 :             return error;
    2114             :         }
    2115             :     }
    2116             : 
    2117           0 :     FOR( i = 0; i < numLfeIn; i++ )
    2118             :     {
    2119             :         /* panning gains */
    2120           0 :         IF( NE_32( ( error = getEfapGains_fx( *inputMc->base.ctx.pEfapOutWrapper, inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i] ) ), IVAS_ERR_OK ) )
    2121             :         {
    2122           0 :             return error;
    2123             :         }
    2124             : 
    2125             :         /* linear input gain */
    2126           0 :         v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], numOutChannels ); /* Q31 */
    2127             :     }
    2128             : 
    2129           0 :     return error;
    2130             : }
    2131          90 : static ivas_error updateLfePanGainsForAmbiOut(
    2132             :     input_mc *inputMc,
    2133             :     const AUDIO_CONFIG outConfig )
    2134             : {
    2135             :     Word16 i;
    2136             :     Word16 numLfeIn, outAmbiOrder;
    2137             :     ivas_error error;
    2138          90 :     error = IVAS_ERR_OK;
    2139          90 :     move32();
    2140             : 
    2141             :     /* If panning is not required, simply return */
    2142          90 :     IF( !inputMc->lfeRouting.pan_lfe )
    2143             :     {
    2144          90 :         return error;
    2145             :     }
    2146             : 
    2147           0 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ), IVAS_ERR_OK ) )
    2148             :     {
    2149           0 :         return error;
    2150             :     }
    2151             : 
    2152           0 :     numLfeIn = getNumLfeChannels( inputMc );
    2153           0 :     move16();
    2154           0 :     FOR( i = 0; i < numLfeIn; i++ )
    2155             :     {
    2156             :         /* panning gains */
    2157           0 :         ivas_dirac_dec_get_response_fx( inputMc->lfeRouting.lfeOutputAzimuth_fx, inputMc->lfeRouting.lfeOutputElevation_fx, inputMc->lfeRouting.lfePanMtx_fx[i], outAmbiOrder, Q29 );
    2158             : 
    2159             :         /* linear input gain */
    2160           0 :         v_multc_fixed( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->lfeRouting.lfeInputGain_fx, inputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS ); /* Q31 */
    2161             :     }
    2162             : 
    2163           0 :     return error;
    2164             : }
    2165         342 : static ivas_error updateMcPanGainsForMcOut(
    2166             :     input_mc *inputMc,
    2167             :     const AUDIO_CONFIG outConfig )
    2168             : {
    2169             :     ivas_error error;
    2170             : 
    2171             :     /* "if" conditions below realize the following mapping:
    2172             : 
    2173             :     If in == out, use identity matrix, otherwise follow the table:
    2174             :     +-----------+-------------+---------------+-----------+--------------------+
    2175             :     |  in\out   |   MONO      |   STEREO      | custom LS |       other        |
    2176             :     +-----------+-------------+---------------+-----------+--------------------+
    2177             :     | MONO      | mono out    | EFAP          | EFAP      | EFAP               |
    2178             :     | custom LS | mono out    | EFAP          | EFAP      | EFAP               |
    2179             :     | other     | mono lookup | stereo lookup | EFAP      | conversion mapping |
    2180             :     +-----------+-------------+---------------+-----------+--------------------+
    2181             :     */
    2182             : 
    2183         342 :     test();
    2184         342 :     test();
    2185         342 :     IF( configsAreEqual( inputMc->base.inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut ) )
    2186             :     {
    2187          29 :         error = initMcPanGainsWithIdentMatrix( inputMc );
    2188             :     }
    2189         313 :     ELSE IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ||
    2190             :              EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) ||
    2191             :              EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    2192             :     {
    2193         185 :         test();
    2194         185 :         IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_MONO ) && ( inputMc->nonDiegeticPan ) )
    2195             :         {
    2196           5 :             IF( EQ_32( inputMc->nonDiegeticPanGain_fx, ONE_IN_Q31 ) )
    2197             :             {
    2198           1 :                 inputMc->panGains_fx[0][0] = ONE_IN_Q31;
    2199             :             }
    2200             :             ELSE
    2201             :             {
    2202           4 :                 inputMc->panGains_fx[0][0] = L_add( L_shr( inputMc->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 /* 0.5f in Q31 */ ); /* Q31 */
    2203             :             }
    2204           5 :             move32();
    2205           5 :             inputMc->panGains_fx[0][1] = L_sub( ONE_IN_Q31, inputMc->panGains_fx[0][0] );
    2206           5 :             move32();
    2207           5 :             error = IVAS_ERR_OK;
    2208           5 :             move32();
    2209             :         }
    2210             :         ELSE
    2211             :         {
    2212         180 :             error = initMcPanGainsWithEfap_fx( inputMc, outConfig );
    2213             :         }
    2214             :     }
    2215         128 :     ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MONO ) )
    2216             :     {
    2217          16 :         error = initMcPanGainsWithMonoOut_fx( inputMc );
    2218             :     }
    2219         112 :     ELSE IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_STEREO ) )
    2220             :     {
    2221          12 :         error = initMcPanGainsWithStereoLookup_fx( inputMc );
    2222             :     }
    2223             :     ELSE /* default */
    2224             :     {
    2225         100 :         error = initMcPanGainsWithConversionMapping_fx( inputMc, outConfig );
    2226             :     }
    2227             : 
    2228             :     /* check for errors from above block */
    2229         342 :     IF( NE_32( error, IVAS_ERR_OK ) )
    2230             :     {
    2231           0 :         return error;
    2232             :     }
    2233             : 
    2234             :     /* update LFE panning */
    2235         342 :     error = updateLfePanGainsForMcOut( inputMc, outConfig );
    2236             : 
    2237         342 :     return error;
    2238             : }
    2239          90 : static ivas_error updateMcPanGainsForAmbiOut(
    2240             :     input_mc *inputMc,
    2241             :     const AUDIO_CONFIG outConfig )
    2242             : {
    2243             :     Word16 ch_in, ch_out, lfeIdx, i;
    2244             :     Word16 numNonLfeInChannels, outAmbiOrder;
    2245             :     const Word32 *spkAzi_fx, *spkEle_fx; /* Q22 */
    2246             :     ivas_error error;
    2247             : 
    2248          90 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &outAmbiOrder ) ), IVAS_ERR_OK ) )
    2249             :     {
    2250           0 :         return error;
    2251             :     }
    2252             : 
    2253          90 :     IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    2254             :     {
    2255          54 :         IF( NE_32( ( error = getNumNonLfeChannelsInSpeakerLayout( inputMc->base.inConfig, &numNonLfeInChannels ) ), IVAS_ERR_OK ) )
    2256             :         {
    2257           0 :             return error;
    2258             :         }
    2259             : 
    2260          54 :         IF( NE_32( ( error = getSpeakerAzimuths_fx( inputMc->base.inConfig, &spkAzi_fx ) ), IVAS_ERR_OK ) )
    2261             :         {
    2262           0 :             return error;
    2263             :         }
    2264             : 
    2265          54 :         IF( NE_32( ( error = getSpeakerElevations_fx( inputMc->base.inConfig, &spkEle_fx ) ), IVAS_ERR_OK ) )
    2266             :         {
    2267           0 :             return error;
    2268             :         }
    2269          54 :         ch_in = 0;
    2270          54 :         move16();
    2271         372 :         FOR( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out )
    2272             :         {
    2273         318 :             IF( EQ_16( ch_in, LFE_CHANNEL ) )
    2274             :             {
    2275          36 :                 ch_out = add( ch_out, 1 );
    2276             :             }
    2277         318 :             move16();
    2278         318 :             move16(); // move for typecasting Word32 to Word16
    2279         318 :             ivas_dirac_dec_get_response_fx( (Word16) L_shr( spkAzi_fx[ch_in], 22 ), (Word16) L_shr( spkEle_fx[ch_in], 22 ), inputMc->panGains_fx[ch_out], outAmbiOrder, Q29 );
    2280        5406 :             FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    2281             :             {
    2282        5088 :                 Word32 temp = inputMc->panGains_fx[ch_out][i];
    2283        5088 :                 move32();
    2284             : 
    2285        5088 :                 IF( GE_32( L_abs( temp ), ONE_IN_Q29 ) )
    2286             :                 {
    2287         324 :                     IF( temp > 0 )
    2288             :                     {
    2289         318 :                         inputMc->panGains_fx[ch_out][i] = ONE_IN_Q31;
    2290         318 :                         move32();
    2291             :                     }
    2292             :                     ELSE
    2293             :                     {
    2294           6 :                         inputMc->panGains_fx[ch_out][i] = L_negate( ONE_IN_Q31 );
    2295           6 :                         move32();
    2296             :                     }
    2297             :                 }
    2298             :                 ELSE
    2299             :                 {
    2300        4764 :                     inputMc->panGains_fx[ch_out][i] = L_shl( temp, 2 ); /* Q29 + Q2 = Q31 */
    2301        4764 :                     move32();
    2302             :                 }
    2303             :             }
    2304         318 :             ch_in = add( ch_in, 1 );
    2305             :         }
    2306             :     }
    2307             :     ELSE
    2308             :     {
    2309          36 :         numNonLfeInChannels = inputMc->customLsInput.num_spk;
    2310          36 :         move16();
    2311          36 :         spkAzi_fx = inputMc->customLsInput.ls_azimuth_fx;
    2312          36 :         move32();
    2313          36 :         spkEle_fx = inputMc->customLsInput.ls_elevation_fx;
    2314          36 :         move32();
    2315          36 :         ch_in = 0;
    2316          36 :         move16();
    2317         270 :         FOR( ch_out = 0; ch_in < numNonLfeInChannels; ++ch_out )
    2318             :         {
    2319         234 :             FOR( lfeIdx = 0; lfeIdx < inputMc->customLsInput.num_lfe; ++lfeIdx )
    2320             :             {
    2321           0 :                 IF( EQ_16( inputMc->customLsInput.lfe_idx[lfeIdx], ch_in ) )
    2322             :                 {
    2323           0 :                     ch_out = add( ch_out, 1 );
    2324           0 :                     BREAK;
    2325             :                 }
    2326             :             }
    2327             : 
    2328         234 :             ivas_dirac_dec_get_response_fx( (Word16) L_shr( spkAzi_fx[ch_in], 22 ), (Word16) L_shr( spkEle_fx[ch_in], 22 ), inputMc->panGains_fx[ch_out], outAmbiOrder, Q29 );
    2329        3978 :             FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    2330             :             {
    2331        3744 :                 Word32 temp = inputMc->panGains_fx[ch_out][i];
    2332        3744 :                 move32();
    2333        3744 :                 IF( GE_32( L_abs( temp ), ONE_IN_Q29 ) )
    2334             :                 {
    2335         240 :                     IF( temp > 0 )
    2336             :                     {
    2337         234 :                         inputMc->panGains_fx[ch_out][i] = ONE_IN_Q31;
    2338         234 :                         move32();
    2339             :                     }
    2340             :                     ELSE
    2341             :                     {
    2342           6 :                         inputMc->panGains_fx[ch_out][i] = L_negate( ONE_IN_Q31 );
    2343           6 :                         move32();
    2344             :                     }
    2345             :                 }
    2346             :                 ELSE
    2347             :                 {
    2348        3504 :                     inputMc->panGains_fx[ch_out][i] = L_shl( temp, 2 ); /* Q29 + Q2 = Q31 */
    2349        3504 :                     move32();
    2350             :                 }
    2351             :             }
    2352         234 :             ch_in = add( ch_in, 1 );
    2353             :         }
    2354             :     }
    2355             : 
    2356             :     /* update LFE panning */
    2357          90 :     IF( NE_32( ( error = updateLfePanGainsForAmbiOut( inputMc, outConfig ) ), IVAS_ERR_OK ) )
    2358             :     {
    2359           0 :         return error;
    2360             :     }
    2361             : 
    2362          90 :     return IVAS_ERR_OK;
    2363             : }
    2364         477 : static ivas_error updateMcPanGains(
    2365             :     input_mc *inputMc,
    2366             :     const AUDIO_CONFIG outConfig )
    2367             : {
    2368             :     Word16 i;
    2369             :     ivas_error error;
    2370             : 
    2371             :     /* Reset to all zeros - some functions below only write non-zero elements. */
    2372         477 :     setZeroPanMatrix_fx( inputMc->panGains_fx );
    2373             : 
    2374         477 :     error = IVAS_ERR_OK;
    2375         477 :     move32();
    2376         477 :     SWITCH( getAudioConfigType( outConfig ) )
    2377             :     {
    2378         254 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    2379         254 :             error = updateMcPanGainsForMcOut( inputMc, outConfig );
    2380         254 :             BREAK;
    2381          90 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    2382          90 :             error = updateMcPanGainsForAmbiOut( inputMc, outConfig );
    2383          90 :             BREAK;
    2384         132 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    2385             :             SWITCH( outConfig )
    2386             :             {
    2387          44 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    2388             :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
    2389             :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
    2390          44 :                     BREAK; /* Do nothing */
    2391          88 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    2392             :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    2393             :                     /* Prepare rendering to intermediate format */
    2394          88 :                     error = updateMcPanGainsForMcOut( inputMc, IVAS_AUDIO_CONFIG_7_1_4 );
    2395          88 :                     BREAK;
    2396           0 :                 default:
    2397           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    2398             :             }
    2399         132 :             BREAK;
    2400           1 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    2401           1 :             BREAK; /* Do nothing */
    2402           0 :         default:
    2403           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    2404             :     }
    2405             :     /* Check error here to keep switch statement more compact */
    2406         477 :     IF( NE_32( error, IVAS_ERR_OK ) )
    2407             :     {
    2408           0 :         return error;
    2409             :     }
    2410             : 
    2411             :     /* Copy LFE routing to pan gains array */
    2412         477 :     IF( EQ_16( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    2413             :     {
    2414         210 :         FOR( i = 0; i < inputMc->customLsInput.num_lfe; ++i )
    2415             :         {
    2416           0 :             Copy32( inputMc->lfeRouting.lfePanMtx_fx[i], inputMc->panGains_fx[inputMc->customLsInput.lfe_idx[i]], IVAS_MAX_OUTPUT_CHANNELS );
    2417             :         }
    2418             :     }
    2419             :     ELSE
    2420             :     {
    2421             :         /* For code simplicity, always copy LFE gains. If config has no LFE, gains will be zero anyway. */
    2422         267 :         Copy32( inputMc->lfeRouting.lfePanMtx_fx[0], inputMc->panGains_fx[LFE_CHANNEL], IVAS_MAX_OUTPUT_CHANNELS );
    2423             :     }
    2424             : 
    2425         477 :     return IVAS_ERR_OK;
    2426             : }
    2427             : 
    2428      113253 : static ivas_error initMcBinauralRendering(
    2429             :     input_mc *inputMc,
    2430             :     const AUDIO_CONFIG inConfig,
    2431             :     const AUDIO_CONFIG outConfig,
    2432             :     RENDER_CONFIG_DATA *hRendCfg,
    2433             :     IVAS_DEC_HRTF_CREND_HANDLE hMixconv,
    2434             :     HRTFS_STATISTICS_HANDLE hHrtfStatistics,
    2435             :     uint8_t reconfigureFlag )
    2436             : {
    2437             :     ivas_error error;
    2438             :     Word32 binauralDelayNs;
    2439             :     Word32 outSampleRate;
    2440             :     Word8 useTDRend;
    2441             :     Word16 i, num_poses;
    2442             : 
    2443      113253 :     num_poses = 1;
    2444      113253 :     move16();
    2445      113253 :     if ( inputMc->base.ctx.pSplitRendWrapper != NULL )
    2446             :     {
    2447           0 :         num_poses = inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    2448           0 :         move16();
    2449             :     }
    2450             : 
    2451             :     /* Allocate TD binaural renderer for custom loudspeaker layouts (regardless of headrotation)
    2452             :       or planar MC layouts with headrotation, CREND for the rest */
    2453      113253 :     useTDRend = FALSE;
    2454      113253 :     move16();
    2455      113253 :     IF( NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
    2456             :     {
    2457       75502 :         test();
    2458       75502 :         test();
    2459       75502 :         test();
    2460       75502 :         IF( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
    2461             :         {
    2462       16931 :             useTDRend = TRUE;
    2463       16931 :             move16();
    2464             :         }
    2465       58571 :         ELSE IF( ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_16( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) &&
    2466             :                  ( inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
    2467             :         {
    2468       18408 :             useTDRend = TRUE;
    2469       18408 :             move16();
    2470             :         }
    2471             :     }
    2472             : 
    2473             :     /* if TD renderer was open and we need to use CREND, close it */
    2474      113253 :     test();
    2475      113253 :     IF( !reconfigureFlag || ( !useTDRend && inputMc->tdRendWrapper.hBinRendererTd != NULL ) )
    2476             :     {
    2477         132 :         ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
    2478             :     }
    2479             : 
    2480      113253 :     IF( !reconfigureFlag || !useTDRend )
    2481             :     {
    2482      623568 :         FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    2483             :         {
    2484      545622 :             IF( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
    2485             :             {
    2486           0 :                 ivas_td_binaural_close_fx( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
    2487             :             }
    2488             :         }
    2489             :     }
    2490             : 
    2491             :     /* if we need to use TD renderer and CREND was open, close it */
    2492      113253 :     IF( useTDRend )
    2493             :     {
    2494       35339 :         ivas_rend_closeCrend( &inputMc->crendWrapper, num_poses );
    2495             :     }
    2496             : 
    2497      113253 :     test();
    2498      113253 :     test();
    2499      113253 :     IF( !reconfigureFlag || ( !useTDRend && NE_16( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && inputMc->hReverb != NULL ) )
    2500             :     {
    2501         132 :         ivas_reverb_close( &inputMc->hReverb );
    2502             :     }
    2503             : 
    2504      113253 :     test();
    2505      113253 :     test();
    2506      113253 :     IF( !reconfigureFlag || ( EQ_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && !inputMc->base.ctx.pHeadRotData->headRotEnabled ) )
    2507             :     {
    2508       19638 :         IF( inputMc->efapInWrapper.hEfap != NULL )
    2509             :         {
    2510          36 :             efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
    2511             :         }
    2512             :     }
    2513             : 
    2514      113253 :     outSampleRate = *inputMc->base.ctx.pOutSampleRate;
    2515      113253 :     move32();
    2516             : 
    2517      113253 :     test();
    2518      113253 :     test();
    2519      113253 :     IF( useTDRend && inputMc->tdRendWrapper.hBinRendererTd == NULL )
    2520          32 :     {
    2521             :         Word16 SrcInd[MAX_NUM_TDREND_CHANNELS];
    2522             :         Word16 num_src;
    2523          32 :         IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->tdRendWrapper, inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
    2524             :         {
    2525           0 :             return error;
    2526             :         }
    2527          32 :         Word16 nchan_rend = num_src;
    2528          32 :         move16();
    2529             : 
    2530          32 :         test();
    2531          32 :         IF( ( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ) && NE_16( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    2532             :         {
    2533           8 :             nchan_rend = sub( nchan_rend, 1 ); /* Skip LFE channel -- added to the others */
    2534             :         }
    2535         236 :         FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
    2536             :         {
    2537         204 :             TDREND_SRC_t *Src_p = inputMc->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
    2538         204 :             IF( Src_p != NULL )
    2539             :             {
    2540         204 :                 IF( Src_p->SrcSpatial_p != NULL )
    2541             :                 {
    2542         204 :                     Src_p->SrcSpatial_p->q_Pos_p = 31;
    2543         204 :                     move16();
    2544             :                 }
    2545         204 :                 IF( inputMc->tdRendWrapper.hBinRendererTd->Sources[nS] != NULL )
    2546             :                 {
    2547         204 :                     TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputMc->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
    2548         204 :                     SrcSpatial_p->q_Pos_p = 31;
    2549         204 :                     move16();
    2550             :                 }
    2551             :             }
    2552             :         }
    2553             : 
    2554          32 :         IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    2555             :         {
    2556             :             /* Open TD renderer wrappers */
    2557           0 :             FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    2558             :             {
    2559           0 :                 IF( NE_32( ( error = ivas_td_binaural_open_ext_fx( &inputMc->splitTdRendWrappers[i], inConfig, hRendCfg, &inputMc->customLsInput, outSampleRate, SrcInd, &num_src ) ), IVAS_ERR_OK ) )
    2560             :                 {
    2561           0 :                     return error;
    2562             :                 }
    2563             : 
    2564             :                 /* Assert same delay as main TD renderer */
    2565           0 :                 assert( inputMc->splitTdRendWrappers[i].binaural_latency_ns == inputMc->tdRendWrapper.binaural_latency_ns );
    2566             : 
    2567           0 :                 FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
    2568             :                 {
    2569           0 :                     TDREND_SRC_t *Src_p = inputMc->splitTdRendWrappers[i].hBinRendererTd->Sources[SrcInd[nS]];
    2570           0 :                     IF( Src_p != NULL )
    2571             :                     {
    2572           0 :                         IF( Src_p->SrcSpatial_p != NULL )
    2573             :                         {
    2574           0 :                             Src_p->SrcSpatial_p->q_Pos_p = 31;
    2575           0 :                             move16();
    2576             :                         }
    2577           0 :                         IF( inputMc->splitTdRendWrappers[i].hBinRendererTd->Sources[nS] != NULL )
    2578             :                         {
    2579           0 :                             TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputMc->splitTdRendWrappers[i].hBinRendererTd->Sources[nS]->SrcSpatial_p;
    2580           0 :                             SrcSpatial_p->q_Pos_p = 31;
    2581           0 :                             move16();
    2582             :                         }
    2583             :                     }
    2584             :                 }
    2585             :             }
    2586             :         }
    2587             : 
    2588             : 
    2589          32 :         test();
    2590          32 :         IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) && inputMc->hReverb == NULL )
    2591             :         {
    2592           4 :             IF( NE_32( ( error = ivas_reverb_open_fx( &( inputMc->hReverb ), hHrtfStatistics, hRendCfg, outSampleRate ) ), IVAS_ERR_OK ) )
    2593             :             {
    2594           0 :                 return error;
    2595             :             }
    2596             :         }
    2597             :     }
    2598      113221 :     ELSE IF( !useTDRend && inputMc->crendWrapper == NULL )
    2599             :     {
    2600             :         /* open CREND */
    2601          76 :         IF( NE_32( ( error = ivas_rend_openCrend( &inputMc->crendWrapper, ( inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM ) ? IVAS_AUDIO_CONFIG_7_1_4 : inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, outSampleRate, num_poses ) ), IVAS_ERR_OK ) )
    2602             :         {
    2603           0 :             return error;
    2604             :         }
    2605             :     }
    2606             : 
    2607             :     /* Initialise the EFAP handle for rotation on input layout */
    2608      113253 :     test();
    2609      113253 :     test();
    2610      113253 :     IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && inputMc->base.ctx.pHeadRotData->headRotEnabled && inputMc->efapInWrapper.hEfap == NULL )
    2611             :     {
    2612          30 :         IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inConfig, NULL ) ), IVAS_ERR_OK ) )
    2613             :         {
    2614           0 :             return error;
    2615             :         }
    2616             :     }
    2617             : 
    2618             :     /* determine binaural delay ( used for aligning LFE to output signal ) */
    2619             : 
    2620      113253 :     IF( ( inputMc->crendWrapper != NULL ) )
    2621             :     {
    2622       77914 :         binauralDelayNs = inputMc->crendWrapper->binaural_latency_ns;
    2623             :     }
    2624             :     ELSE
    2625             :     {
    2626       35339 :         binauralDelayNs = 0;
    2627             :     }
    2628      113253 :     move32();
    2629             : 
    2630      113253 :     binauralDelayNs = L_max( binauralDelayNs, inputMc->tdRendWrapper.binaural_latency_ns );
    2631      113253 :     Word16 exp = 0;
    2632      113253 :     move16();
    2633      113253 :     Word16 var1 = BASOP_Util_Divide3232_Scale( *inputMc->base.ctx.pOutSampleRate, 1000000000, &exp );
    2634      113253 :     Word32 var2 = L_shr_r( Mpy_32_32( binauralDelayNs, L_deposit_h( var1 ) ), negate( exp ) ); /* Q0 */
    2635      113253 :     inputMc->binauralDelaySmp = extract_l( var2 );
    2636      113253 :     move16();
    2637             :     // inputMc->binauralDelaySmp = (int16_t) roundf( (float) binauralDelayNs * *inputMc->base.ctx.pOutSampleRate / 1000000000.f );
    2638             : 
    2639      113253 :     IF( GT_16( inputMc->binauralDelaySmp, MAX_BIN_DELAY_SAMPLES ) )
    2640             :     {
    2641           0 :         return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "Invalid delay for LFE binaural rendering!)" );
    2642             :     }
    2643             : 
    2644      113253 :     return IVAS_ERR_OK;
    2645             : }
    2646             : 
    2647           1 : static ivas_error initMcMasaRendering(
    2648             :     input_mc *inputMc,
    2649             :     const AUDIO_CONFIG inConfig,
    2650             :     const Word32 inSampleRate )
    2651             : {
    2652             :     ivas_error error;
    2653             :     Word16 num_poses;
    2654             : 
    2655           1 :     num_poses = 1;
    2656           1 :     move16();
    2657           1 :     if ( inputMc->base.ctx.pSplitRendWrapper != NULL )
    2658             :     {
    2659           0 :         num_poses = inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    2660           0 :         move16();
    2661             :     }
    2662             : 
    2663           1 :     IF( inputMc->tdRendWrapper.hBinRendererTd != NULL )
    2664             :     {
    2665           0 :         ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
    2666             :     }
    2667             : 
    2668           1 :     ivas_rend_closeCrend( &inputMc->crendWrapper, num_poses );
    2669             : 
    2670           1 :     ivas_reverb_close( &inputMc->hReverb );
    2671             : 
    2672           1 :     IF( inputMc->efapInWrapper.hEfap != NULL )
    2673             :     {
    2674           0 :         efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
    2675             :     }
    2676             : 
    2677           1 :     IF( NE_32( ( error = ivas_mcmasa_ana_open( &inputMc->hMcMasa, inConfig, inSampleRate ) ), IVAS_ERR_OK ) )
    2678             :     {
    2679           0 :         return error;
    2680             :     }
    2681             : 
    2682           1 :     return IVAS_ERR_OK;
    2683             : }
    2684             : 
    2685         477 : static lfe_routing defaultLfeRouting(
    2686             :     const AUDIO_CONFIG inConfig,
    2687             :     const LSSETUP_CUSTOM_STRUCT customLsIn,
    2688             :     const AUDIO_CONFIG outConfig,
    2689             :     const LSSETUP_CUSTOM_STRUCT customLsOut )
    2690             : {
    2691             :     Word16 i;
    2692             :     lfe_routing routing;
    2693             : 
    2694             :     /* Set all output gains to zero, then route each input LFE consecutively to the next available output LFE. */
    2695             : 
    2696        2385 :     FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; ++i )
    2697             :     {
    2698        1908 :         set32_fx( routing.lfePanMtx_fx[i], 0, IVAS_MAX_OUTPUT_CHANNELS );
    2699             :     }
    2700         477 :     routing.pan_lfe = false;
    2701         477 :     move16();
    2702         477 :     routing.lfeInputGain_fx = ONE_IN_Q31;
    2703         477 :     move32();
    2704             : 
    2705         477 :     SWITCH( inConfig )
    2706             :     {
    2707         196 :         case IVAS_AUDIO_CONFIG_5_1:
    2708             :         case IVAS_AUDIO_CONFIG_5_1_2:
    2709             :         case IVAS_AUDIO_CONFIG_5_1_4:
    2710             :         case IVAS_AUDIO_CONFIG_7_1:
    2711             :         case IVAS_AUDIO_CONFIG_7_1_4:
    2712         196 :             routing.numLfeChannels = 1;
    2713         196 :             move16();
    2714         196 :             BREAK;
    2715         210 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
    2716         210 :             routing.numLfeChannels = customLsIn.num_lfe;
    2717         210 :             move16();
    2718         210 :             BREAK;
    2719          71 :         default:
    2720          71 :             routing.numLfeChannels = 0;
    2721          71 :             move16();
    2722             :     }
    2723             : 
    2724         477 :     SWITCH( outConfig )
    2725             :     {
    2726         150 :         case IVAS_AUDIO_CONFIG_5_1:
    2727             :         case IVAS_AUDIO_CONFIG_5_1_2:
    2728             :         case IVAS_AUDIO_CONFIG_5_1_4:
    2729             :         case IVAS_AUDIO_CONFIG_7_1:
    2730             :         case IVAS_AUDIO_CONFIG_7_1_4:
    2731         150 :             routing.lfePanMtx_fx[0][LFE_CHANNEL] = ONE_IN_Q31;
    2732         150 :             move32();
    2733         150 :             BREAK;
    2734          39 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
    2735          39 :             FOR( i = 0; i < routing.numLfeChannels && i < customLsOut.num_lfe; ++i )
    2736             :             {
    2737           0 :                 test();
    2738           0 :                 routing.lfePanMtx_fx[i][customLsOut.lfe_idx[i]] = ONE_IN_Q31;
    2739           0 :                 move32();
    2740             :             }
    2741          39 :             BREAK;
    2742         288 :         default:
    2743             :             /* Do nothing */
    2744         288 :             BREAK;
    2745             :     }
    2746             : 
    2747         477 :     return routing;
    2748             : }
    2749         372 : static ivas_error setRendInputActiveMc(
    2750             :     void *input,
    2751             :     const AUDIO_CONFIG inConfig,
    2752             :     const IVAS_REND_InputId id,
    2753             :     RENDER_CONFIG_DATA *hRendCfg,
    2754             :     hrtf_handles *hrtfs )
    2755             : {
    2756             :     Word16 i;
    2757             :     ivas_error error;
    2758             :     rendering_context rendCtx;
    2759             :     AUDIO_CONFIG outConfig;
    2760             :     input_mc *inputMc;
    2761             :     Word16 pos_idx;
    2762             : 
    2763         372 :     inputMc = (input_mc *) input;
    2764         372 :     rendCtx = inputMc->base.ctx;
    2765         372 :     outConfig = *rendCtx.pOutConfig;
    2766             : 
    2767         372 :     IF( !isIoConfigPairSupported( inConfig, outConfig ) )
    2768             :     {
    2769           0 :         return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    2770             :     }
    2771         372 :     IF( NE_32( ( error = allocateMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx, MAX_BIN_DELAY_SAMPLES ) ), IVAS_ERR_OK ) )
    2772             :     {
    2773           0 :         return error;
    2774             :     }
    2775             : 
    2776         372 :     IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMc->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
    2777             :     {
    2778           0 :         return error;
    2779             :     }
    2780         372 :     initRendInputBase_fx( &inputMc->base, inConfig, id, rendCtx, inputMc->bufferData_fx, MAX_BUFFER_LENGTH );
    2781             : 
    2782         372 :     setZeroPanMatrix_fx( inputMc->panGains_fx );
    2783             : 
    2784         372 :     inputMc->customLsInput = defaultCustomLs();
    2785         372 :     inputMc->tdRendWrapper = defaultTdRendWrapper();
    2786             : 
    2787         372 :     if ( hrtfs->hHrtfTD )
    2788             :     {
    2789           0 :         inputMc->tdRendWrapper.binaural_latency_ns = Mult_32_32( hrtfs->hHrtfTD->latency_s_fx, 1000000000 );
    2790             :     }
    2791         372 :     inputMc->tdRendWrapper.hHrtfTD = &hrtfs->hHrtfTD;
    2792         372 :     inputMc->crendWrapper = NULL;
    2793         372 :     inputMc->hReverb = NULL;
    2794         372 :     inputMc->hMcMasa = NULL;
    2795             : 
    2796        3348 :     FOR( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
    2797             :     {
    2798        2976 :         initRotGainsWord32_fx( inputMc->rot_gains_prev_fx[pos_idx] );
    2799             :     }
    2800         372 :     inputMc->lfeRouting = defaultLfeRouting( inConfig, inputMc->customLsInput, outConfig, *inputMc->base.ctx.pCustomLsOut );
    2801         372 :     set32_fx( inputMc->lfeDelayBuffer_fx, 0, MAX_BIN_DELAY_SAMPLES );
    2802         372 :     inputMc->binauralDelaySmp = 0;
    2803         372 :     move16();
    2804             : 
    2805         372 :     test();
    2806         372 :     test();
    2807        2976 :     FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    2808             :     {
    2809        2604 :         if ( hrtfs->hHrtfTD )
    2810             :         {
    2811           0 :             inputMc->splitTdRendWrappers[i].binaural_latency_ns = Mult_32_32( hrtfs->hHrtfTD->latency_s_fx, 1000000000 );
    2812             :         }
    2813        2604 :         inputMc->splitTdRendWrappers[i].hHrtfTD = &hrtfs->hHrtfTD;
    2814             :     }
    2815             : 
    2816         372 :     IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
    2817             :     {
    2818             : 
    2819          96 :         IF( NE_32( ( error = initMcBinauralRendering( inputMc, inConfig, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
    2820             :         {
    2821           0 :             return error;
    2822             :         }
    2823             :     }
    2824             : 
    2825         372 :     test();
    2826         372 :     IF( EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_16( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    2827             :     {
    2828           1 :         IF( NE_32( ( error = initMcMasaRendering( inputMc, inConfig, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    2829             :         {
    2830           0 :             return error;
    2831             :         }
    2832             :     }
    2833             : 
    2834         372 :     IF( NE_32( ( error = updateMcPanGains( inputMc, outConfig ) ), IVAS_ERR_OK ) )
    2835             :     {
    2836           0 :         return error;
    2837             :     }
    2838             : 
    2839         372 :     return IVAS_ERR_OK;
    2840             : }
    2841             : 
    2842         666 : static void clearInputMc(
    2843             :     input_mc *inputMc )
    2844             : {
    2845             :     rendering_context rendCtx;
    2846             :     Word16 i, num_poses;
    2847             : 
    2848         666 :     num_poses = 1;
    2849         666 :     move16();
    2850         666 :     if ( inputMc->base.ctx.pSplitRendWrapper != NULL )
    2851             :     {
    2852           0 :         num_poses = inputMc->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    2853           0 :         move16();
    2854             :     }
    2855             : 
    2856         666 :     rendCtx = inputMc->base.ctx;
    2857         666 :     freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx );
    2858         666 :     freeInputBaseBufferData_fx( &inputMc->bufferData_fx );
    2859         666 :     initRendInputBase_fx( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    2860             : 
    2861             :     /* Free input's internal handles */
    2862         666 :     IF( inputMc->efapInWrapper.hEfap != NULL )
    2863             :     {
    2864          99 :         efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
    2865             :     }
    2866             : 
    2867         666 :     ivas_rend_closeCrend( &inputMc->crendWrapper, num_poses );
    2868             : 
    2869         666 :     ivas_reverb_close( &inputMc->hReverb );
    2870             : 
    2871         666 :     IF( inputMc->tdRendWrapper.hBinRendererTd != NULL )
    2872             :     {
    2873          20 :         ivas_td_binaural_close_fx( &inputMc->tdRendWrapper.hBinRendererTd );
    2874             :     }
    2875             : 
    2876        5328 :     FOR( i = 0; i < MAX_HEAD_ROT_POSES - 1; ++i )
    2877             :     {
    2878        4662 :         IF( inputMc->splitTdRendWrappers[i].hBinRendererTd != NULL )
    2879             :         {
    2880           0 :             ivas_td_binaural_close_fx( &inputMc->splitTdRendWrappers[i].hBinRendererTd );
    2881           0 :             inputMc->splitTdRendWrappers[i].hHrtfTD = NULL;
    2882             :         }
    2883             :     }
    2884             : 
    2885         666 :     ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
    2886             : 
    2887         666 :     return;
    2888             : }
    2889             : 
    2890          89 : static ivas_error initSbaPanGainsForMcOut(
    2891             :     input_sba *inputSba,
    2892             :     const AUDIO_CONFIG outConfig,
    2893             :     const LSSETUP_CUSTOM_STRUCT *outSetupCustom )
    2894             : {
    2895             :     Word16 ambiOrderIn;
    2896             :     Word16 chInIdx, chOutIdx;
    2897             :     Word32 *tmpDecMtx, *readPtr;
    2898             :     IVAS_OUTPUT_SETUP hOutSetup;
    2899             :     ivas_error error;
    2900             : 
    2901          89 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( inputSba->base.inConfig, &ambiOrderIn ) ), IVAS_ERR_OK ) )
    2902             :     {
    2903           0 :         return error;
    2904             :     }
    2905             : 
    2906          89 :     IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    2907             :     {
    2908           0 :         assert( !"Invalid configuration" );
    2909             :         return IVAS_ERR_WRONG_PARAMS;
    2910             :     }
    2911             : 
    2912          89 :     SWITCH( outConfig )
    2913             :     {
    2914           8 :         case IVAS_AUDIO_CONFIG_MONO:
    2915           8 :             hOutSetup.ls_azimuth_fx = ls_azimuth_CICP1_fx;
    2916           8 :             hOutSetup.ls_elevation_fx = ls_elevation_CICP1_fx;
    2917           8 :             ivas_output_init( &hOutSetup, outConfig );
    2918           8 :             BREAK;
    2919          72 :         case IVAS_AUDIO_CONFIG_STEREO:
    2920             :         case IVAS_AUDIO_CONFIG_5_1:
    2921             :         case IVAS_AUDIO_CONFIG_7_1:
    2922             :         case IVAS_AUDIO_CONFIG_5_1_2:
    2923             :         case IVAS_AUDIO_CONFIG_5_1_4:
    2924             :         case IVAS_AUDIO_CONFIG_7_1_4:
    2925          72 :             ivas_output_init( &hOutSetup, outConfig );
    2926          72 :             BREAK;
    2927           9 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
    2928             :             // ivas_ls_custom_setup( &hOutSetup, (LSSETUP_CUSTOM_STRUCT *)outSetupCustom );
    2929           9 :             ivas_ls_custom_setup_fx( &hOutSetup, outSetupCustom );
    2930           9 :             BREAK;
    2931           0 :         default:
    2932           0 :             assert( !"Invalid speaker config" );
    2933             :             return IVAS_ERR_WRONG_PARAMS;
    2934             :     }
    2935             : 
    2936             :     /* obtain and copy over HOA decoding matrix */
    2937          89 :     tmpDecMtx = NULL;
    2938          89 :     IF( NE_32( ( error = ivas_sba_get_hoa_dec_matrix_fx( hOutSetup, &tmpDecMtx, ambiOrderIn ) ), IVAS_ERR_OK ) )
    2939             :     {
    2940           0 :         return error;
    2941             :     }
    2942             : 
    2943          89 :     readPtr = &tmpDecMtx[0];
    2944         861 :     FOR( chOutIdx = 0; chOutIdx < hOutSetup.nchan_out_woLFE + hOutSetup.num_lfe; ++chOutIdx )
    2945             :     {
    2946       13124 :         FOR( chInIdx = 0; chInIdx < SBA_NHARM_HOA3; ++chInIdx )
    2947             :         {
    2948       12352 :             test();
    2949       12352 :             IF( hOutSetup.num_lfe > 0 && EQ_16( chOutIdx, hOutSetup.index_lfe[0] ) )
    2950             :             {
    2951        1024 :                 CONTINUE; /* nothing to be rendered to LFE */
    2952             :             }
    2953       11328 :             inputSba->hoaDecMtx_fx[chInIdx][chOutIdx] = L_shl_sat( *readPtr++, Q2 ); /* Q29 + Q2 = Q31 */
    2954       11328 :             move32();
    2955             :         }
    2956             :     }
    2957          89 :     free( tmpDecMtx );
    2958             : 
    2959          89 :     return IVAS_ERR_OK;
    2960             : }
    2961             : 
    2962          24 : static ivas_error initSbaPanGainsForSbaOut(
    2963             :     input_sba *inputSba,
    2964             :     const AUDIO_CONFIG outConfig )
    2965             : {
    2966             :     ivas_error error;
    2967          24 :     error = IVAS_ERR_OK;
    2968          24 :     move32();
    2969             : 
    2970          24 :     IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    2971             :     {
    2972           0 :         assert( !"Invalid configuration" );
    2973             :         return IVAS_ERR_WRONG_PARAMS;
    2974             :     }
    2975             : 
    2976          24 :     fillIdentityPanMatrix_fx( inputSba->hoaDecMtx_fx );
    2977             : 
    2978          24 :     return error;
    2979             : }
    2980             : 
    2981         126 : static ivas_error updateSbaPanGains(
    2982             :     input_sba *inputSba,
    2983             :     const AUDIO_CONFIG outConfig,
    2984             :     RENDER_CONFIG_DATA *hRendCfg,
    2985             :     IVAS_DEC_HRTF_CREND_HANDLE hMixconv,
    2986             :     IVAS_DEC_HRTF_STATISTICS_HANDLE hHrtfStatistics )
    2987             : {
    2988             :     ivas_error error;
    2989             :     AUDIO_CONFIG inConfig;
    2990             :     rendering_context rendCtx;
    2991             :     Word16 num_poses;
    2992             : 
    2993             :     /* Reset to all zeros - some functions below only write non-zero elements. */
    2994         126 :     setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
    2995             : 
    2996         126 :     inConfig = inputSba->base.inConfig;
    2997         126 :     rendCtx = inputSba->base.ctx;
    2998             : 
    2999         126 :     num_poses = 1;
    3000         126 :     move16();
    3001         126 :     if ( rendCtx.pSplitRendWrapper != NULL )
    3002             :     {
    3003           0 :         num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
    3004           0 :         move16();
    3005             :     }
    3006             : 
    3007         126 :     SWITCH( getAudioConfigType( outConfig ) )
    3008             :     {
    3009          65 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    3010          65 :             error = initSbaPanGainsForMcOut( inputSba, outConfig, inputSba->base.ctx.pCustomLsOut );
    3011          65 :             BREAK;
    3012          24 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    3013          24 :             error = initSbaPanGainsForSbaOut( inputSba, outConfig );
    3014          24 :             BREAK;
    3015          36 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    3016             :             SWITCH( outConfig )
    3017             :             {
    3018           0 :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
    3019             :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
    3020             :                 {
    3021           0 :                     IF( EQ_32( hRendCfg->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
    3022             : 
    3023             :                     {
    3024           0 :                         assert( inConfig == IVAS_AUDIO_CONFIG_HOA3 && ( *rendCtx.pOutSampleRate == 48000 ) && "split binaural fast conv mode is currently supported with HOA3 input and 48k sampling rate only" );
    3025           0 :                         if ( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
    3026             :                         {
    3027           0 :                             return error;
    3028             :                         }
    3029             :                     }
    3030             :                     else
    3031             :                     {
    3032           0 :                         assert( ( *rendCtx.pOutSampleRate == 48000 ) && "split binaural crend mode is currently supported with 48k sampling rate only" );
    3033           0 :                         if ( ( error = ivas_rend_openMultiBinCrend( &inputSba->crendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
    3034             :                         {
    3035           0 :                             return error;
    3036             :                         }
    3037             :                     }
    3038           0 :                     break;
    3039             :                 }
    3040          12 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    3041             :                 {
    3042          12 :                     if ( hRendCfg->split_rend_config.rendererSelection == ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV )
    3043             :                     {
    3044           0 :                         if ( ( error = ivas_rend_openCldfbRend( &inputSba->cldfbRendWrapper, inConfig, outConfig, &rendCtx.pSplitRendWrapper->multiBinPoseData, *rendCtx.pOutSampleRate ) ) != IVAS_ERR_OK )
    3045             :                         {
    3046           0 :                             return error;
    3047             :                         }
    3048             :                     }
    3049             :                     else
    3050             :                     {
    3051          12 :                         IF( NE_32( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, inConfig, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
    3052             :                         {
    3053           0 :                             return error;
    3054             :                         }
    3055             :                     }
    3056             :                 }
    3057          12 :                     BREAK;
    3058          24 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    3059             :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    3060          24 :                     IF( NE_32( ( error = initSbaPanGainsForMcOut( inputSba, IVAS_AUDIO_CONFIG_7_1_4, NULL ) ), IVAS_ERR_OK ) )
    3061             :                     {
    3062           0 :                         return error;
    3063             :                     }
    3064          24 :                     IF( NE_32( ( error = ivas_rend_openCrend( &inputSba->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, hRendCfg, hMixconv, hHrtfStatistics, *rendCtx.pOutSampleRate, num_poses ) ), IVAS_ERR_OK ) )
    3065             :                     {
    3066           0 :                         return error;
    3067             :                     }
    3068          24 :                     BREAK;
    3069           0 :                 default:
    3070           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    3071             :             }
    3072          36 :             BREAK;
    3073           1 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    3074           1 :             error = IVAS_ERR_OK;
    3075           1 :             move32();
    3076           1 :             BREAK; /* Do nothing */
    3077           0 :         default:
    3078           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    3079             :     }
    3080             : 
    3081             :     /* Check error here to keep switch statement more compact */
    3082         126 :     IF( NE_32( error, IVAS_ERR_OK ) )
    3083             :     {
    3084           0 :         return error;
    3085             :     }
    3086             : 
    3087         126 :     return IVAS_ERR_OK;
    3088             : }
    3089             : 
    3090           1 : static ivas_error initSbaMasaRendering(
    3091             :     input_sba *inputSba,
    3092             :     Word32 inSampleRate )
    3093             : {
    3094             :     ivas_error error;
    3095             :     Word16 num_poses;
    3096             : 
    3097           1 :     num_poses = 1;
    3098           1 :     move16();
    3099           1 :     if ( inputSba->base.ctx.pSplitRendWrapper != NULL )
    3100             :     {
    3101           0 :         num_poses = inputSba->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    3102           0 :         move16();
    3103             :     }
    3104             : 
    3105           1 :     ivas_rend_closeCrend( &inputSba->crendWrapper, num_poses );
    3106             : 
    3107           1 :     IF( NE_32( ( error = ivas_dirac_ana_open_fx( &inputSba->hDirAC, inSampleRate ) ), IVAS_ERR_OK ) )
    3108             :     {
    3109           0 :         return error;
    3110             :     }
    3111             : 
    3112           1 :     return IVAS_ERR_OK;
    3113             : }
    3114             : 
    3115         126 : static ivas_error setRendInputActiveSba(
    3116             :     void *input,
    3117             :     const AUDIO_CONFIG inConfig,
    3118             :     const IVAS_REND_InputId id,
    3119             :     RENDER_CONFIG_DATA *hRendCfg,
    3120             :     hrtf_handles *hrtfs )
    3121             : {
    3122             :     ivas_error error;
    3123             :     rendering_context rendCtx;
    3124             :     AUDIO_CONFIG outConfig;
    3125             :     input_sba *inputSba;
    3126             :     Word16 pos_idx;
    3127             : 
    3128         126 :     inputSba = (input_sba *) input;
    3129         126 :     rendCtx = inputSba->base.ctx;
    3130         126 :     outConfig = *rendCtx.pOutConfig;
    3131         126 :     move32();
    3132             : 
    3133         126 :     IF( !isIoConfigPairSupported( inConfig, outConfig ) )
    3134             :     {
    3135           0 :         return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    3136             :     }
    3137             : 
    3138         126 :     IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputSba->bufferData_fx, MAX_CLDFB_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
    3139             :     {
    3140           0 :         return error;
    3141             :     }
    3142             : 
    3143         126 :     initRendInputBase_fx( &inputSba->base, inConfig, id, rendCtx, inputSba->bufferData_fx, MAX_CLDFB_BUFFER_LENGTH );
    3144             : 
    3145         126 :     setZeroPanMatrix_fx( inputSba->hoaDecMtx_fx );
    3146             : 
    3147         126 :     inputSba->crendWrapper = NULL;
    3148         126 :     inputSba->hDirAC = NULL;
    3149        1134 :     FOR( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
    3150             :     {
    3151        1008 :         initRotGains_fx( inputSba->rot_gains_prev_fx[pos_idx] );
    3152             :     }
    3153         126 :     inputSba->cldfbRendWrapper.hHrtfFastConv = hrtfs->hHrtfFastConv;
    3154             : 
    3155         126 :     test();
    3156         126 :     IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    3157             :     {
    3158           1 :         IF( NE_32( ( error = initSbaMasaRendering( inputSba, *rendCtx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    3159             :         {
    3160           0 :             return error;
    3161             :         }
    3162             :     }
    3163         126 :     IF( NE_32( ( error = updateSbaPanGains( inputSba, outConfig, hRendCfg, hrtfs->hSetOfHRTF, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
    3164             :     {
    3165           0 :         return error;
    3166             :     }
    3167             : 
    3168         126 :     return error;
    3169             : }
    3170             : 
    3171         666 : static void clearInputSba(
    3172             :     input_sba *inputSba )
    3173             : {
    3174             :     rendering_context rendCtx;
    3175             :     Word16 num_poses;
    3176             : 
    3177         666 :     rendCtx = inputSba->base.ctx;
    3178             : 
    3179         666 :     num_poses = 1;
    3180         666 :     move16();
    3181         666 :     if ( rendCtx.pSplitRendWrapper != NULL )
    3182             :     {
    3183           0 :         num_poses = rendCtx.pSplitRendWrapper->multiBinPoseData.num_poses;
    3184           0 :         move16();
    3185             :     }
    3186             : 
    3187         666 :     freeInputBaseBufferData_fx( &inputSba->bufferData_fx );
    3188             : 
    3189         666 :     initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    3190             : 
    3191         666 :     ivas_rend_closeCrend( &inputSba->crendWrapper, num_poses );
    3192             : 
    3193         666 :     IF( inputSba->cldfbRendWrapper.hCldfbRend != NULL )
    3194             :     {
    3195           0 :         ivas_rend_closeCldfbRend( &inputSba->cldfbRendWrapper );
    3196             :     }
    3197             : 
    3198         666 :     ivas_dirac_ana_close_fx( &( inputSba->hDirAC ) );
    3199             : 
    3200         666 :     return;
    3201             : }
    3202             : 
    3203          49 : static ivas_error setRendInputActiveMasa(
    3204             :     void *input,
    3205             :     const AUDIO_CONFIG inConfig,
    3206             :     const IVAS_REND_InputId id,
    3207             :     RENDER_CONFIG_DATA *hRendCfg,
    3208             :     hrtf_handles *hrtfs )
    3209             : {
    3210             :     ivas_error error;
    3211             :     rendering_context rendCtx;
    3212             :     AUDIO_CONFIG outConfig;
    3213             :     input_masa *inputMasa;
    3214             :     Word16 numInChannels;
    3215             : 
    3216          49 :     inputMasa = (input_masa *) input;
    3217          49 :     rendCtx = inputMasa->base.ctx;
    3218          49 :     outConfig = *rendCtx.pOutConfig;
    3219          49 :     move32();
    3220             : 
    3221          49 :     IF( !isIoConfigPairSupported( inConfig, outConfig ) )
    3222             :     {
    3223           0 :         return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    3224             :     }
    3225             : 
    3226          49 :     IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputMasa->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
    3227             :     {
    3228           0 :         return error;
    3229             :     }
    3230          49 :     initRendInputBase_fx( &inputMasa->base, inConfig, id, rendCtx, inputMasa->bufferData_fx, MAX_BUFFER_LENGTH );
    3231             : 
    3232          49 :     IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &numInChannels ) ), IVAS_ERR_OK ) )
    3233             :     {
    3234           0 :         return error;
    3235             :     }
    3236             : 
    3237          49 :     IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    3238             :     {
    3239           1 :         inputMasa->metadataHasBeenFed = false;
    3240           1 :         move16();
    3241             :         Word16 temp;
    3242           1 :         IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
    3243             :         {
    3244           0 :             temp = 1;
    3245             :         }
    3246             :         ELSE
    3247             :         {
    3248           1 :             temp = 2;
    3249             :         }
    3250           1 :         move16();
    3251           1 :         IF( NE_32( ( error = masaPrerendOpen_fx( &inputMasa->hMasaPrerend, temp, *( inputMasa->base.ctx.pOutSampleRate ) ) ), IVAS_ERR_OK ) )
    3252             :         {
    3253           0 :             return error;
    3254             :         }
    3255             :     }
    3256             :     ELSE
    3257             :     {
    3258          48 :         IF( NE_32( ( error = initMasaExtRenderer( inputMasa, outConfig, hRendCfg, hrtfs ) ), IVAS_ERR_OK ) )
    3259             :         {
    3260           0 :             return error;
    3261             :         }
    3262          48 :         inputMasa->metadataHasBeenFed = false;
    3263          48 :         move16();
    3264             :     }
    3265             : 
    3266          49 :     return IVAS_ERR_OK;
    3267             : }
    3268             : 
    3269         666 : static void clearInputMasa(
    3270             :     input_masa *inputMasa )
    3271             : {
    3272             :     rendering_context rendCtx;
    3273             : 
    3274         666 :     rendCtx = inputMasa->base.ctx;
    3275             : 
    3276         666 :     freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
    3277             : 
    3278         666 :     masaPrerendClose_fx( &inputMasa->hMasaPrerend );
    3279             : 
    3280         666 :     freeMasaExtRenderer( &inputMasa->hMasaExtRend );
    3281             : 
    3282         666 :     initRendInputBase_fx( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    3283             : 
    3284         666 :     return;
    3285             : }
    3286             : 
    3287             : 
    3288             : /*-------------------------------------------------------------------------
    3289             :  * IVAS_REND_Open()
    3290             :  *
    3291             :  *
    3292             :  *------------------------------------------------------------------------*/
    3293             : 
    3294         666 : ivas_error IVAS_REND_Open(
    3295             :     IVAS_REND_HANDLE *phIvasRend,      /* i/o: Pointer to renderer handle                          */
    3296             :     const Word32 outputSampleRate,     /* i  : output sampling rate                                */
    3297             :     const IVAS_AUDIO_CONFIG outConfig, /* i  : output audio config                                 */
    3298             :     const bool asHrtfBinary,           /* i  : load hrtf binary file                               */
    3299             :     const Word16 nonDiegeticPan,       /* i  : non-diegetic object flag                            */
    3300             :     const Word32 nonDiegeticPanGain,   /* i  : non-diegetic panning gain                        Q31*/
    3301             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3302             :     const Word16 Opt_Headrotation,        /* i  : indicates whether head-rotation is used             */
    3303             :     const Word16 Opt_ExternalOrientation, /* i  : indicates whether external orientations are used    */
    3304             : #endif
    3305             :     const Word16 num_subframes /* i  : number of subframes                                 */
    3306             : )
    3307             : {
    3308             :     Word16 i;
    3309             :     Word16 j;
    3310             :     IVAS_REND_HANDLE hIvasRend;
    3311             :     ivas_error error;
    3312             :     Word16 numOutChannels;
    3313             : 
    3314             :     /* Validate function arguments */
    3315         666 :     IF( phIvasRend == NULL )
    3316             :     {
    3317           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3318             :     }
    3319             : 
    3320         666 :     IF( NE_32( ( error = validateOutputAudioConfig( outConfig ) ), IVAS_ERR_OK ) )
    3321             :     {
    3322           0 :         return error;
    3323             :     }
    3324             : 
    3325         666 :     IF( NE_32( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ), IVAS_ERR_OK ) )
    3326             :     {
    3327           0 :         return error;
    3328             :     }
    3329             : 
    3330         666 :     *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
    3331         666 :     IF( *phIvasRend == NULL )
    3332             :     {
    3333           0 :         return IVAS_ERR_FAILED_ALLOC;
    3334             :     }
    3335             : 
    3336         666 :     hIvasRend = *phIvasRend;
    3337         666 :     hIvasRend->sampleRateOut = outputSampleRate;
    3338         666 :     hIvasRend->outputConfig = outConfig;
    3339         666 :     hIvasRend->customLsOut = defaultCustomLs();
    3340         666 :     hIvasRend->hLimiter = NULL;
    3341         666 :     hIvasRend->efapOutWrapper.hEfap = NULL;
    3342         666 :     hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
    3343         666 :     hIvasRend->num_subframes = num_subframes;
    3344             : 
    3345             :     /* Initialize limiter */
    3346         666 :     IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
    3347             :     {
    3348           0 :         return error;
    3349             :     }
    3350             : 
    3351         666 :     IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ), IVAS_ERR_OK ) )
    3352             :     {
    3353           0 :         return error;
    3354             :     }
    3355             : 
    3356             :     /* Initialize headrotation data */
    3357             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3358         666 :     hIvasRend->headRotData.headRotEnabled = 0;
    3359         666 :     IF( Opt_Headrotation )
    3360             :     {
    3361             : #endif
    3362          94 :         IF( NE_32( ( error = initHeadRotation_fx( hIvasRend ) ), IVAS_ERR_OK ) )
    3363             :         {
    3364           0 :             return error;
    3365             :         }
    3366             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3367             :     }
    3368             : #endif
    3369             : 
    3370             :     /* Initialize external orientation data */
    3371             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3372         666 :     hIvasRend->hExternalOrientationData = NULL;
    3373         666 :     IF( Opt_ExternalOrientation )
    3374             :     {
    3375             : #endif
    3376           0 :         IF( NE_32( ( error = ivas_external_orientation_open( &( hIvasRend->hExternalOrientationData ), num_subframes ) ), IVAS_ERR_OK ) )
    3377             :         {
    3378           0 :             return error;
    3379             :         }
    3380             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3381             :     }
    3382             : #endif
    3383             : 
    3384             :     /* Initilize combined orientation data */
    3385             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3386         666 :     hIvasRend->hCombinedOrientationData = NULL;
    3387         666 :     IF( Opt_Headrotation || Opt_ExternalOrientation )
    3388             :     {
    3389             : #endif
    3390          94 :         IF( NE_32( ( error = ivas_combined_orientation_open( &( hIvasRend->hCombinedOrientationData ), outputSampleRate, num_subframes ) ), IVAS_ERR_OK ) )
    3391             :         {
    3392           0 :             return error;
    3393             :         }
    3394             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3395             :     }
    3396             : #endif
    3397             : 
    3398             :     /* Initialize EFAP */
    3399         666 :     IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, outConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
    3400             :     {
    3401           0 :         return error;
    3402             :     }
    3403             : 
    3404             :     /* Initialize inputs */
    3405         666 :     hIvasRend->splitRendWrapper = NULL;
    3406         666 :     test();
    3407         666 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    3408             :     {
    3409           0 :         if ( ( hIvasRend->splitRendWrapper = (SPLIT_REND_WRAPPER *) malloc( sizeof( SPLIT_REND_WRAPPER ) ) ) == NULL )
    3410             :         {
    3411           0 :             return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Cannot allocate memory for IVAS renderer handle" );
    3412             :         }
    3413             : 
    3414           0 :         isar_init_split_rend_handles( hIvasRend->splitRendWrapper );
    3415             :     }
    3416             : 
    3417        3330 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    3418             :     {
    3419        2664 :         initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    3420        2664 :         hIvasRend->inputsIsm[i].crendWrapper = NULL;
    3421        2664 :         hIvasRend->inputsIsm[i].hReverb = NULL;
    3422        2664 :         hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
    3423       21312 :         FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j )
    3424             :         {
    3425       18648 :             hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
    3426       18648 :             hIvasRend->inputsIsm[i].splitTdRendWrappers[j].hHrtfTD = NULL;
    3427             :         }
    3428        2664 :         hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
    3429        2664 :         move16();
    3430        2664 :         hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
    3431        2664 :         move32();
    3432        2664 :         hIvasRend->inputsIsm[i].hOMasa = NULL;
    3433        2664 :         hIvasRend->inputsIsm[i].bufferData_fx = NULL;
    3434             :     }
    3435             : 
    3436        1332 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    3437             :     {
    3438         666 :         initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    3439             : 
    3440         666 :         hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
    3441         666 :         hIvasRend->inputsMc[i].crendWrapper = NULL;
    3442         666 :         hIvasRend->inputsMc[i].hReverb = NULL;
    3443         666 :         hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
    3444         666 :         hIvasRend->inputsMc[i].bufferData_fx = NULL;
    3445         666 :         hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL;
    3446         666 :         hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
    3447         666 :         move16();
    3448         666 :         hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
    3449         666 :         move32();
    3450         666 :         hIvasRend->inputsMc[i].hMcMasa = NULL;
    3451        5328 :         FOR( j = 0; j < MAX_HEAD_ROT_POSES - 1; ++j )
    3452             :         {
    3453        4662 :             hIvasRend->inputsMc[i].splitTdRendWrappers[j].hBinRendererTd = NULL;
    3454        4662 :             hIvasRend->inputsMc[i].splitTdRendWrappers[j].hHrtfTD = NULL;
    3455             :         }
    3456             :     }
    3457             : 
    3458        1332 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    3459             :     {
    3460         666 :         initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    3461             : 
    3462         666 :         hIvasRend->inputsSba[i].crendWrapper = NULL;
    3463         666 :         hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend = NULL;
    3464         666 :         hIvasRend->inputsSba[i].cldfbRendWrapper.hHrtfFastConv = NULL;
    3465         666 :         hIvasRend->inputsSba[i].bufferData_fx = NULL;
    3466         666 :         hIvasRend->inputsSba[i].hDirAC = NULL;
    3467             :     }
    3468             : 
    3469        1332 :     FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
    3470             :     {
    3471         666 :         initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    3472             : 
    3473         666 :         hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
    3474         666 :         hIvasRend->inputsMasa[i].bufferData_fx = NULL;
    3475         666 :         hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
    3476         666 :         hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
    3477         666 :         move16();
    3478             :     }
    3479             : 
    3480         666 :     hIvasRend->hHrtfs.hHrtfFastConv = NULL;
    3481         666 :     hIvasRend->hHrtfs.hHrtfParambin = NULL;
    3482         666 :     hIvasRend->hHrtfs.hHrtfTD = NULL;
    3483         666 :     hIvasRend->hHrtfs.hSetOfHRTF = NULL;
    3484         666 :     hIvasRend->hHrtfs.hHrtfStatistics = NULL;
    3485         666 :     IF( asHrtfBinary )
    3486             :     {
    3487           0 :         IF( NE_32( ( error = ivas_HRTF_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfTD ) ) ), IVAS_ERR_OK ) )
    3488             :         {
    3489           0 :             return error;
    3490             :         }
    3491           0 :         IF( NE_32( ( error = ivas_HRTF_CRend_binary_open_fx( &( hIvasRend->hHrtfs.hSetOfHRTF ) ) ), IVAS_ERR_OK ) )
    3492             :         {
    3493           0 :             return error;
    3494             :         }
    3495           0 :         IF( NE_32( ( error = ivas_HRTF_fastconv_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfFastConv ) ) ), IVAS_ERR_OK ) )
    3496             :         {
    3497           0 :             return error;
    3498             :         }
    3499           0 :         IF( NE_32( ( error = ivas_HRTF_parambin_binary_open_fx( &( hIvasRend->hHrtfs.hHrtfParambin ) ) ), IVAS_ERR_OK ) )
    3500             :         {
    3501           0 :             return error;
    3502             :         }
    3503           0 :         IF( NE_32( ( error = ivas_HRTF_statistics_binary_open( &( hIvasRend->hHrtfs.hHrtfStatistics ) ) ), IVAS_ERR_OK ) )
    3504             :         {
    3505           0 :             return error;
    3506             :         }
    3507             :     }
    3508             : 
    3509             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3510         666 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) )
    3511             :     {
    3512             : #endif
    3513          60 :         IF( NE_32( ( error = ivas_HRTF_statistics_init( &( hIvasRend->hHrtfs.hHrtfStatistics ), hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
    3514             :         {
    3515           0 :             return error;
    3516             :         }
    3517             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    3518             :     }
    3519             : #endif
    3520             : 
    3521         666 :     return IVAS_ERR_OK;
    3522             : }
    3523             : 
    3524             : 
    3525         152 : static LSSETUP_CUSTOM_STRUCT makeCustomLsSetup(
    3526             :     const IVAS_CUSTOM_LS_DATA rendCustomLsLayout )
    3527             : {
    3528             :     Word16 i;
    3529             :     LSSETUP_CUSTOM_STRUCT customLs;
    3530             : 
    3531             :     /* Copy layout description */
    3532         152 :     customLs.num_spk = rendCustomLsLayout.num_spk;
    3533         152 :     move16();
    3534         152 :     Copy32( rendCustomLsLayout.azimuth_fx, customLs.ls_azimuth_fx, rendCustomLsLayout.num_spk );
    3535         152 :     Copy32( rendCustomLsLayout.elevation_fx, customLs.ls_elevation_fx, rendCustomLsLayout.num_spk );
    3536         152 :     customLs.is_planar_setup = 1;
    3537         152 :     move16();
    3538         776 :     FOR( i = 0; i < rendCustomLsLayout.num_spk; ++i )
    3539             :     {
    3540         776 :         IF( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
    3541             :         {
    3542         152 :             customLs.is_planar_setup = 0;
    3543         152 :             move16();
    3544         152 :             BREAK;
    3545             :         }
    3546             :     }
    3547             : 
    3548         152 :     customLs.num_lfe = rendCustomLsLayout.num_lfe;
    3549         152 :     move16();
    3550         152 :     Copy( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
    3551             : 
    3552         152 :     return customLs;
    3553             : }
    3554             : 
    3555             : 
    3556         152 : static ivas_error validateCustomLsLayout_fx(
    3557             :     const IVAS_CUSTOM_LS_DATA layout )
    3558             : {
    3559             :     Word16 i;
    3560             : 
    3561             :     /* Negative number of speakers or LFEs makes no sense */
    3562         152 :     test();
    3563         152 :     IF( layout.num_spk < 0 || layout.num_lfe < 0 )
    3564             :     {
    3565           0 :         return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
    3566             :     }
    3567             : 
    3568             :     /* There must be at least one speaker or LFE in the layout */
    3569         152 :     IF( add( layout.num_spk, layout.num_lfe ) <= 0 )
    3570             :     {
    3571           0 :         return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
    3572             :     }
    3573             : 
    3574             :     /* LFE indices must be positive */
    3575         152 :     FOR( i = 0; i < layout.num_lfe; ++i )
    3576             :     {
    3577           0 :         IF( layout.lfe_idx[i] < 0 )
    3578             :         {
    3579           0 :             return IVAS_ERR_INVALID_CUSTOM_LS_LAYOUT;
    3580             :         }
    3581             :     }
    3582             : 
    3583         152 :     return IVAS_ERR_OK;
    3584             : }
    3585             : 
    3586             : 
    3587             : /*-------------------------------------------------------------------*
    3588             :  * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
    3589             :  *
    3590             :  *
    3591             :  *-------------------------------------------------------------------*/
    3592             : 
    3593          47 : ivas_error IVAS_REND_ConfigureCustomOutputLoudspeakerLayout(
    3594             :     IVAS_REND_HANDLE hIvasRend,
    3595             :     const IVAS_CUSTOM_LS_DATA layout )
    3596             : {
    3597             :     Word16 i, numOutChannels;
    3598             :     ivas_error error;
    3599             :     input_mc *inputMc;
    3600             :     input_sba *inputSba;
    3601             : 
    3602             :     /* Validate function arguments */
    3603          47 :     IF( hIvasRend == NULL )
    3604             :     {
    3605           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3606             :     }
    3607             : 
    3608          47 :     IF( NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    3609             :     {
    3610             :         /* Specifying details of custom speaker layout only makes sense if output config is set to custom speaker layout */
    3611           0 :         return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    3612             :     }
    3613             : 
    3614          47 :     IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
    3615             :     {
    3616           0 :         return error;
    3617             :     }
    3618             : 
    3619          47 :     hIvasRend->customLsOut = makeCustomLsSetup( layout );
    3620             : 
    3621             :     /* Re-initialize limiter - number of output channels may have changed */
    3622          47 :     IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
    3623             :     {
    3624           0 :         return error;
    3625             :     }
    3626             : 
    3627          47 :     IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, hIvasRend->sampleRateOut ) ), IVAS_ERR_OK ) )
    3628             :     {
    3629           0 :         return error;
    3630             :     }
    3631             : 
    3632             :     /* Re-initialize EFAP - output layout has changed or has been fully defined for the first time */
    3633          47 :     IF( NE_32( ( error = initEfap( &hIvasRend->efapOutWrapper, hIvasRend->outputConfig, &hIvasRend->customLsOut ) ), IVAS_ERR_OK ) )
    3634             :     {
    3635           0 :         return error;
    3636             :     }
    3637             : 
    3638             :     /* Re-initialize panning gains for each active MC input, This includes re-initializing
    3639             :      * LFE handling for the new output layout, which means custom LFE handling is overwritten,
    3640             :      * if previously set for any MC input. */
    3641          94 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    3642             :     {
    3643          47 :         inputMc = &hIvasRend->inputsMc[i];
    3644          47 :         IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3645             :         {
    3646             :             /* Input inactive, skip. */
    3647          47 :             CONTINUE;
    3648             :         }
    3649             : 
    3650           0 :         inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
    3651             : 
    3652           0 :         IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
    3653             :         {
    3654           0 :             return error;
    3655             :         }
    3656             :     }
    3657             : 
    3658             :     /* Re-initialize panning gains for each active SBA input */
    3659          94 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    3660             :     {
    3661          47 :         inputSba = &hIvasRend->inputsSba[i];
    3662             : 
    3663          47 :         IF( EQ_32( inputSba->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3664             :         {
    3665             :             /* Input inactive, skip. */
    3666          47 :             CONTINUE;
    3667             :         }
    3668           0 :         IF( NE_32( ( error = updateSbaPanGains( inputSba, hIvasRend->outputConfig, hIvasRend->hRendererConfig, NULL, NULL ) ), IVAS_ERR_OK ) )
    3669             :         {
    3670           0 :             return error;
    3671             :         }
    3672             :     }
    3673             : 
    3674          47 :     return IVAS_ERR_OK;
    3675             : }
    3676             : 
    3677             : /*-------------------------------------------------------------------*
    3678             :  * IVAS_REND_NumOutChannels()
    3679             :  *
    3680             :  *
    3681             :  *-------------------------------------------------------------------*/
    3682             : 
    3683     1127519 : ivas_error IVAS_REND_NumOutChannels(
    3684             :     IVAS_REND_CONST_HANDLE hIvasRend,
    3685             :     Word16 *numOutChannels )
    3686             : {
    3687             :     ivas_error error;
    3688             : 
    3689             :     /* Validate function arguments */
    3690     1127519 :     test();
    3691     1127519 :     IF( hIvasRend == NULL || numOutChannels == NULL )
    3692             :     {
    3693           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3694             :     }
    3695             : 
    3696             :     /* Handle special cases where additional info is needed from the renderer, otherwise use getAudioConfigNumChannels() */
    3697     1127519 :     SWITCH( hIvasRend->outputConfig )
    3698             :     {
    3699       36003 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
    3700       36003 :             *numOutChannels = add( hIvasRend->customLsOut.num_spk, hIvasRend->customLsOut.num_lfe );
    3701       36003 :             move16();
    3702       36003 :             BREAK;
    3703     1091516 :         default:
    3704     1091516 :             IF( NE_32( ( error = getAudioConfigNumChannels( hIvasRend->outputConfig, numOutChannels ) ), IVAS_ERR_OK ) )
    3705             :             {
    3706           0 :                 return error;
    3707             :             }
    3708     1091516 :             BREAK;
    3709             :     }
    3710             : 
    3711     1127519 :     return IVAS_ERR_OK;
    3712             : }
    3713             : 
    3714             : 
    3715         973 : static IVAS_REND_InputId makeInputId(
    3716             :     AUDIO_CONFIG config,
    3717             :     const Word32 inputIndex )
    3718             : {
    3719             :     /* Put config type in second byte (from LSB), put index + 1 in first byte
    3720             :      *
    3721             :      * Index is incremented here so that a valid ID can never be 0. */
    3722         973 :     return (IVAS_REND_InputId) UL_or( UL_lshl( ( (UWord32) getAudioConfigType( config ) ), 8 ), L_add( inputIndex, 1 ) );
    3723             : }
    3724             : 
    3725             : 
    3726     3133018 : static ivas_error getInputById(
    3727             :     IVAS_REND_HANDLE hIvasRend,
    3728             :     IVAS_REND_InputId inputId,
    3729             :     void **ppInput )
    3730             : {
    3731             :     Word32 inputIndex;
    3732             :     IVAS_REND_AudioConfigType configType;
    3733             :     input_base *pInputBase;
    3734             : 
    3735             :     /* Reverse makeInputId() */
    3736     3133018 :     inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
    3737     3133018 :     configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
    3738             : 
    3739             :     /* Validate values derived from input ID */
    3740     3133018 :     IF( inputIndex < 0 )
    3741             :     {
    3742           0 :         return IVAS_ERR_INVALID_INPUT_ID;
    3743             :     }
    3744     3133018 :     SWITCH( configType )
    3745             :     {
    3746     2495576 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    3747     2495576 :             IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
    3748             :             {
    3749           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3750             :             }
    3751     2495576 :             pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
    3752     2495576 :             BREAK;
    3753      360012 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    3754      360012 :             IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
    3755             :             {
    3756           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3757             :             }
    3758      360012 :             pInputBase = &hIvasRend->inputsMc[inputIndex].base;
    3759      360012 :             BREAK;
    3760      251881 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    3761      251881 :             IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
    3762             :             {
    3763           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3764             :             }
    3765      251881 :             pInputBase = &hIvasRend->inputsSba[inputIndex].base;
    3766      251881 :             BREAK;
    3767       25549 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    3768       25549 :             IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
    3769             :             {
    3770           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3771             :             }
    3772       25549 :             pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
    3773       25549 :             BREAK;
    3774           0 :         default:
    3775           0 :             return IVAS_ERR_INVALID_INPUT_ID;
    3776             :     }
    3777             : 
    3778             :     /* Ensure input ID matches and that input is active */
    3779     3133018 :     test();
    3780     3133018 :     IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3781             :     {
    3782           0 :         return IVAS_ERR_INVALID_INPUT_ID;
    3783             :     }
    3784             : 
    3785             :     /* Validation done, set value via output parameter */
    3786     3133018 :     *ppInput = pInputBase;
    3787             : 
    3788     3133018 :     return IVAS_ERR_OK;
    3789             : }
    3790             : 
    3791             : 
    3792      630413 : static ivas_error getConstInputById(
    3793             :     IVAS_REND_CONST_HANDLE hIvasRend,
    3794             :     const IVAS_REND_InputId inputId,
    3795             :     const void **ppInput )
    3796             : {
    3797             :     Word32 inputIndex;
    3798             :     IVAS_REND_AudioConfigType configType;
    3799             :     const input_base *pInputBase;
    3800             : 
    3801             :     /* Reverse makeInputId() */
    3802      630413 :     inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
    3803      630413 :     configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
    3804             : 
    3805             :     /* Validate values derived from input ID */
    3806      630413 :     IF( inputIndex < 0 )
    3807             :     {
    3808           0 :         return IVAS_ERR_INVALID_INPUT_ID;
    3809             :     }
    3810      630413 :     SWITCH( configType )
    3811             :     {
    3812         426 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    3813         426 :             IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
    3814             :             {
    3815           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3816             :             }
    3817         426 :             pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
    3818         426 :             BREAK;
    3819      359907 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    3820      359907 :             IF( GT_32( inputIndex, RENDERER_MAX_MC_INPUTS ) )
    3821             :             {
    3822           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3823             :             }
    3824      359907 :             pInputBase = &hIvasRend->inputsMc[inputIndex].base;
    3825      359907 :             BREAK;
    3826      251881 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    3827      251881 :             IF( GT_32( inputIndex, RENDERER_MAX_SBA_INPUTS ) )
    3828             :             {
    3829           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3830             :             }
    3831      251881 :             pInputBase = &hIvasRend->inputsSba[inputIndex].base;
    3832      251881 :             BREAK;
    3833       18199 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    3834       18199 :             IF( GT_32( inputIndex, RENDERER_MAX_MASA_INPUTS ) )
    3835             :             {
    3836           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3837             :             }
    3838       18199 :             pInputBase = &hIvasRend->inputsMasa[inputIndex].base;
    3839       18199 :             BREAK;
    3840           0 :         default:
    3841           0 :             return IVAS_ERR_INVALID_INPUT_ID;
    3842             :     }
    3843             : 
    3844             :     /* Ensure input ID matches and that input is active */
    3845      630413 :     test();
    3846      630413 :     IF( NE_32( pInputBase->id, inputId ) || EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3847             :     {
    3848           0 :         return IVAS_ERR_INVALID_INPUT_ID;
    3849             :     }
    3850             : 
    3851             :     /* Validation done, set value via output parameter */
    3852      630413 :     *ppInput = pInputBase;
    3853             : 
    3854      630413 :     return IVAS_ERR_OK;
    3855             : }
    3856             : 
    3857         973 : static ivas_error findFreeInputSlot_fx(
    3858             :     const void *inputs,
    3859             :     const Word32 inputStructSize,
    3860             :     const Word32 maxInputs,
    3861             :     Word32 *inputIndex )
    3862             : {
    3863             :     /* Using a void pointer and a separately provided size is a hack for this function
    3864             :            to be reusable for arrays of any input type (input_ism, input_mc, input_sba, input_masa).
    3865             :             Assumptions:
    3866             :                 - input_base is always the first member in the input struct
    3867             :                 - provided size is correct
    3868             :         */
    3869             : 
    3870             :     Word32 i;
    3871             :     bool canAddInput;
    3872             :     const UWord8 *pByte;
    3873             :     const input_base *pInputBase;
    3874             : 
    3875         973 :     canAddInput = false;
    3876         973 :     move16();
    3877             : 
    3878             :     /* Find first unused input in array */
    3879        1353 :     FOR( ( i = 0, pByte = inputs ); i < maxInputs; ( ++i, pByte += inputStructSize ) )
    3880             :     {
    3881        1353 :         pInputBase = (const input_base *) pByte;
    3882             : 
    3883        1353 :         IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3884             :         {
    3885         973 :             *inputIndex = i;
    3886         973 :             move32();
    3887         973 :             canAddInput = true;
    3888         973 :             move16();
    3889         973 :             BREAK;
    3890             :         }
    3891             :     }
    3892             : 
    3893         973 :     IF( !canAddInput )
    3894             :     {
    3895           0 :         return IVAS_ERR_TOO_MANY_INPUTS;
    3896             :     }
    3897             : 
    3898         973 :     return IVAS_ERR_OK;
    3899             : }
    3900             : 
    3901             : 
    3902             : /*-------------------------------------------------------------------------
    3903             :  * Function getCldfbRendFlag()
    3904             :  *
    3905             :  *
    3906             :  *------------------------------------------------------------------------*/
    3907             : 
    3908           0 : static Word16 getCldfbRendFlag(
    3909             :     IVAS_REND_HANDLE hIvasRend, /* i  : Renderer handle               */
    3910             :     const IVAS_REND_AudioConfigType new_configType )
    3911             : {
    3912             :     Word16 i;
    3913           0 :     Word16 numMasaInputs = 0, numSbaInputs = 0, numIsmInputs = 0, numMcInputs = 0;
    3914             :     Word16 isCldfbRend;
    3915             : 
    3916           0 :     move16();
    3917           0 :     move16();
    3918           0 :     move16();
    3919           0 :     move16();
    3920             : 
    3921           0 :     isCldfbRend = 0;
    3922           0 :     move16();
    3923             : 
    3924           0 :     IF( hIvasRend->hRendererConfig != NULL )
    3925             :     {
    3926           0 :         FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
    3927             :         {
    3928           0 :             numMasaInputs = add( numMasaInputs, ( hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) ? 0 : 1 );
    3929           0 :             move16();
    3930             :         }
    3931           0 :         FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    3932             :         {
    3933           0 :             numSbaInputs = add( numSbaInputs, ( hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) ? 0 : 1 );
    3934           0 :             move16();
    3935             :         }
    3936           0 :         FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    3937             :         {
    3938           0 :             numIsmInputs = add( numIsmInputs, ( hIvasRend->inputsIsm[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) ? 0 : 1 );
    3939           0 :             move16();
    3940             :         }
    3941           0 :         FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    3942             :         {
    3943           0 :             numMcInputs = add( numMcInputs, ( hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID && new_configType != IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) ? 0 : 1 );
    3944           0 :             move16();
    3945             :         }
    3946             : 
    3947           0 :         IF( GT_16( numIsmInputs, 0 ) || GT_16( numMcInputs, 0 ) )
    3948             :         {
    3949           0 :             isCldfbRend = 0;
    3950           0 :             move16();
    3951             :         }
    3952           0 :         ELSE IF( GT_16( numMasaInputs, 0 ) || ( GT_16( numSbaInputs, 0 ) && EQ_32( hIvasRend->hRendererConfig->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) ) )
    3953             :         {
    3954           0 :             isCldfbRend = 1;
    3955           0 :             move16();
    3956             :         }
    3957             :     }
    3958             : 
    3959           0 :     return isCldfbRend;
    3960             : }
    3961             : 
    3962             : 
    3963             : /*-------------------------------------------------------------------------
    3964             :  * Function ivas_pre_rend_init()
    3965             :  *
    3966             :  *
    3967             :  *------------------------------------------------------------------------*/
    3968             : 
    3969           0 : static ivas_error ivas_pre_rend_init(
    3970             :     SPLIT_REND_WRAPPER *pSplitRendWrapper,
    3971             :     IVAS_REND_AudioBuffer *pSplitRendEncBuffer,
    3972             :     ISAR_SPLIT_REND_CONFIG_DATA *pSplit_rend_config,
    3973             :     IVAS_REND_HeadRotData headRotData,
    3974             :     const Word32 outputSampleRate,
    3975             :     const AUDIO_CONFIG outConfig,
    3976             :     const Word16 cldfb_in_flag,
    3977             :     const Word16 num_subframes )
    3978             : {
    3979             :     ivas_error error;
    3980             :     IVAS_REND_AudioBufferConfig bufConfig;
    3981             : 
    3982           0 :     test();
    3983           0 :     IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    3984             :     {
    3985           0 :         IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
    3986             :         {
    3987           0 :             ISAR_PRE_REND_GetMultiBinPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData, headRotData.sr_pose_pred_axis );
    3988             :         }
    3989           0 :         ELSE IF( EQ_32( pSplit_rend_config->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE ) )
    3990             :         {
    3991           0 :             isar_renderSplitUpdateNoCorrectionPoseData( pSplit_rend_config, &pSplitRendWrapper->multiBinPoseData );
    3992             :         }
    3993             : 
    3994           0 :         IF( ( error = ISAR_PRE_REND_open( pSplitRendWrapper, pSplit_rend_config, outputSampleRate, cldfb_in_flag, outConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM, num_subframes, 0 ) ) != IVAS_ERR_OK )
    3995             :         {
    3996           0 :             return error;
    3997             :         }
    3998             : 
    3999             :         /*allocate for CLDFB in and change to TD during process if needed*/
    4000           0 :         bufConfig.numSamplesPerChannel = MAX_CLDFB_BUFFER_LENGTH_PER_CHANNEL;
    4001           0 :         bufConfig.numChannels = i_mult( BINAURAL_CHANNELS, pSplitRendWrapper->multiBinPoseData.num_poses );
    4002           0 :         bufConfig.is_cldfb = 1;
    4003           0 :         pSplitRendEncBuffer->config = bufConfig;
    4004           0 :         move16();
    4005           0 :         move16();
    4006           0 :         move16();
    4007           0 :         move32();
    4008             : 
    4009           0 :         IF( ( pSplitRendEncBuffer->data_fx = malloc( bufConfig.numChannels * bufConfig.numSamplesPerChannel * sizeof( float ) ) ) == NULL )
    4010             :         {
    4011           0 :             return IVAS_ERR_FAILED_ALLOC;
    4012             :         }
    4013             : 
    4014           0 :         pSplitRendEncBuffer->q_factor = 0;
    4015           0 :         pSplitRendEncBuffer->pq_fact = &pSplitRendEncBuffer->q_factor;
    4016             :     }
    4017             :     ELSE
    4018             :     {
    4019             :         IVAS_REND_AudioBufferConfig bufConfig2;
    4020             : 
    4021           0 :         bufConfig2.numSamplesPerChannel = 0;
    4022           0 :         bufConfig2.numChannels = 0;
    4023           0 :         bufConfig2.is_cldfb = 0;
    4024           0 :         pSplitRendEncBuffer->config = bufConfig2;
    4025           0 :         pSplitRendEncBuffer->data_fx = NULL;
    4026           0 :         pSplitRendEncBuffer->pq_fact = NULL;
    4027           0 :         pSplitRendEncBuffer->q_factor = 0;
    4028           0 :         move16();
    4029           0 :         move16();
    4030           0 :         move16();
    4031           0 :         move32();
    4032           0 :         move32();
    4033             :     }
    4034             : 
    4035           0 :     return IVAS_ERR_OK;
    4036             : }
    4037             : 
    4038             : 
    4039             : /*-------------------------------------------------------------------*
    4040             :  * IVAS_REND_AddInput()
    4041             :  *
    4042             :  *
    4043             :  *-------------------------------------------------------------------*/
    4044             : 
    4045         973 : ivas_error IVAS_REND_AddInput_fx(
    4046             :     IVAS_REND_HANDLE hIvasRend,  /* i/o: Renderer handle               */
    4047             :     const AUDIO_CONFIG inConfig, /* i  : audio config for a new input  */
    4048             :     IVAS_REND_InputId *inputId   /* o  : ID of the new input           */
    4049             : )
    4050             : {
    4051             :     ivas_error error;
    4052             :     Word32 maxNumInputsOfType;
    4053             :     void *inputsArray;
    4054             :     Word32 inputStructSize;
    4055             :     ivas_error ( *activateInput )( void *, AUDIO_CONFIG, IVAS_REND_InputId, RENDER_CONFIG_DATA *, hrtf_handles *hrtfs );
    4056             :     Word32 inputIndex;
    4057             : 
    4058             :     /* Validate function arguments */
    4059         973 :     test();
    4060         973 :     IF( hIvasRend == NULL || inputId == NULL )
    4061             :     {
    4062           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4063             :     }
    4064             : 
    4065         973 :     IF( ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ) && hIvasRend->splitRendEncBuffer.data_fx == NULL && hIvasRend->hRendererConfig != NULL )
    4066             :     {
    4067             :         Word16 cldfb_in_flag;
    4068           0 :         cldfb_in_flag = getCldfbRendFlag( hIvasRend, getAudioConfigType( inConfig ) );
    4069             : 
    4070           0 :         IF( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
    4071             :         {
    4072           0 :             return error;
    4073             :         }
    4074             :     }
    4075             : 
    4076             : 
    4077         973 :     SWITCH( getAudioConfigType( inConfig ) )
    4078             :     {
    4079         426 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    4080         426 :             maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
    4081         426 :             inputsArray = hIvasRend->inputsIsm;
    4082         426 :             inputStructSize = sizeof( *hIvasRend->inputsIsm );
    4083         426 :             activateInput = setRendInputActiveIsm;
    4084         426 :             move32();
    4085         426 :             move32();
    4086         426 :             BREAK;
    4087         372 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    4088         372 :             maxNumInputsOfType = RENDERER_MAX_MC_INPUTS;
    4089         372 :             inputsArray = hIvasRend->inputsMc;
    4090         372 :             inputStructSize = sizeof( *hIvasRend->inputsMc );
    4091         372 :             activateInput = setRendInputActiveMc;
    4092         372 :             move32();
    4093         372 :             move32();
    4094         372 :             BREAK;
    4095         126 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    4096         126 :             maxNumInputsOfType = RENDERER_MAX_SBA_INPUTS;
    4097         126 :             inputsArray = hIvasRend->inputsSba;
    4098         126 :             inputStructSize = sizeof( *hIvasRend->inputsSba );
    4099         126 :             activateInput = setRendInputActiveSba;
    4100         126 :             move32();
    4101         126 :             move32();
    4102         126 :             BREAK;
    4103          49 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    4104          49 :             maxNumInputsOfType = RENDERER_MAX_MASA_INPUTS;
    4105          49 :             inputsArray = hIvasRend->inputsMasa;
    4106          49 :             inputStructSize = sizeof( *hIvasRend->inputsMasa );
    4107          49 :             activateInput = setRendInputActiveMasa;
    4108          49 :             move32();
    4109          49 :             move32();
    4110          49 :             BREAK;
    4111           0 :         default:
    4112           0 :             return IVAS_ERR_INVALID_INPUT_FORMAT;
    4113             :     }
    4114             : 
    4115             :     /* Find first free input in array corresponding to input type */
    4116         973 :     IF( NE_32( ( error = findFreeInputSlot_fx( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ), IVAS_ERR_OK ) )
    4117             :     {
    4118           0 :         return error;
    4119             :     }
    4120             : 
    4121         973 :     *inputId = makeInputId( inConfig, inputIndex );
    4122         973 :     move16();
    4123         973 :     IF( NE_32( ( error = activateInput( (uint8_t *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig, &hIvasRend->hHrtfs ) ), IVAS_ERR_OK ) )
    4124             :     {
    4125           0 :         return error;
    4126             :     }
    4127             : 
    4128         973 :     return IVAS_ERR_OK;
    4129             : }
    4130             : 
    4131             : 
    4132             : /*-------------------------------------------------------------------*
    4133             :  * IVAS_REND_ConfigureCustomInputLoudspeakerLayout()
    4134             :  *
    4135             :  *
    4136             :  * Note: this will reset any custom LFE routing set for the input
    4137             :  *-------------------------------------------------------------------*/
    4138         105 : ivas_error IVAS_REND_ConfigureCustomInputLoudspeakerLayout(
    4139             :     IVAS_REND_HANDLE hIvasRend,      /* i/o: Renderer handle                        */
    4140             :     const IVAS_REND_InputId inputId, /* i  : ID of the input                        */
    4141             :     const IVAS_CUSTOM_LS_DATA layout /* i  : custom loudspeaker layout for input    */
    4142             : )
    4143             : {
    4144             :     input_mc *inputMc;
    4145             :     ivas_error error;
    4146             : 
    4147             :     /* Validate function arguments */
    4148         105 :     IF( hIvasRend == NULL )
    4149             :     {
    4150           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4151             :     }
    4152             : 
    4153         105 :     IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
    4154             :     {
    4155           0 :         return error;
    4156             :     }
    4157             : 
    4158         105 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputMc ) ), IVAS_ERR_OK ) )
    4159             :     {
    4160           0 :         return error;
    4161             :     }
    4162             : 
    4163         105 :     IF( NE_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    4164             :     {
    4165             :         /* Specifying details of custom speaker layout only makes sense if input config is set to custom speaker layout */
    4166           0 :         return IVAS_ERR_INVALID_INPUT_FORMAT;
    4167             :     }
    4168             : 
    4169             :     /* Re-initialize panning gains for the MC input, This includes re-initializing LFE handling
    4170             :      * for the new input layout, which means custom LFE handling is overwritten, if previously
    4171             :      * set for the MC input. */
    4172         105 :     inputMc->customLsInput = makeCustomLsSetup( layout );
    4173             : 
    4174         105 :     inputMc->lfeRouting = defaultLfeRouting( inputMc->base.inConfig, inputMc->customLsInput, hIvasRend->outputConfig, *inputMc->base.ctx.pCustomLsOut );
    4175             : 
    4176         105 :     IF( NE_32( ( error = initEfap( &inputMc->efapInWrapper, inputMc->base.inConfig, &inputMc->customLsInput ) ), IVAS_ERR_OK ) )
    4177             :     {
    4178           0 :         return error;
    4179             :     }
    4180             : 
    4181         105 :     test();
    4182         105 :     test();
    4183             : 
    4184         105 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
    4185             :     {
    4186          36 :         IF( NE_32( ( error = initMcBinauralRendering( inputMc, inputMc->base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, FALSE ) ), IVAS_ERR_OK ) )
    4187             :         {
    4188           0 :             return error;
    4189             :         }
    4190             :     }
    4191             : 
    4192         105 :     IF( NE_32( ( error = updateMcPanGains( inputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
    4193             :     {
    4194           0 :         return error;
    4195             :     }
    4196             : 
    4197         105 :     return IVAS_ERR_OK;
    4198             : }
    4199             : 
    4200             : /*-------------------------------------------------------------------*
    4201             :  * IVAS_REND_SetInputGain()
    4202             :  *
    4203             :  *
    4204             :  *-------------------------------------------------------------------*/
    4205         973 : ivas_error IVAS_REND_SetInputGain_fx(
    4206             :     IVAS_REND_HANDLE hIvasRend,      /* i/o: Renderer handle             */
    4207             :     const IVAS_REND_InputId inputId, /* i  : ID of the input             */
    4208             :     const Word32 gain                /* i  : linear gain (not in dB) Q30 */
    4209             : )
    4210             : {
    4211             :     input_base *inputBase;
    4212             :     ivas_error error;
    4213             : 
    4214             :     /* Validate function arguments */
    4215         973 :     IF( hIvasRend == NULL )
    4216             :     {
    4217           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4218             :     }
    4219             : 
    4220         973 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    4221             :     {
    4222           0 :         return error;
    4223             :     }
    4224             : 
    4225         973 :     inputBase->gain_fx = gain;
    4226         973 :     move32();
    4227             : 
    4228         973 :     return IVAS_ERR_OK;
    4229             : }
    4230             : 
    4231             : /*-------------------------------------------------------------------*
    4232             :  * IVAS_REND_SetInputLfeMtx()
    4233             :  *
    4234             :  *
    4235             :  *-------------------------------------------------------------------*/
    4236           0 : ivas_error IVAS_REND_SetInputLfeMtx_fx(
    4237             :     IVAS_REND_HANDLE hIvasRend,             /* i/o: Renderer handle        */
    4238             :     const IVAS_REND_InputId inputId,        /* i  : ID of the input        */
    4239             :     const IVAS_REND_LfePanMtx_fx *lfePanMtx /* i  : LFE panning matrix     */
    4240             : )
    4241             : {
    4242             :     Word16 i;
    4243             :     input_base *pInputBase;
    4244             :     input_mc *pInputMc;
    4245             :     ivas_error error;
    4246             : 
    4247             :     /* Validate function arguments */
    4248           0 :     IF( hIvasRend == NULL )
    4249             :     {
    4250           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4251             :     }
    4252             : 
    4253           0 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
    4254             :     {
    4255           0 :         return error;
    4256             :     }
    4257             : 
    4258           0 :     IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    4259             :     {
    4260             :         /* Custom LFE panning matrix only makes sense with channel-based input */
    4261           0 :         return IVAS_ERR_INVALID_INPUT_FORMAT;
    4262             :     }
    4263           0 :     pInputMc = (input_mc *) pInputBase;
    4264             : 
    4265             :     /* copy LFE panning matrix */
    4266           0 :     FOR( i = 0; i < RENDERER_MAX_INPUT_LFE_CHANNELS; i++ )
    4267             :     {
    4268           0 :         Copy32( ( *lfePanMtx )[i], pInputMc->lfeRouting.lfePanMtx_fx[i], IVAS_MAX_OUTPUT_CHANNELS );
    4269             :     }
    4270             : 
    4271           0 :     IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
    4272             :     {
    4273           0 :         return error;
    4274             :     }
    4275             : 
    4276           0 :     return IVAS_ERR_OK;
    4277             : }
    4278             : 
    4279             : /*-------------------------------------------------------------------*
    4280             :  * IVAS_REND_SetInputLfePos()
    4281             :  *
    4282             :  *
    4283             :  *-------------------------------------------------------------------*/
    4284             : 
    4285           0 : ivas_error IVAS_REND_SetInputLfePos_fx(
    4286             :     IVAS_REND_HANDLE hIvasRend,      /* i/o: Renderer handle                                    */
    4287             :     const IVAS_REND_InputId inputId, /* i  : ID of the input                                    */
    4288             :     const Word32 inputGain,          /* i  : Input gain to be applied to the LFE channel(s) Q31 */
    4289             :     const Word16 outputAzimuth,      /* i  : Output azimuth position                         Q0 */
    4290             :     const Word16 outputElevation     /* i  : Output elevation position                       Q0 */
    4291             : )
    4292             : {
    4293             :     input_base *pInputBase;
    4294             :     input_mc *pInputMc;
    4295             :     ivas_error error;
    4296             : 
    4297             :     /* Validate function arguments */
    4298           0 :     IF( hIvasRend == NULL )
    4299             :     {
    4300           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4301             :     }
    4302             : 
    4303           0 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &pInputBase ) ), IVAS_ERR_OK ) )
    4304             :     {
    4305           0 :         return error;
    4306             :     }
    4307             : 
    4308           0 :     IF( NE_32( getAudioConfigType( pInputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    4309             :     {
    4310             :         /* Custom LFE routing only makes sense with channel-based input */
    4311           0 :         return IVAS_ERR_INVALID_INPUT_FORMAT;
    4312             :     }
    4313           0 :     pInputMc = (input_mc *) pInputBase;
    4314             : 
    4315           0 :     pInputMc->lfeRouting.pan_lfe = true;
    4316           0 :     move16();
    4317           0 :     pInputMc->lfeRouting.lfeInputGain_fx = inputGain; /* Q31 */
    4318           0 :     move32();
    4319           0 :     pInputMc->lfeRouting.lfeOutputAzimuth_fx = outputAzimuth; /* Q0 */
    4320           0 :     move16();
    4321           0 :     pInputMc->lfeRouting.lfeOutputElevation_fx = outputElevation; /* Q0 */
    4322           0 :     move16();
    4323             : 
    4324           0 :     IF( NE_32( ( error = updateMcPanGains( pInputMc, hIvasRend->outputConfig ) ), IVAS_ERR_OK ) )
    4325             :     {
    4326           0 :         return error;
    4327             :     }
    4328             : 
    4329           0 :     return IVAS_ERR_OK;
    4330             : }
    4331             : 
    4332             : /*-------------------------------------------------------------------*
    4333             :  * IVAS_REND_RemoveInput()
    4334             :  *
    4335             :  *
    4336             :  *-------------------------------------------------------------------*/
    4337             : /* ToDo; unused function */
    4338           0 : ivas_error IVAS_REND_RemoveInput(
    4339             :     IVAS_REND_HANDLE hIvasRend,     /* i/o: Renderer handle     */
    4340             :     const IVAS_REND_InputId inputId /* i  : ID of the input     */
    4341             : )
    4342             : {
    4343             :     ivas_error error;
    4344             :     input_base *inputBase;
    4345             : 
    4346             :     /* Validate function arguments */
    4347           0 :     IF( hIvasRend == NULL )
    4348             :     {
    4349           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4350             :     }
    4351             : 
    4352           0 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    4353             :     {
    4354           0 :         return error;
    4355             :     }
    4356             : 
    4357           0 :     SWITCH( getAudioConfigType( inputBase->inConfig ) )
    4358             :     {
    4359           0 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    4360           0 :             clearInputIsm( (input_ism *) inputBase );
    4361           0 :             BREAK;
    4362           0 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    4363           0 :             clearInputMc( (input_mc *) inputBase );
    4364           0 :             BREAK;
    4365           0 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    4366           0 :             clearInputSba( (input_sba *) inputBase );
    4367           0 :             BREAK;
    4368           0 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    4369           0 :             clearInputMasa( (input_masa *) inputBase );
    4370           0 :             BREAK;
    4371           0 :         default:
    4372           0 :             return IVAS_ERR_INVALID_INPUT_FORMAT;
    4373             :     }
    4374             : 
    4375           0 :     return IVAS_ERR_OK;
    4376             : }
    4377             : 
    4378             : 
    4379             : /*-------------------------------------------------------------------*
    4380             :  * IVAS_REND_GetInputNumChannels()
    4381             :  *
    4382             :  *
    4383             :  *-------------------------------------------------------------------*/
    4384      630413 : ivas_error IVAS_REND_GetInputNumChannels(
    4385             :     IVAS_REND_CONST_HANDLE hIvasRend, /* i  : Renderer handle                   */
    4386             :     const IVAS_REND_InputId inputId,  /* i  : ID of the input                   */
    4387             :     Word16 *numChannels               /* o  : number of channels of the input   */
    4388             : )
    4389             : {
    4390             :     ivas_error error;
    4391             :     const input_base *pInput;
    4392             : 
    4393             :     /* Validate function arguments */
    4394      630413 :     test();
    4395      630413 :     IF( hIvasRend == NULL || numChannels == NULL )
    4396             :     {
    4397           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4398             :     }
    4399             : 
    4400      630413 :     IF( NE_32( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ), IVAS_ERR_OK ) )
    4401             :     {
    4402           0 :         return error;
    4403             :     }
    4404             : 
    4405      630413 :     IF( NE_32( ( error = getRendInputNumChannels( pInput, numChannels ) ), IVAS_ERR_OK ) )
    4406             :     {
    4407           0 :         return error;
    4408             :     }
    4409             : 
    4410      630413 :     return IVAS_ERR_OK;
    4411             : }
    4412             : 
    4413             : /*-------------------------------------------------------------------*
    4414             :  * IVAS_REND_GetNumAllObjects()
    4415             :  *
    4416             :  *
    4417             :  *-------------------------------------------------------------------*/
    4418         426 : ivas_error IVAS_REND_GetNumAllObjects(
    4419             :     IVAS_REND_CONST_HANDLE hIvasRend, /* i  : Renderer handle       */
    4420             :     Word16 *numChannels               /* o  : number of all objects */
    4421             : )
    4422             : {
    4423         426 :     test();
    4424         426 :     IF( hIvasRend == NULL || numChannels == NULL )
    4425             :     {
    4426           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4427             :     }
    4428             : 
    4429         426 :     test();
    4430         426 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    4431             :     {
    4432           1 :         *numChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
    4433           1 :         move16();
    4434             :     }
    4435             : 
    4436         426 :     return IVAS_ERR_OK;
    4437             : }
    4438             : 
    4439             : 
    4440             : /*-------------------------------------------------------------------*
    4441             :  * IVAS_REND_GetDelay()
    4442             :  *
    4443             :  *
    4444             :  *-------------------------------------------------------------------*/
    4445             : 
    4446           0 : ivas_error IVAS_REND_GetDelay_fx(
    4447             :     IVAS_REND_CONST_HANDLE hIvasRend, /* i  : Renderer state                                                    */
    4448             :     Word16 *nSamples,                 /* o  : Renderer delay in samples                                         */
    4449             :     Word32 *timeScale                 /* o  : Time scale of the delay, equal to renderer output sampling rate   */
    4450             : )
    4451             : {
    4452             :     /* TODO tmu : this function only returns the maximum delay across all inputs
    4453             :      * Ideally each input has its own delay buffer and everything is aligned (binaural and LFE filtering delays are nonuniform)
    4454             :      */
    4455             :     Word16 i;
    4456             :     Word32 latency_ns;
    4457             :     Word32 max_latency_ns;
    4458             : 
    4459           0 :     Word32 timescale_by_ns[7] = { 0, 17180, 34360, 0, 68719, 0, 103079 };
    4460           0 :     move32();
    4461           0 :     move32();
    4462           0 :     move32();
    4463           0 :     move32();
    4464           0 :     move32();
    4465           0 :     move32();
    4466           0 :     move32();
    4467             : 
    4468             :     /* Validate function arguments */
    4469           0 :     test();
    4470           0 :     test();
    4471           0 :     IF( hIvasRend == NULL || nSamples == NULL || timeScale == NULL )
    4472             :     {
    4473           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4474             :     }
    4475             : 
    4476           0 :     *timeScale = hIvasRend->sampleRateOut;
    4477           0 :     move32();
    4478           0 :     assert( *timeScale == 8000 || *timeScale == 16000 || *timeScale == 32000 || *timeScale == 48000 );
    4479           0 :     *nSamples = 0;
    4480           0 :     move16();
    4481           0 :     max_latency_ns = 0;
    4482           0 :     move32();
    4483             : 
    4484             :     /* Compute the maximum delay across all inputs */
    4485           0 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; i++ )
    4486             :     {
    4487           0 :         IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    4488             :         {
    4489           0 :             IF( hIvasRend->inputsIsm[i].crendWrapper != NULL )
    4490             :             {
    4491           0 :                 latency_ns = hIvasRend->inputsIsm[i].crendWrapper->binaural_latency_ns;
    4492             :             }
    4493             :             ELSE
    4494             :             {
    4495           0 :                 latency_ns = 0;
    4496             :             }
    4497           0 :             move32();
    4498             : 
    4499           0 :             latency_ns = L_max( latency_ns, hIvasRend->inputsIsm[i].tdRendWrapper.binaural_latency_ns );
    4500           0 :             max_latency_ns = L_max( max_latency_ns, latency_ns );
    4501             :         }
    4502             :     }
    4503             : 
    4504           0 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
    4505             :     {
    4506           0 :         IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    4507             :         {
    4508           0 :             IF( ( hIvasRend->inputsMc[i].crendWrapper != NULL ) )
    4509             :             {
    4510           0 :                 latency_ns = hIvasRend->inputsMc[i].crendWrapper->binaural_latency_ns;
    4511             :             }
    4512             :             ELSE
    4513             :             {
    4514           0 :                 latency_ns = 0;
    4515             :             }
    4516             : 
    4517           0 :             move32();
    4518             : 
    4519           0 :             latency_ns = L_max( latency_ns, hIvasRend->inputsMc[i].tdRendWrapper.binaural_latency_ns );
    4520           0 :             max_latency_ns = L_max( max_latency_ns, latency_ns );
    4521             :         }
    4522             :     }
    4523             : 
    4524           0 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
    4525             :     {
    4526           0 :         IF( NE_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    4527             :         {
    4528             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    4529           0 :             test();
    4530           0 :             IF( hIvasRend->splitRendWrapper != NULL && hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL )
    4531             : #else
    4532             :             IF( hIvasRend->splitRendWrapper->hBinHrSplitPreRend != NULL )
    4533             : #endif
    4534             :             {
    4535           0 :                 IF( hIvasRend->hRendererConfig->split_rend_config.rendererSelection == ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV )
    4536             :                 {
    4537           0 :                     latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
    4538           0 :                     move32();
    4539             :                 }
    4540             :                 ELSE
    4541             :                 {
    4542           0 :                     IF( ( hIvasRend->inputsSba[i].crendWrapper != NULL ) )
    4543             :                     {
    4544           0 :                         latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
    4545             :                     }
    4546             :                     ELSE
    4547             :                     {
    4548           0 :                         latency_ns = 0;
    4549             :                     }
    4550           0 :                     move32();
    4551             :                 }
    4552           0 :                 max_latency_ns = L_max( max_latency_ns, latency_ns );
    4553             :             }
    4554           0 :             ELSE IF( hIvasRend->inputsSba[i].cldfbRendWrapper.hCldfbRend != NULL )
    4555             :             {
    4556           0 :                 latency_ns = hIvasRend->inputsSba[i].cldfbRendWrapper.binaural_latency_ns;
    4557           0 :                 move32();
    4558           0 :                 latency_ns = L_add( latency_ns, IVAS_FB_DEC_DELAY_NS );
    4559           0 :                 max_latency_ns = L_max( max_latency_ns, latency_ns );
    4560             :             }
    4561             :             ELSE
    4562             :             {
    4563           0 :                 IF( hIvasRend->inputsSba[i].crendWrapper != NULL )
    4564             :                 {
    4565           0 :                     latency_ns = hIvasRend->inputsSba[i].crendWrapper->binaural_latency_ns;
    4566             :                 }
    4567             :                 ELSE
    4568             :                 {
    4569           0 :                     latency_ns = 0;
    4570             :                 }
    4571           0 :                 move32();
    4572           0 :                 max_latency_ns = L_max( max_latency_ns, latency_ns );
    4573             :             }
    4574             :         }
    4575             :     }
    4576             : 
    4577           0 :     FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
    4578             :     {
    4579           0 :         IF( NE_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    4580             :         {
    4581           0 :             latency_ns = (Word32) ( IVAS_FB_DEC_DELAY_NS );
    4582           0 :             move32();
    4583           0 :             max_latency_ns = L_max( max_latency_ns, latency_ns );
    4584             :         }
    4585             :     }
    4586             : 
    4587             :     //*nSamples = (Word16) roundf( (float) max_latency_ns * *timeScale / 1000000000.f );
    4588           0 :     Word32 temp = Mpy_32_32( *timeScale, 268436 ); // Q0 + Q31 - Q31 -> Q0, ( 1 / 8000 ) * 2 ^ 31
    4589           0 :     *nSamples = extract_l( Mpy_32_32_r( max_latency_ns, timescale_by_ns[temp] ) );
    4590           0 :     move16();
    4591             : 
    4592           0 :     return IVAS_ERR_OK;
    4593             : }
    4594             : 
    4595             : 
    4596             : /*-------------------------------------------------------------------*
    4597             :  * IVAS_REND_FeedInputAudio()
    4598             :  *
    4599             :  *
    4600             :  *-------------------------------------------------------------------*/
    4601             : 
    4602     1877090 : ivas_error IVAS_REND_FeedInputAudio_fx(
    4603             :     IVAS_REND_HANDLE hIvasRend,                    /* i/o: Renderer handle          */
    4604             :     const IVAS_REND_InputId inputId,               /* i  : ID of the input          */
    4605             :     const IVAS_REND_ReadOnlyAudioBuffer inputAudio /* i  : buffer with input audio  */
    4606             : )
    4607             : {
    4608             :     ivas_error error;
    4609             :     input_base *inputBase;
    4610             :     Word16 numInputChannels;
    4611             :     Word16 cldfb2tdShift;
    4612             : 
    4613             :     /* Validate function arguments */
    4614     1877090 :     test();
    4615     1877090 :     IF( hIvasRend == NULL || inputAudio.data_fx == NULL )
    4616             :     {
    4617           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4618             :     }
    4619             : 
    4620     1877090 :     test();
    4621     1877090 :     cldfb2tdShift = ( inputAudio.config.is_cldfb ) ? 1 : 0;
    4622             : 
    4623     1877090 :     IF( inputAudio.config.numSamplesPerChannel <= 0 || ( MAX_BUFFER_LENGTH_PER_CHANNEL < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 0 ) ||
    4624             :         ( ( shl( MAX_BUFFER_LENGTH_PER_CHANNEL, cldfb2tdShift ) ) < inputAudio.config.numSamplesPerChannel && inputAudio.config.is_cldfb == 1 ) )
    4625             :     {
    4626           0 :         return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Buffer size outside of supported range" );
    4627             :     }
    4628             : 
    4629     1877090 :     test();
    4630     1877090 :     IF( inputAudio.config.numChannels <= 0 || LT_16( MAX_INPUT_CHANNELS, inputAudio.config.numChannels ) )
    4631             :     {
    4632           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    4633             :     }
    4634             : 
    4635     1877090 :     test();
    4636     1877090 :     move32(); // move added for typecasting
    4637     1877090 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
    4638             :         NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) &&
    4639             :         NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) &&
    4640             :         NE_32( L_shr( L_mult0( inputAudio.config.numSamplesPerChannel, 1000 ), cldfb2tdShift ), (Word32) W_mult0_32_32( L_mult0( BINAURAL_RENDERING_FRAME_SIZE_MS, hIvasRend->num_subframes ), hIvasRend->sampleRateOut ) ) )
    4641             :     {
    4642           0 :         return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
    4643             :     }
    4644             : 
    4645     1877090 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    4646             :     {
    4647           0 :         return error;
    4648             :     }
    4649             : 
    4650     1877090 :     IF( NE_32( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ), IVAS_ERR_OK ) )
    4651             :     {
    4652           0 :         return error;
    4653             :     }
    4654     1877090 :     test();
    4655     1877090 :     test();
    4656     1877090 :     IF( ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) ) && EQ_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
    4657             :     {
    4658         150 :         numInputChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
    4659         150 :         move16();
    4660             :     }
    4661             : 
    4662     1877090 :     IF( NE_16( numInputChannels, inputAudio.config.numChannels ) )
    4663             :     {
    4664           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    4665             :     }
    4666             : 
    4667     1877090 :     inputBase->inputBuffer.config = inputAudio.config;
    4668             : 
    4669     1877090 :     MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
    4670             : 
    4671     1877090 :     inputBase->numNewSamplesPerChannel = shr( inputAudio.config.numSamplesPerChannel, cldfb2tdShift );
    4672     1877090 :     move32();
    4673             : 
    4674     1877090 :     return IVAS_ERR_OK;
    4675             : }
    4676             : 
    4677             : 
    4678             : /*-------------------------------------------------------------------*
    4679             :  * IVAS_REND_FeedInputObjectMetadata()
    4680             :  *
    4681             :  *
    4682             :  *-------------------------------------------------------------------*/
    4683             : 
    4684     1247500 : ivas_error IVAS_REND_FeedInputObjectMetadata(
    4685             :     IVAS_REND_HANDLE hIvasRend,            /* i/o: Renderer handle          */
    4686             :     const IVAS_REND_InputId inputId,       /* i  : ID of the input          */
    4687             :     const IVAS_ISM_METADATA objectPosition /* i  : object position struct   */
    4688             : )
    4689             : {
    4690             :     input_base *inputBase;
    4691             :     input_ism *inputIsm;
    4692             :     ivas_error error;
    4693             : 
    4694             :     /* Validate function arguments */
    4695     1247500 :     IF( hIvasRend == NULL )
    4696             :     {
    4697           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4698             :     }
    4699             : 
    4700     1247500 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    4701             :     {
    4702           0 :         return error;
    4703             :     }
    4704             : 
    4705     1247500 :     IF( NE_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
    4706             :     {
    4707             :         /* Object metadata should only be fed for object inputs */
    4708           0 :         return IVAS_ERR_METADATA_NOT_EXPECTED;
    4709             :     }
    4710             : 
    4711     1247500 :     inputIsm = (input_ism *) inputBase;
    4712     1247500 :     inputIsm->previousPos = inputIsm->currentPos;
    4713     1247500 :     inputIsm->currentPos = objectPosition;
    4714             : 
    4715     1247500 :     return IVAS_ERR_OK;
    4716             : }
    4717             : 
    4718             : 
    4719             : /*-------------------------------------------------------------------*
    4720             :  * IVAS_REND_FeedInputObjectMetadataToOMasa()
    4721             :  *
    4722             :  *
    4723             :  *-------------------------------------------------------------------*/
    4724         600 : ivas_error IVAS_REND_FeedInputObjectMetadataToOMasa(
    4725             :     IVAS_REND_HANDLE hIvasRend,            /* i/o: Renderer handle          */
    4726             :     const Word16 inputIndex,               /* i  : Index of the input       */
    4727             :     const IVAS_ISM_METADATA objectPosition /* i  : object position struct   */
    4728             : )
    4729             : {
    4730             :     /* Validate function arguments */
    4731         600 :     IF( hIvasRend == NULL )
    4732             :     {
    4733           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4734             :     }
    4735             : 
    4736             :     /* Set position to OMasa struct */
    4737         600 :     hIvasRend->inputsIsm->hOMasa->ism_azimuth_fx[inputIndex] = objectPosition.azimuth_fx;
    4738         600 :     move32();
    4739         600 :     hIvasRend->inputsIsm->hOMasa->ism_elevation_fx[inputIndex] = objectPosition.elevation_fx;
    4740         600 :     move32();
    4741             : 
    4742         600 :     return IVAS_ERR_OK;
    4743             : }
    4744             : 
    4745             : 
    4746             : /*-------------------------------------------------------------------*
    4747             :  * IVAS_REND_FeedInputMasaMetadata()
    4748             :  *
    4749             :  *
    4750             :  *-------------------------------------------------------------------*/
    4751             : 
    4752        7350 : ivas_error IVAS_REND_FeedInputMasaMetadata(
    4753             :     IVAS_REND_HANDLE hIvasRend,            /* i/o: Renderer handle      */
    4754             :     const IVAS_REND_InputId inputId,       /* i  : ID of the input      */
    4755             :     IVAS_MASA_METADATA_HANDLE masaMetadata /* i  : MASA metadata frame  */
    4756             : )
    4757             : {
    4758             :     ivas_error error;
    4759             :     input_base *inputBase;
    4760             :     input_masa *inputMasa;
    4761             : 
    4762             :     /* Validate function arguments */
    4763        7350 :     IF( hIvasRend == NULL )
    4764             :     {
    4765           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4766             :     }
    4767             : 
    4768        7350 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    4769             :     {
    4770           0 :         return error;
    4771             :     }
    4772             : 
    4773        7350 :     IF( NE_32( getAudioConfigType( inputBase->inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    4774             :     {
    4775             :         /* MASA metadata should only be fed for MASA inputs */
    4776           0 :         return IVAS_ERR_METADATA_NOT_EXPECTED;
    4777             :     }
    4778             : 
    4779        7350 :     inputMasa = (input_masa *) inputBase;
    4780        7350 :     inputMasa->masaMetadata = *masaMetadata;
    4781        7350 :     inputMasa->metadataHasBeenFed = true;
    4782        7350 :     move16();
    4783             : 
    4784        7350 :     return IVAS_ERR_OK;
    4785             : }
    4786             : 
    4787             : 
    4788             : /*-------------------------------------------------------------------*
    4789             :  * IVAS_REND_InitConfig()
    4790             :  *
    4791             :  *
    4792             :  *-------------------------------------------------------------------*/
    4793             : 
    4794         666 : ivas_error IVAS_REND_InitConfig(
    4795             :     IVAS_REND_HANDLE hIvasRend,       /* i/o: Renderer handle     */
    4796             :     const AUDIO_CONFIG outAudioConfig /* i  : output audioConfig  */
    4797             : )
    4798             : {
    4799             :     ivas_error error;
    4800             :     bool rendererConfigEnabled;
    4801             : 
    4802         666 :     rendererConfigEnabled = EQ_32( getAudioConfigType( outAudioConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
    4803             : 
    4804         666 :     IF( rendererConfigEnabled )
    4805             :     {
    4806         188 :         hIvasRend->rendererConfigEnabled = 1;
    4807         188 :         move16();
    4808             :     }
    4809             :     ELSE
    4810             :     {
    4811         478 :         hIvasRend->rendererConfigEnabled = 0;
    4812         478 :         move16();
    4813             :     }
    4814             : 
    4815         666 :     IF( rendererConfigEnabled )
    4816             :     {
    4817         188 :         IF( NE_32( ( error = ivas_render_config_open( &( hIvasRend->hRendererConfig ) ) ), IVAS_ERR_OK ) )
    4818             :         {
    4819           0 :             return error;
    4820             :         }
    4821         188 :         IF( NE_32( ( error = ivas_render_config_init_from_rom_fx( &hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
    4822             :         {
    4823           0 :             return error;
    4824             :         }
    4825             :     }
    4826             :     ELSE
    4827             :     {
    4828         478 :         hIvasRend->hRendererConfig = NULL;
    4829             :     }
    4830             : 
    4831         666 :     return IVAS_ERR_OK;
    4832             : }
    4833             : 
    4834             : 
    4835             : /*-------------------------------------------------------------------*
    4836             :  * IVAS_REND_GetRenderConfig()
    4837             :  *
    4838             :  *
    4839             :  *-------------------------------------------------------------------*/
    4840             : 
    4841           0 : Word16 IVAS_REND_GetRenderConfig(
    4842             :     IVAS_REND_HANDLE hIvasRend,            /* i/o: IVAS renderer handle        */
    4843             :     const IVAS_RENDER_CONFIG_HANDLE hRCout /* o  : Render configuration handle */
    4844             : )
    4845             : {
    4846             :     RENDER_CONFIG_HANDLE hRCin;
    4847             : 
    4848           0 :     test();
    4849           0 :     test();
    4850           0 :     IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL || hRCout == NULL )
    4851             :     {
    4852           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4853             :     }
    4854             : 
    4855           0 :     hRCin = hIvasRend->hRendererConfig;
    4856             : #ifndef FIX_587_DEFAULT_REVERB
    4857             :     hRCout->roomAcoustics.override = hRCin->roomAcoustics.override;
    4858             : #endif
    4859           0 :     hRCout->roomAcoustics.nBands = hRCin->roomAcoustics.nBands;
    4860           0 :     hRCout->roomAcoustics.acousticPreDelay_fx = hRCin->roomAcoustics.acousticPreDelay_fx;
    4861           0 :     hRCout->roomAcoustics.inputPreDelay_fx = hRCin->roomAcoustics.inputPreDelay_fx;
    4862           0 :     Copy( hRCin->directivity_fx, hRCout->directivity_fx, 3 * MAX_NUM_OBJECTS );
    4863             : #ifndef FIX_587_DEFAULT_REVERB
    4864             :     move16();
    4865             : #endif
    4866           0 :     move16();
    4867           0 :     move32();
    4868           0 :     move32();
    4869             : 
    4870           0 :     Copy32( hRCin->roomAcoustics.pFc_input_fx, hRCout->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
    4871           0 :     Copy32( hRCin->roomAcoustics.pAcoustic_rt60_fx, hRCout->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
    4872           0 :     Copy32( hRCin->roomAcoustics.pAcoustic_dsr_fx, hRCout->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
    4873             : 
    4874           0 :     hRCout->split_rend_config.splitRendBitRate = ISAR_MAX_SPLIT_REND_BITRATE;
    4875           0 :     hRCout->split_rend_config.dof = 3;
    4876           0 :     hRCout->split_rend_config.hq_mode = 0;
    4877           0 :     hRCout->split_rend_config.codec_delay_ms = 0;
    4878           0 :     hRCout->split_rend_config.isar_frame_size_ms = 20;
    4879           0 :     hRCout->split_rend_config.codec_frame_size_ms = 0; /* 0 means "use default for selected codec" */
    4880           0 :     hRCout->split_rend_config.codec = ISAR_SPLIT_REND_CODEC_DEFAULT;
    4881           0 :     hRCout->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB;
    4882           0 :     hRCout->split_rend_config.rendererSelection = hRCin->split_rend_config.rendererSelection;
    4883           0 :     hRCout->split_rend_config.lc3plus_highres = 0;
    4884             : 
    4885           0 :     hRCout->roomAcoustics.use_er = hRCin->roomAcoustics.use_er;
    4886           0 :     hRCout->roomAcoustics.lowComplexity = hRCin->roomAcoustics.lowComplexity;
    4887           0 :     move16();
    4888           0 :     move32();
    4889             : 
    4890           0 :     return IVAS_ERR_OK;
    4891             : }
    4892             : 
    4893             : 
    4894             : /*-------------------------------------------------------------------*
    4895             :  * IVAS_REND_FeedRenderConfig()
    4896             :  *
    4897             :  *
    4898             :  *-------------------------------------------------------------------*/
    4899             : 
    4900           0 : Word16 IVAS_REND_FeedRenderConfig(
    4901             :     IVAS_REND_HANDLE hIvasRend,                /* i/o: IVAS renderer handle        */
    4902             :     const IVAS_RENDER_CONFIG_DATA renderConfig /* i  : Render configuration struct */
    4903             : )
    4904             : {
    4905             :     RENDER_CONFIG_HANDLE hRenderConfig;
    4906             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    4907             :     UWord16 i;
    4908             :     input_ism *pIsmInput;
    4909             :     input_masa *pMasaInput;
    4910             :     input_mc *pMcInput;
    4911             :     input_sba *pSbaInput;
    4912             :     ivas_error error;
    4913             : #else
    4914             :     ivas_error error;
    4915             : #endif
    4916             : 
    4917           0 :     test();
    4918           0 :     IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
    4919             :     {
    4920           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4921             :     }
    4922           0 :     hRenderConfig = hIvasRend->hRendererConfig;
    4923             : 
    4924             : #ifndef FIX_587_DEFAULT_REVERB
    4925             :     hRenderConfig->roomAcoustics.override = renderConfig.roomAcoustics.override;
    4926             :     move16();
    4927             : #endif
    4928           0 :     hRenderConfig->roomAcoustics.nBands = renderConfig.roomAcoustics.nBands;
    4929           0 :     move16();
    4930           0 :     hRenderConfig->roomAcoustics.acousticPreDelay_fx = renderConfig.roomAcoustics.acousticPreDelay_fx;
    4931           0 :     move32();
    4932           0 :     hRenderConfig->roomAcoustics.inputPreDelay_fx = renderConfig.roomAcoustics.inputPreDelay_fx;
    4933           0 :     move32();
    4934           0 :     Copy32( renderConfig.roomAcoustics.pFc_input_fx, hRenderConfig->roomAcoustics.pFc_input_fx, CLDFB_NO_CHANNELS_MAX );
    4935           0 :     Copy32( renderConfig.roomAcoustics.pAcoustic_rt60_fx, hRenderConfig->roomAcoustics.pAcoustic_rt60_fx, CLDFB_NO_CHANNELS_MAX );
    4936           0 :     Copy32( renderConfig.roomAcoustics.pAcoustic_dsr_fx, hRenderConfig->roomAcoustics.pAcoustic_dsr_fx, CLDFB_NO_CHANNELS_MAX );
    4937           0 :     Copy( renderConfig.directivity_fx, hRenderConfig->directivity_fx, 3 * MAX_NUM_OBJECTS );
    4938             : 
    4939           0 :     hRenderConfig->roomAcoustics.use_er = 0;
    4940           0 :     move16();
    4941           0 :     IF( EQ_16( renderConfig.roomAcoustics.use_er, 1 ) )
    4942             :     {
    4943           0 :         hRenderConfig->roomAcoustics.use_er = renderConfig.roomAcoustics.use_er;
    4944           0 :         move16();
    4945           0 :         hRenderConfig->roomAcoustics.lowComplexity = renderConfig.roomAcoustics.lowComplexity;
    4946           0 :         move32();
    4947           0 :         hRenderConfig->roomAcoustics.dimensions = renderConfig.roomAcoustics.dimensions;
    4948           0 :         hRenderConfig->roomAcoustics.ListenerOrigin = renderConfig.roomAcoustics.ListenerOrigin;
    4949             : 
    4950           0 :         Copy32( renderConfig.roomAcoustics.AbsCoeff_fx, hRenderConfig->roomAcoustics.AbsCoeff_fx, IVAS_ROOM_ABS_COEFF );
    4951             :     }
    4952             : 
    4953             : #ifdef FIX_1053_REVERB_RECONFIGURATION
    4954             :     /* Re-initialize reverb instance if already available */
    4955             :     /* ISM inputs */
    4956           0 :     for ( i = 0, pIsmInput = hIvasRend->inputsIsm; i < RENDERER_MAX_ISM_INPUTS; ++i, ++pIsmInput )
    4957             :     {
    4958           0 :         IF( EQ_32( pIsmInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    4959             :         {
    4960             :             /* Skip inactive inputs */
    4961           0 :             continue;
    4962             :         }
    4963           0 :         if ( pIsmInput->hReverb != NULL )
    4964             :         {
    4965           0 :             IF( NE_32( ( error = ivas_reverb_open_fx( &pIsmInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    4966             :             {
    4967           0 :                 return error;
    4968             :             }
    4969             :         }
    4970           0 :         if ( pIsmInput->crendWrapper != NULL && pIsmInput->crendWrapper->hCrend[0] != NULL )
    4971             :         {
    4972           0 :             IF( NE_32( ( error = ivas_reverb_open_fx( &pIsmInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pIsmInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    4973             :             {
    4974           0 :                 return error;
    4975             :             }
    4976             :         }
    4977             :     }
    4978             : 
    4979             :     /* MASA inputs */
    4980           0 :     for ( i = 0, pMasaInput = hIvasRend->inputsMasa; i < RENDERER_MAX_MASA_INPUTS; ++i, ++pMasaInput )
    4981             :     {
    4982           0 :         IF( EQ_32( pMasaInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    4983             :         {
    4984             :             /* Skip inactive inputs */
    4985           0 :             continue;
    4986             :         }
    4987             : 
    4988           0 :         if ( pMasaInput->hMasaExtRend != NULL )
    4989             :         {
    4990           0 :             if ( pMasaInput->hMasaExtRend->hDiracDecBin[0] != NULL && pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb != NULL )
    4991             :             {
    4992           0 :                 ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb );
    4993             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    4994           0 :                 IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) )
    4995             : #else
    4996             :                 IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hDiracDecBin[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL ) ), IVAS_ERR_OK ) )
    4997             : #endif
    4998             :                 {
    4999           0 :                     return error;
    5000             :                 }
    5001             :             }
    5002           0 :             if ( pMasaInput->hMasaExtRend->hReverb != NULL )
    5003             :             {
    5004           0 :                 ivas_binaural_reverb_close_fx( &pMasaInput->hMasaExtRend->hReverb );
    5005             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
    5006           0 :                 IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL, NULL ) ), IVAS_ERR_OK ) )
    5007             : #else
    5008             :                 IF( NE_32( ( error = ivas_binaural_reverb_init( &pMasaInput->hMasaExtRend->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, pMasaInput->hMasaExtRend->hSpatParamRendCom->num_freq_bands, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRenderConfig->roomAcoustics ), *pMasaInput->base.ctx.pOutSampleRate, NULL, NULL ) ), IVAS_ERR_OK ) )
    5009             : #endif
    5010             :                 {
    5011           0 :                     return error;
    5012             :                 }
    5013             :             }
    5014             :         }
    5015             :     }
    5016             : 
    5017             :     /* Multi-channel inputs */
    5018           0 :     for ( i = 0, pMcInput = hIvasRend->inputsMc; i < RENDERER_MAX_MC_INPUTS; ++i, ++pMcInput )
    5019             :     {
    5020           0 :         IF( EQ_32( pMcInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    5021             :         {
    5022             :             /* Skip inactive inputs */
    5023           0 :             continue;
    5024             :         }
    5025             : 
    5026           0 :         if ( pMcInput->hReverb != NULL )
    5027             :         {
    5028           0 :             IF( NE_32( ( error = ivas_reverb_open_fx( &pMcInput->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    5029             :             {
    5030           0 :                 return error;
    5031             :             }
    5032             :         }
    5033           0 :         if ( pMcInput->crendWrapper != NULL && pMcInput->crendWrapper->hCrend[0] && pMcInput->crendWrapper->hCrend[0]->hReverb != NULL )
    5034             :         {
    5035           0 :             IF( NE_32( ( error = ivas_reverb_open_fx( &pMcInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pMcInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    5036             :             {
    5037           0 :                 return error;
    5038             :             }
    5039             :         }
    5040             :     }
    5041             : 
    5042             :     /* SBA inputs */
    5043           0 :     for ( i = 0, pSbaInput = hIvasRend->inputsSba; i < RENDERER_MAX_SBA_INPUTS; ++i, ++pSbaInput )
    5044             :     {
    5045           0 :         IF( EQ_32( pSbaInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    5046             :         {
    5047             :             /* Skip inactive inputs */
    5048           0 :             continue;
    5049             :         }
    5050           0 :         if ( pSbaInput->crendWrapper != NULL && pSbaInput->crendWrapper->hCrend[0] != NULL && pSbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
    5051             :         {
    5052           0 :             IF( NE_32( ( error = ivas_reverb_open_fx( &pSbaInput->crendWrapper->hCrend[0]->hReverb, hIvasRend->hHrtfs.hHrtfStatistics, hRenderConfig, *pSbaInput->base.ctx.pOutSampleRate ) ), IVAS_ERR_OK ) )
    5053             :             {
    5054           0 :                 return error;
    5055             :             }
    5056             :         }
    5057             :     }
    5058             : #endif
    5059             : 
    5060           0 :     hRenderConfig->split_rend_config = renderConfig.split_rend_config;
    5061             :     /* Overwrite any pose correction settings if 0 DOF (no pose correction) was selected */
    5062           0 :     IF( EQ_16( hRenderConfig->split_rend_config.dof, 0 ) )
    5063             :     {
    5064           0 :         hRenderConfig->split_rend_config.poseCorrectionMode = ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE;
    5065             :     }
    5066             : 
    5067           0 :     hRenderConfig->split_rend_config.codec = renderConfig.split_rend_config.codec;
    5068             : 
    5069           0 :     IF( ( error = isar_split_rend_validate_config( &hRenderConfig->split_rend_config, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0 ) ) != IVAS_ERR_OK )
    5070             :     {
    5071           0 :         return error;
    5072             :     }
    5073             : 
    5074             :     /* Must re-initialize split rendering config in case renderer config is updated after adding renderer inputs */
    5075             :     /* if its not initialized yet then no need to re-initialize, initialization will happen while adding inputs*/
    5076           0 :     IF( hIvasRend->splitRendEncBuffer.data_fx != NULL && hIvasRend->hRendererConfig != NULL )
    5077             :     {
    5078             :         Word16 cldfb_in_flag;
    5079           0 :         cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
    5080           0 :         IF( hIvasRend->splitRendWrapper != NULL )
    5081             :         {
    5082           0 :             ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
    5083           0 :             free( hIvasRend->splitRendWrapper );
    5084           0 :             hIvasRend->splitRendWrapper = NULL;
    5085             :         }
    5086             : 
    5087           0 :         IF( ( error = ivas_pre_rend_init( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer, &hIvasRend->hRendererConfig->split_rend_config, hIvasRend->headRotData, hIvasRend->sampleRateOut, hIvasRend->outputConfig, cldfb_in_flag, hIvasRend->num_subframes ) ) != IVAS_ERR_OK )
    5088             :         {
    5089           0 :             return error;
    5090             :         }
    5091             :     }
    5092             : 
    5093           0 :     return IVAS_ERR_OK;
    5094             : }
    5095             : 
    5096             : /*-------------------------------------------------------------------*
    5097             :  * IVAS_REND_SetHeadRotation()
    5098             :  *
    5099             :  *
    5100             :  *-------------------------------------------------------------------*/
    5101      288060 : ivas_error IVAS_REND_SetHeadRotation(
    5102             :     IVAS_REND_HANDLE hIvasRend,              /* i/o: Renderer handle                            */
    5103             :     const IVAS_QUATERNION headRot,           /* i  : head orientations for next rendering call  */
    5104             :     const IVAS_VECTOR3 Pos,                  /* i  : listener positions for next rendering call */
    5105             :     const ISAR_SPLIT_REND_ROT_AXIS rot_axis, /* i  : external control for rotation axis for split rendering                  */
    5106             :     const Word16 sf_idx                      /* i  : subframe index                             */
    5107             : )
    5108             : {
    5109             :     Word16 i;
    5110             :     IVAS_QUATERNION rotQuat;
    5111             :     ivas_error error;
    5112             : 
    5113             :     /* Validate function arguments */
    5114      288060 :     IF( hIvasRend == NULL )
    5115             :     {
    5116           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    5117             :     }
    5118             : 
    5119      288060 :     IF( NE_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
    5120             :     {
    5121             :         /* Head rotation can be set only with binaural output */
    5122           0 :         return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    5123             :     }
    5124             : 
    5125      288060 :     hIvasRend->headRotData.headRotEnabled = 1;
    5126      288060 :     move16();
    5127             : 
    5128             :     /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
    5129      576120 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    5130             :     {
    5131      288060 :         IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    5132             :         {
    5133       69615 :             IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, TRUE ) ), IVAS_ERR_OK ) )
    5134             :             {
    5135           0 :                 return error;
    5136             :             }
    5137             :         }
    5138             :     }
    5139             : 
    5140             :     /* check for Euler angle signaling */
    5141      288060 :     IF( EQ_32( headRot.w_fx, L_negate( 12582912 ) ) && EQ_16( headRot.q_fact, Q22 ) )
    5142             :     {
    5143           0 :         Euler2Quat_fx( deg2rad_fx( headRot.x_fx ), deg2rad_fx( headRot.y_fx ), deg2rad_fx( headRot.z_fx ), &rotQuat );
    5144           0 :         modify_Quat_q_fx( &rotQuat, &rotQuat, Q29 );
    5145             :     }
    5146             :     ELSE
    5147             :     {
    5148      288060 :         rotQuat = headRot;
    5149             :     }
    5150             : 
    5151      288060 :     Word32 updateRate_fx = 1677721600;                                // value is 200 in Q23
    5152      288060 :     rotQuat.w_fx = L_shl( rotQuat.w_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
    5153      288060 :     rotQuat.x_fx = L_shl( rotQuat.x_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
    5154      288060 :     rotQuat.y_fx = L_shl( rotQuat.y_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
    5155      288060 :     rotQuat.z_fx = L_shl( rotQuat.z_fx, sub( Q29, rotQuat.q_fact ) ); /* Q29 */
    5156             : 
    5157      288060 :     move32();
    5158      288060 :     move32();
    5159      288060 :     move32();
    5160      288060 :     move32();
    5161             : 
    5162      288060 :     hIvasRend->headRotData.hOrientationTracker->refRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) );          /* Q29 */
    5163      288060 :     hIvasRend->headRotData.hOrientationTracker->refRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) );          /* Q29 */
    5164      288060 :     hIvasRend->headRotData.hOrientationTracker->refRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) );          /* Q29 */
    5165      288060 :     hIvasRend->headRotData.hOrientationTracker->refRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->refRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->refRot.q_fact ) );          /* Q29 */
    5166      288060 :     hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.w_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
    5167      288060 :     hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.x_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
    5168      288060 :     hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.y_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
    5169      288060 :     hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx = L_shl( hIvasRend->headRotData.hOrientationTracker->absAvgRot.z_fx, sub( Q29, hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact ) ); /* Q29 */
    5170             : 
    5171      288060 :     move32();
    5172      288060 :     move32();
    5173      288060 :     move32();
    5174      288060 :     move32();
    5175      288060 :     move32();
    5176      288060 :     move32();
    5177      288060 :     move32();
    5178      288060 :     move32();
    5179             : 
    5180      288060 :     hIvasRend->headRotData.hOrientationTracker->refRot.q_fact = Q29;
    5181      288060 :     hIvasRend->headRotData.hOrientationTracker->absAvgRot.q_fact = Q29;
    5182      288060 :     move16();
    5183      288060 :     move16();
    5184      288060 :     rotQuat.q_fact = Q29;
    5185             : 
    5186      288060 :     move16();
    5187      288060 :     IF( NE_32( ( error = ivas_orient_trk_Process_fx( hIvasRend->headRotData.hOrientationTracker, rotQuat, updateRate_fx, &hIvasRend->headRotData.headPositions[sf_idx] ) ), IVAS_ERR_OK ) )
    5188             :     {
    5189           0 :         return error;
    5190             :     }
    5191             : 
    5192      288060 :     hIvasRend->headRotData.sr_pose_pred_axis = rot_axis;
    5193             : 
    5194      288060 :     hIvasRend->headRotData.Pos[sf_idx] = Pos;
    5195             : 
    5196      288060 :     return IVAS_ERR_OK;
    5197             : }
    5198             : 
    5199             : /*-------------------------------------------------------------------*
    5200             :  * IVAS_REND_DisableHeadRotation()
    5201             :  *
    5202             :  *
    5203             :  *-------------------------------------------------------------------*/
    5204      946116 : ivas_error IVAS_REND_DisableHeadRotation(
    5205             :     IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle  */
    5206             : )
    5207             : {
    5208             :     Word16 i;
    5209             :     ivas_error error;
    5210             : 
    5211             :     /* Validate function arguments */
    5212      946116 :     IF( hIvasRend == NULL )
    5213             :     {
    5214           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    5215             :     }
    5216             : 
    5217      946116 :     hIvasRend->headRotData.headRotEnabled = 0;
    5218      946116 :     move32();
    5219             : 
    5220             :     /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
    5221      946116 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
    5222             :     {
    5223      360048 :         FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    5224             :         {
    5225      180024 :             IF( NE_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    5226             :             {
    5227       43506 :                 IF( NE_32( ( error = initMcBinauralRendering( &hIvasRend->inputsMc[i], hIvasRend->inputsMc[i].base.inConfig, hIvasRend->outputConfig, hIvasRend->hRendererConfig, hIvasRend->hHrtfs.hSetOfHRTF, hIvasRend->hHrtfs.hHrtfStatistics, TRUE ) ), IVAS_ERR_OK ) )
    5228             :                 {
    5229             : 
    5230           0 :                     return error;
    5231             :                 }
    5232             :             }
    5233             :         }
    5234             :     }
    5235             : 
    5236      946116 :     return IVAS_ERR_OK;
    5237             : }
    5238             : 
    5239             : 
    5240             : /*-------------------------------------------------------------------*
    5241             :  * IVAS_REND_SetSplitRendBFI()
    5242             :  *
    5243             :  *
    5244             :  *-------------------------------------------------------------------*/
    5245             : 
    5246           0 : ivas_error IVAS_REND_SetSplitRendBFI(
    5247             :     IVAS_REND_HANDLE hIvasRend, /* i/o: Renderer handle      */
    5248             :     const Word16 bfi            /* i  : Bad Frame Indicator  */
    5249             : )
    5250             : {
    5251           0 :     hIvasRend->splitRendBFI = bfi;
    5252             : 
    5253           0 :     return IVAS_ERR_OK;
    5254             : }
    5255             : 
    5256             : 
    5257             : /*-------------------------------------------------------------------*
    5258             :  * IVAS_REND_SetOrientationTrackingMode()
    5259             :  *
    5260             :  *
    5261             :  *-------------------------------------------------------------------*/
    5262             : 
    5263         666 : ivas_error IVAS_REND_SetOrientationTrackingMode(
    5264             :     IVAS_REND_HANDLE hIvasRend,                       /* i/o: Renderer handle                */
    5265             :     const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i  : Head orientation tracking type */
    5266             : )
    5267             : {
    5268             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    5269         666 :     if ( hIvasRend->headRotData.headRotEnabled == 0 )
    5270             :     {
    5271         572 :         return IVAS_ERR_OK;
    5272             :     }
    5273             : #endif
    5274             : 
    5275          94 :     return ivas_orient_trk_SetTrackingType_fx( hIvasRend->headRotData.hOrientationTracker, orientation_tracking );
    5276             : }
    5277             : 
    5278             : 
    5279             : /*-------------------------------------------------------------------*
    5280             :  * IVAS_REND_SetReferenceRotation()
    5281             :  *
    5282             :  *
    5283             :  *-------------------------------------------------------------------*/
    5284             : 
    5285           0 : ivas_error IVAS_REND_SetReferenceRotation(
    5286             :     IVAS_REND_HANDLE hIvasRend,  /* i/o: Renderer handle        */
    5287             :     const IVAS_QUATERNION refRot /* i  : Reference rotation     */
    5288             : )
    5289             : {
    5290             :     ivas_error error;
    5291             : 
    5292             :     /* Validate function arguments */
    5293           0 :     IF( hIvasRend == NULL )
    5294             :     {
    5295           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    5296             :     }
    5297             : 
    5298           0 :     error = ivas_orient_trk_SetReferenceRotation_fx( hIvasRend->headRotData.hOrientationTracker, refRot );
    5299             : 
    5300           0 :     IF( NE_32( error, IVAS_ERR_OK ) )
    5301             :     {
    5302             : 
    5303           0 :         return error;
    5304             :     }
    5305           0 :     return IVAS_ERR_OK;
    5306             : }
    5307             : 
    5308             : 
    5309             : /*-------------------------------------------------------------------*
    5310             :  * IVAS_REND_GetMainOrientation()
    5311             :  *
    5312             :  *
    5313             :  *-------------------------------------------------------------------*/
    5314             : 
    5315             : 
    5316             : /*-------------------------------------------------------------------*
    5317             :  * IVAS_REND_GetTrackedRotation()
    5318             :  *
    5319             :  *
    5320             :  *-------------------------------------------------------------------*/
    5321             : 
    5322             : 
    5323             : /*---------------------------------------------------------------------*
    5324             :  * IVAS_REND_SetReferenceVector( )
    5325             :  *
    5326             :  * Sets a reference vector spanning from listenerPos to refPos. Only
    5327             :  * available in OTR_TRACKING_REF_VEC and OTR_TRACKING_REF_VEC_LEV modes.
    5328             :  *---------------------------------------------------------------------*/
    5329             : 
    5330           0 : ivas_error IVAS_REND_SetReferenceVector(
    5331             :     IVAS_REND_HANDLE hIvasRend,     /* i/o: Renderer handle             */
    5332             :     const IVAS_VECTOR3 listenerPos, /* i  : Listener position           */
    5333             :     const IVAS_VECTOR3 refPos       /* i  : Reference position          */
    5334             : )
    5335             : {
    5336           0 :     test();
    5337           0 :     IF( hIvasRend == NULL || hIvasRend->headRotData.hOrientationTracker == NULL )
    5338             :     {
    5339           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    5340             :     }
    5341             : 
    5342           0 :     return ivas_orient_trk_SetReferenceVector_fx( hIvasRend->headRotData.hOrientationTracker, listenerPos, refPos );
    5343             : }
    5344             : 
    5345             : 
    5346             : /*---------------------------------------------------------------------*
    5347             :  * IVAS_REND_SetExternalOrientation()
    5348             :  *
    5349             :  *
    5350             :  *---------------------------------------------------------------------*/
    5351             : 
    5352           0 : ivas_error IVAS_REND_SetExternalOrientation(
    5353             :     IVAS_REND_HANDLE hIvasRend,          /* i/o: Renderer handle                                                         */
    5354             :     IVAS_QUATERNION *orientation,        /* i  : external orientation data                                               */
    5355             :     Word8 enableHeadRotation,            /* i  : flag to enable head rotation for this frame                             */
    5356             :     Word8 enableExternalOrientation,     /* i  : flag to enable external orientation for this frame                      */
    5357             :     Word8 enableRotationInterpolation,   /* i  : flag to interpolate rotations from current and previous frames          */
    5358             :     Word16 numFramesToTargetOrientation, /* i  : number of frames until target orientation is reached                    */
    5359             :     const Word16 sf_idx                  /* i  : subframe index                                                          */
    5360             : )
    5361             : {
    5362             :     /* Validate function arguments */
    5363           0 :     test();
    5364           0 :     IF( hIvasRend == NULL || hIvasRend->hExternalOrientationData == NULL )
    5365             :     {
    5366           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    5367             :     }
    5368             : 
    5369           0 :     IF( orientation == NULL )
    5370             :     {
    5371           0 :         hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = 0;
    5372           0 :         move16();
    5373             :     }
    5374             :     ELSE
    5375             :     {
    5376           0 :         QuaternionInverse_fx( *orientation, &hIvasRend->hExternalOrientationData->Quaternions[sf_idx] );
    5377             : 
    5378           0 :         hIvasRend->hExternalOrientationData->enableHeadRotation[sf_idx] = enableHeadRotation;
    5379           0 :         hIvasRend->hExternalOrientationData->enableExternalOrientation[sf_idx] = enableExternalOrientation;
    5380           0 :         hIvasRend->hExternalOrientationData->enableRotationInterpolation[sf_idx] = enableRotationInterpolation;
    5381           0 :         hIvasRend->hExternalOrientationData->numFramesToTargetOrientation[sf_idx] = numFramesToTargetOrientation;
    5382           0 :         move16();
    5383           0 :         move16();
    5384           0 :         move16();
    5385           0 :         move16();
    5386             :     }
    5387             : 
    5388           0 :     return IVAS_ERR_OK;
    5389             : }
    5390             : 
    5391             : 
    5392             : /*---------------------------------------------------------------------*
    5393             :  * IVAS_REND_CombineHeadAndExternalOrientation()
    5394             :  *
    5395             :  *
    5396             :  *---------------------------------------------------------------------*/
    5397             : 
    5398     1126140 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
    5399             :     IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle      */
    5400             : )
    5401             : {
    5402     1126140 :     IF( hIvasRend == NULL )
    5403             :     {
    5404           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    5405             :     }
    5406     1126140 :     ivas_error error = combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
    5407             : 
    5408     1126140 :     return error;
    5409             : }
    5410             : 
    5411             : 
    5412             : /*---------------------------------------------------------------------*
    5413             :  * IVAS_REND_GetCombinedOrientation()
    5414             :  *
    5415             :  *
    5416             :  *---------------------------------------------------------------------*/
    5417             : 
    5418             : 
    5419             : /*-------------------------------------------------------------------*
    5420             :  * Local functions
    5421             :  *-------------------------------------------------------------------*/
    5422             : /* Take one channel from input buffer and copy it to each channel
    5423             :        in output buffer, with different gain applied per output channel.
    5424             :        This function takes 2 gain vectors - one for the beginning and one
    5425             :        for the end of the buffer. Gain values are lineraly interpolated
    5426             :        for all samples in between. */
    5427             : /* Take one channel from input buffer and copy it to each channel
    5428             :        in output buffer, with different gain applied per output channel.
    5429             :        This function takes 2 gain vectors - one for the beginning and one
    5430             :        for the end of the buffer. Gain values are lineraly interpolated
    5431             :        for all samples in between. */
    5432     5282295 : static void renderBufferChannelLerp_fx(
    5433             :     const IVAS_REND_AudioBuffer inAudio,
    5434             :     const Word32 inChannelIdx,
    5435             :     const Word32 *const gainsCurrent, /* Q31 */
    5436             :     const Word32 *const gainsPrev,    /* Q31 */
    5437             :     IVAS_REND_AudioBuffer outAudio )
    5438             : {
    5439             :     const Word32 *inSmpl;
    5440             :     Word32 *outSmpl;
    5441             :     Word32 fadeIn;
    5442             :     Word32 fadeOut;
    5443             :     Word32 i;
    5444             :     const Word32 *lastInSmpl;
    5445             :     Word16 outChnlIdx;
    5446             :     Word32 currentGain;  /* Q31 */
    5447             :     Word32 previousGain; /* Q31 */
    5448             : 
    5449             :     /* Pointer to behind last input sample */
    5450     5282295 :     lastInSmpl = getSmplPtr_fx( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
    5451             : 
    5452    51204875 :     FOR( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
    5453             :     {
    5454    45922580 :         currentGain = gainsCurrent[outChnlIdx];
    5455    45922580 :         move32();
    5456    45922580 :         if ( gainsPrev == NULL )
    5457             :         {
    5458    42525392 :             previousGain = 0;
    5459    42525392 :             move32();
    5460             :         }
    5461             :         else
    5462             :         {
    5463     3397188 :             previousGain = gainsPrev[outChnlIdx];
    5464     3397188 :             move32();
    5465             :         }
    5466             : 
    5467             :         /* Process current output channel only if applying non-zero gains */
    5468    45922580 :         test();
    5469    45922580 :         test();
    5470    45922580 :         IF( GT_32( L_abs( currentGain ), EPSILON_FX ) || ( gainsPrev != NULL && GT_32( L_abs( previousGain ), EPSILON_FX ) ) )
    5471             :         {
    5472             :             /* Reset input pointer to the beginning of input channel */
    5473    27135745 :             inSmpl = getSmplPtr_fx( inAudio, inChannelIdx, 0 );
    5474             : 
    5475             :             /* Set output pointer to first output channel sample */
    5476    27135745 :             outSmpl = getSmplPtr_fx( outAudio, outChnlIdx, 0 );
    5477             : 
    5478    27135745 :             test();
    5479    27135745 :             IF( gainsPrev == NULL || LE_32( L_abs( L_sub( L_shr( previousGain, 1 ), L_shr( currentGain, 1 ) ) ), EPSILON_FX ) )
    5480             :             {
    5481             :                 /* If no interpolation from previous frame, apply current gain */
    5482             :                 DO
    5483             :                 {
    5484 10024117680 :                     *outSmpl = L_add( Mpy_32_32( currentGain, ( *inSmpl ) ), *outSmpl );
    5485 10024117680 :                     move32();
    5486 10024117680 :                     ++outSmpl;
    5487 10024117680 :                     ++inSmpl;
    5488             :                 }
    5489 10024117680 :                 WHILE( inSmpl != lastInSmpl );
    5490             :             }
    5491             :             ELSE
    5492             :             {
    5493     1996136 :                 i = 0;
    5494     1996136 :                 Word32 tmp = Q31_BY_SUB_FRAME_240;
    5495     1996136 :                 Word32 tmp1 = 239; /* L_SUBFRAME_48k - 1 */
    5496     1996136 :                 move32();
    5497     1996136 :                 move32();
    5498     1996136 :                 move32();
    5499     1996136 :                 SWITCH( outAudio.config.numSamplesPerChannel )
    5500             :                 {
    5501     1051037 :                     case NUM_SAMPLES_960:
    5502     1051037 :                         tmp = Q31_BY_NUM_SAMPLES_960;
    5503     1051037 :                         tmp1 = 959; /* NUM_SAMPLES_960 - 1 */
    5504     1051037 :                         move32();
    5505     1051037 :                         move32();
    5506     1051037 :                         BREAK;
    5507           0 :                     case NUM_SAMPLES_720:
    5508           0 :                         tmp = Q31_BY_NUM_SAMPLES_720;
    5509           0 :                         tmp1 = 719; /* NUM_SAMPLES_720 - 1 */
    5510           0 :                         move32();
    5511           0 :                         move32();
    5512           0 :                         BREAK;
    5513           0 :                     case NUM_SAMPLES_640:
    5514           0 :                         tmp = Q31_BY_NUM_SAMPLES_640;
    5515           0 :                         tmp1 = 639; /* NUM_SAMPLES_640 - 1 */
    5516           0 :                         move32();
    5517           0 :                         move32();
    5518           0 :                         BREAK;
    5519           0 :                     case NUM_SAMPLES_320:
    5520           0 :                         tmp = Q31_BY_NUM_SAMPLES_320;
    5521           0 :                         tmp1 = 319; /* NUM_SAMPLES_320 - 1 */
    5522           0 :                         move32();
    5523           0 :                         move32();
    5524           0 :                         BREAK;
    5525           0 :                     case L_SUBFRAME_32k:
    5526           0 :                         tmp = Q31_BY_NUM_SAMPLES_160;
    5527           0 :                         tmp1 = 159; /* NUM_SAMPLES_160 - 1 */
    5528           0 :                         move32();
    5529           0 :                         move32();
    5530           0 :                         BREAK;
    5531      945099 :                     case L_SUBFRAME_48k:
    5532      945099 :                         tmp = Q31_BY_SUB_FRAME_240;
    5533      945099 :                         tmp1 = 239; /* L_SUBFRAME_48k - 1 */
    5534      945099 :                         move32();
    5535      945099 :                         move32();
    5536      945099 :                         BREAK;
    5537           0 :                     case L_SUBFRAME_16k:
    5538           0 :                         tmp = Q31_BY_SUB_FRAME_80;
    5539           0 :                         tmp1 = 79; /* L_SUBFRAME_16k - 1 */
    5540           0 :                         move32();
    5541           0 :                         move32();
    5542           0 :                         BREAK;
    5543           0 :                     case L_SUBFRAME_8k:
    5544           0 :                         tmp = Q31_BY_SUB_FRAME_40;
    5545           0 :                         tmp1 = 39; /* L_SUBFRAME_8k - 1 */
    5546           0 :                         move32();
    5547           0 :                         move32();
    5548           0 :                         BREAK;
    5549           0 :                     default:
    5550           0 :                         BREAK;
    5551             :                 }
    5552             :                 /* Otherwise use weighted average between previous and current gain */
    5553  1233823144 :                 DO
    5554             :                 {
    5555  1235819280 :                     IF( EQ_32( i, tmp1 ) )
    5556             :                     {
    5557     1996136 :                         fadeIn = ONE_IN_Q31;
    5558     1996136 :                         move32();
    5559             :                     }
    5560             :                     ELSE
    5561             :                     {
    5562  1233823144 :                         fadeIn = UL_Mpy_32_32( i, tmp );
    5563             :                     }
    5564  1235819280 :                     fadeOut = L_sub( ONE_IN_Q31, fadeIn );
    5565             : 
    5566  1235819280 :                     *outSmpl = L_add( Mpy_32_32( L_add( Mpy_32_32( fadeIn, currentGain ), Mpy_32_32( fadeOut, previousGain ) ), ( *inSmpl ) ), *outSmpl );
    5567  1235819280 :                     move32();
    5568  1235819280 :                     ++outSmpl;
    5569  1235819280 :                     ++inSmpl;
    5570  1235819280 :                     ++i;
    5571             :                 }
    5572  1235819280 :                 WHILE( inSmpl != lastInSmpl );
    5573             :             }
    5574             :         }
    5575             :     }
    5576             : 
    5577     5282295 :     return;
    5578             : }
    5579             : 
    5580             : 
    5581             : /* Take one channel from input buffer and copy it to each channel
    5582             :        in output buffer, with different gain applied per output channel */
    5583     4334795 : static void renderBufferChannel_fx(
    5584             :     const IVAS_REND_AudioBuffer inAudio,
    5585             :     const Word32 inChannelIdx,
    5586             :     const Word32 *const outputGains, /* Q31 */
    5587             :     IVAS_REND_AudioBuffer outAudio )
    5588             : {
    5589     4334795 :     renderBufferChannelLerp_fx( inAudio, inChannelIdx, outputGains, NULL, outAudio );
    5590             : 
    5591     4334795 :     return;
    5592             : }
    5593             : 
    5594       70522 : static ivas_error chooseCrossfade_fx(
    5595             :     const IVAS_REND_HeadRotData *headRotData,
    5596             :     const Word32 **pCrossfade /* Q31 */ )
    5597             : {
    5598       70522 :     *pCrossfade = headRotData->crossfade_fx;
    5599             : 
    5600       70522 :     return IVAS_ERR_OK;
    5601             : }
    5602             : 
    5603             : 
    5604       25504 : static ivas_error rotateFrameMc_fx(
    5605             :     IVAS_REND_AudioBuffer inAudio,                               /* i  : Input Audio buffer               */
    5606             :     AUDIO_CONFIG inConfig,                                       /* i  : Input Audio config               */
    5607             :     const LSSETUP_CUSTOM_STRUCT *pInCustomLs,                    /* i  : Input Custom LS setup            */
    5608             :     const IVAS_REND_HeadRotData *headRotData,                    /* i  : Head rotation data               */
    5609             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i  : Combined head and external orientations */
    5610             :     rotation_gains_Word32 gains_prev,                            /* i/o: Previous frame rotation gains    */
    5611             :     const EFAP_HANDLE hEFAPdata,                                 /* i  : EFAP structure                   */
    5612             :     IVAS_REND_AudioBuffer outAudio                               /* o  : Output Audio buffer              */
    5613             : )
    5614             : {
    5615             :     Word16 i;
    5616             :     Word16 j;
    5617             :     const Word32 *crossfade; /* Q31 */
    5618             :     Word16 num_subframes;
    5619             :     Word16 subframe_idx, subframe_len;
    5620             :     Word32 azimuth_fx, elevation_fx; /* Q22 */
    5621             :     Word16 is_planar_setup, lfe_idx;
    5622             :     Word16 nchan;
    5623             :     Word16 ch_in, ch_out;
    5624             :     Word16 ch_in_woLFE, ch_out_woLFE;
    5625       25504 :     Word32 *readPtr, *writePtr = NULL;
    5626             :     const Word32 *ls_azimuth, *ls_elevation;
    5627             :     rotation_matrix_fx Rmat_fx;
    5628             :     rotation_gains_Word32 gains;
    5629             :     Word32 tmp_gains[MAX_INPUT_CHANNELS]; /* Q30 */
    5630             :     ivas_error error;
    5631             : 
    5632       25504 :     push_wmops( "rotateFrameMc_fx" );
    5633       25504 :     IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
    5634             :     {
    5635           0 :         return error;
    5636             :     }
    5637       25504 :     IF( ( hCombinedOrientationData != NULL ) )
    5638             :     {
    5639       25504 :         num_subframes = ( *hCombinedOrientationData )->num_subframes;
    5640             :     }
    5641             :     ELSE
    5642             :     {
    5643           0 :         num_subframes = MAX_PARAM_SPATIAL_SUBFRAMES;
    5644             :     }
    5645       25504 :     move16();
    5646             : 
    5647       25504 :     IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    5648             :     {
    5649       12500 :         IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ), IVAS_ERR_OK ) )
    5650             :         {
    5651           0 :             return error;
    5652             :         }
    5653             :     }
    5654             :     ELSE
    5655             :     {
    5656       13004 :         nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe );
    5657             :     }
    5658             : 
    5659       25504 :     IF( NE_32( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ), IVAS_ERR_OK ) )
    5660             :     {
    5661           0 :         return error;
    5662             :     }
    5663             : 
    5664             :     /* initialize gains to passthrough */
    5665      319068 :     FOR( ch_in = 0; ch_in < nchan; ch_in++ )
    5666             :     {
    5667      293564 :         set32_fx( gains[ch_in], 0, nchan );
    5668      293564 :         gains[ch_in][ch_in] = ONE_IN_Q30;
    5669      293564 :         move32();
    5670             :     }
    5671             : 
    5672             :     /* subframe loop */
    5673             :     Word16 tmp_e;
    5674       25504 :     Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e );
    5675       25504 :     tmp = shr( tmp, negate( add( 1, tmp_e ) ) );
    5676       25504 :     subframe_len = tmp;
    5677       25504 :     move16();
    5678             : 
    5679       66314 :     FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
    5680             :     {
    5681      163240 :         FOR( i = 0; i < 3; i++ )
    5682             :         {
    5683      122430 :             IF( hCombinedOrientationData != NULL )
    5684             :             {
    5685      489720 :                 FOR( j = 0; j < 3; j++ )
    5686             :                 {
    5687      367290 :                     Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
    5688      367290 :                     move32();
    5689             :                 }
    5690             :             }
    5691             :             ELSE
    5692             :             {
    5693             :                 /* Set to identity */
    5694           0 :                 set32_fx( Rmat_fx[i], 0, 3 );
    5695           0 :                 Rmat_fx[i][i] = ONE_IN_Q30;
    5696           0 :                 move32();
    5697             :             }
    5698             :         }
    5699             : 
    5700      510570 :         FOR( ch_in = 0; ch_in < nchan; ch_in++ )
    5701             :         {
    5702             :             /* skip LFE */
    5703      469760 :             IF( EQ_16( ch_in, lfe_idx ) )
    5704             :             {
    5705       20000 :                 CONTINUE;
    5706             :             }
    5707             : 
    5708             :             /* input channel index without LFE */
    5709      449760 :             test();
    5710      449760 :             IF( ( lfe_idx > 0 ) && ( GE_16( ch_in, lfe_idx ) ) )
    5711             :             {
    5712       85600 :                 ch_in_woLFE = sub( ch_in, 1 );
    5713             :             }
    5714             :             ELSE
    5715             :             {
    5716      364160 :                 ch_in_woLFE = ch_in;
    5717      364160 :                 move16();
    5718             :             }
    5719             : 
    5720             : 
    5721             :             /* gains for current subframe rotation */
    5722      449760 :             rotateAziEle_fixed( (Word16) L_shr( ls_azimuth[ch_in_woLFE], 22 ), (Word16) L_shr( ls_elevation[ch_in_woLFE], 22 ), &azimuth_fx, &elevation_fx, Rmat_fx, is_planar_setup );
    5723             : 
    5724      449760 :             test();
    5725      449760 :             test();
    5726      449760 :             IF( hEFAPdata != NULL && ( NE_32( ls_azimuth[ch_in_woLFE], azimuth_fx ) || NE_32( ls_elevation[ch_in_woLFE], elevation_fx ) ) )
    5727             :             {
    5728      144730 :                 efap_determine_gains_fx( hEFAPdata, tmp_gains, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
    5729             : 
    5730     1444790 :                 FOR( ch_out = 0; ch_out < nchan; ch_out++ )
    5731             :                 {
    5732             :                     /* skip LFE */
    5733     1300060 :                     IF( EQ_16( ch_out, lfe_idx ) )
    5734             :                     {
    5735      144730 :                         CONTINUE;
    5736             :                     }
    5737             : 
    5738             :                     /* output channel index without LFE */
    5739     1155330 :                     test();
    5740     1155330 :                     IF( ( lfe_idx > 0 ) && ( GE_16( ch_out, lfe_idx ) ) )
    5741             :                     {
    5742      721140 :                         ch_out_woLFE = sub( ch_out, 1 );
    5743             :                     }
    5744             :                     ELSE
    5745             :                     {
    5746      434190 :                         ch_out_woLFE = ch_out;
    5747      434190 :                         move16();
    5748             :                     }
    5749             : 
    5750     1155330 :                     gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
    5751     1155330 :                     move32();
    5752             :                 }
    5753             :             }
    5754             :         }
    5755             : 
    5756             :         /* apply panning gains by mtx multiplication */
    5757      510570 :         FOR( ch_out = 0; ch_out < nchan; ch_out++ )
    5758             :         {
    5759     6541120 :             FOR( ch_in = 0; ch_in < nchan; ch_in++ )
    5760             :             {
    5761     6071360 :                 writePtr = getSmplPtr_fx( outAudio, ch_out, imult1616( subframe_idx, subframe_len ) ); /* Qx */
    5762     6071360 :                 readPtr = getSmplPtr_fx( inAudio, ch_in, imult1616( subframe_idx, subframe_len ) );    /* Qx */
    5763             :                 /* crossfade with previous rotation gains */
    5764  1463197760 :                 FOR( i = 0; i < subframe_len; i++ )
    5765             :                 {
    5766  1457126400 :                     *writePtr =
    5767  1457126400 :                         L_add( *writePtr, L_add( Mpy_32_32( ( *readPtr ), Mpy_32_32( L_sub( ONE_IN_Q31, crossfade[i] ), gains_prev[ch_in][ch_out] ) ),
    5768  1457126400 :                                                  Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); /* Qx - 1 */
    5769  1457126400 :                     move32();
    5770  1457126400 :                     readPtr++;
    5771  1457126400 :                     writePtr++;
    5772             :                 }
    5773             :             }
    5774             :         }
    5775             : 
    5776             :         /* move gains to gains_prev */
    5777      510570 :         FOR( i = 0; i < nchan; i++ )
    5778             :         {
    5779      469760 :             MVR2R_WORD32( gains[i], gains_prev[i], nchan );
    5780             :         }
    5781             :     }
    5782             : 
    5783       25504 :     pop_wmops();
    5784       25504 :     return IVAS_ERR_OK;
    5785             : }
    5786             : 
    5787             : 
    5788       45018 : static ivas_error rotateFrameSba_fx(
    5789             :     IVAS_REND_AudioBuffer inAudio,                               /* i  : Input Audio buffer                      */
    5790             :     const AUDIO_CONFIG inConfig,                                 /* i  : Input Audio config                      */
    5791             :     const IVAS_REND_HeadRotData *headRotData,                    /* i  : Head rotation data                      */
    5792             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i  : Combined head and external orientations */
    5793             :     Word16 gains_prev[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS],   /* i/o: Previous frame rotation gains       Q14 */
    5794             :     IVAS_REND_AudioBuffer outAudio                               /* o  : Output Audio buffer                     */
    5795             : )
    5796             : {
    5797             :     Word16 i, l, n, m;
    5798             :     Word16 m1, m2;
    5799             :     Word16 shd_rot_max_order;
    5800             :     const Word32 *crossfade; /* Q31 */
    5801             :     Word16 num_subframes;
    5802             :     Word16 subframe_idx, subframe_len;
    5803             :     Word32 *writePtr;
    5804             :     Word32 tmpRot[2 * HEADROT_ORDER + 1];
    5805             :     Word16 gains[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; /* Q14 */
    5806             :     Word32 temp;
    5807             :     Word32 Rmat[3][3]; /* Q30 */
    5808             :     ivas_error error;
    5809             :     Word16 idx, exp;
    5810             :     Word32 cf, oneminuscf; /* Q31 */
    5811             :     Word32 val;
    5812             : 
    5813       45018 :     push_wmops( "rotateFrameSba" );
    5814             : 
    5815       45018 :     IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
    5816             :     {
    5817           0 :         return error;
    5818             :     }
    5819       45018 :     num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
    5820       45018 :     move16();
    5821             : 
    5822       45018 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( inConfig, &shd_rot_max_order ) ), IVAS_ERR_OK ) )
    5823             :     {
    5824           0 :         return error;
    5825             :     }
    5826             : 
    5827             :     // subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
    5828       45018 :     subframe_len = BASOP_Util_Divide1616_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &exp );
    5829       45018 :     subframe_len = shr( subframe_len, sub( 15, exp ) );
    5830      117063 :     FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
    5831             :     {
    5832             :         /* initialize rotation matrices with zeros */
    5833     1224765 :         FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
    5834             :         {
    5835     1152720 :             set16_fx( gains[i], 0, HEADROT_SHMAT_DIM );
    5836             :         }
    5837             : 
    5838      288180 :         FOR( i = 0; i < 3; i++ )
    5839             :         {
    5840      216135 :             IF( hCombinedOrientationData != NULL )
    5841             :             {
    5842      864540 :                 FOR( l = 0; l < 3; l++ )
    5843             :                 {
    5844      648405 :                     Rmat[i][l] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][l]; /* Q30 */
    5845      648405 :                     move32();
    5846             :                 }
    5847             :             }
    5848             :             ELSE
    5849             :             {
    5850             :                 /* Set to identity */
    5851           0 :                 set32_fx( Rmat[i], 0, 3 );
    5852           0 :                 Rmat[i][i] = ONE_IN_Q30;
    5853           0 :                 move32();
    5854             :             }
    5855             :         }
    5856             :         /* calculate ambisonics rotation matrices for the previous and current frames */
    5857       72045 :         SHrotmatgen_fx( gains, Rmat, shd_rot_max_order );
    5858             : 
    5859             : #ifdef DEBUGGING
    5860             :         dbgwrite_txt( (const float *) ( gains[0] ), HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_code_gains.txt", NULL );
    5861             :         dbgwrite_txt( (const float *) ( Rmat[0] ), 3 * 3, "Fixed_code_Rmat.txt", NULL );
    5862             : #endif
    5863    17362845 :         FOR( i = 0; i < subframe_len; i++ )
    5864             :         {
    5865    17290800 :             idx = add( imult1616( subframe_idx, subframe_len ), i );
    5866             :             // cf = crossfade[i];
    5867    17290800 :             cf = crossfade[i];
    5868    17290800 :             move32();
    5869    17290800 :             oneminuscf = L_sub( ONE_IN_Q31, cf );
    5870             :             /*    As the rotation matrix becomes block diagonal in a SH basis, we can*/
    5871             :             /*      apply each angular-momentum block individually to save complexity. */
    5872             : 
    5873             :             /*    loop over l blocks */
    5874    17290800 :             m1 = 1;
    5875    17290800 :             m2 = 4;
    5876    17290800 :             move16();
    5877    17290800 :             move16();
    5878    51872400 :             FOR( l = 1; l <= shd_rot_max_order; l++ )
    5879             :             {
    5880             :                 /* compute mtx-vector product for this l  */
    5881   184435200 :                 FOR( n = m1; n < m2; n++ )
    5882             :                 {
    5883   149853600 :                     tmpRot[n - m1] = 0;
    5884   149853600 :                     move32();
    5885   876067200 :                     FOR( m = m1; m < m2; m++ )
    5886             :                     {
    5887   726213600 :                         val = inAudio.data_fx[m * inAudio.config.numSamplesPerChannel + idx];
    5888             :                         /* crossfade with previous rotation gains */
    5889   726213600 :                         temp = Mpy_32_32( L_add( Mpy_32_16_r( cf, gains[n][m] ), ( Mpy_32_16_r( oneminuscf, gains_prev[n][m] ) ) ), val );
    5890   726213600 :                         tmpRot[n - m1] = L_add( L_shl( temp, 1 ), tmpRot[n - m1] );
    5891   726213600 :                         move32();
    5892   726213600 :                         move32();
    5893             :                     }
    5894             :                 }
    5895             :                 /* write back the result */
    5896   184435200 :                 FOR( n = m1; n < m2; n++ )
    5897             :                 {
    5898   149853600 :                     writePtr = getSmplPtr_fx( outAudio, n, idx );
    5899   149853600 :                     ( *writePtr ) = tmpRot[n - m1];
    5900   149853600 :                     move32();
    5901             :                 }
    5902    34581600 :                 m1 = m2;
    5903    34581600 :                 move16();
    5904    34581600 :                 m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
    5905             :             }
    5906             :         }
    5907             : 
    5908             :         /* move SHrotmat to SHrotmat_prev */
    5909     1224765 :         FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
    5910             :         {
    5911     1152720 :             Copy( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
    5912             :         }
    5913             :     }
    5914       45018 :     pop_wmops();
    5915             : 
    5916       45018 :     return IVAS_ERR_OK;
    5917             : }
    5918             : 
    5919             : 
    5920      150000 : static ivas_error renderIsmToBinaural(
    5921             :     input_ism *ismInput,
    5922             :     IVAS_REND_AudioBuffer outAudio )
    5923             : {
    5924             :     Word32 tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    5925             :     ivas_error error;
    5926             :     Word16 ism_md_subframe_update_ext;
    5927             :     Word16 i;
    5928      150000 :     Word16 exp = *outAudio.pq_fact;
    5929      150000 :     move16();
    5930             : 
    5931      150000 :     push_wmops( "renderIsmToBinaural" );
    5932             :     /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
    5933      150000 :     ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, 429496730 /* 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
    5934      150000 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer );
    5935             : 
    5936     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5937             :     {
    5938     2400000 :         Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    5939             :     }
    5940             : 
    5941      150000 :     IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext,
    5942             :                                                            *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer, &exp ) ),
    5943             :                IVAS_ERR_OK ) )
    5944             :     {
    5945           0 :         return error;
    5946             :     }
    5947             : 
    5948     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5949             :     {
    5950     2400000 :         Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    5951             :     }
    5952             : 
    5953      150000 :     IF( ismInput->hReverb != NULL )
    5954             :     {
    5955           0 :         FOR( i = 0; i < outAudio.config.numChannels; i++ )
    5956             :         {
    5957           0 :             FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
    5958             :             {
    5959           0 :                 tmpTDRendBuffer[i][j] = L_shl( tmpTDRendBuffer[i][j], Q2 ); /* Q(exp + 2) */
    5960           0 :                 move32();
    5961             :             }
    5962             :         }
    5963             :     }
    5964      150000 :     accumulate2dArrayToBuffer_fx( tmpTDRendBuffer, &outAudio );
    5965             : 
    5966      150000 :     pop_wmops();
    5967             : 
    5968      150000 :     return IVAS_ERR_OK;
    5969             : }
    5970             : 
    5971             : 
    5972           0 : static Word16 getNumSubframesInBuffer(
    5973             :     const IVAS_REND_AudioBuffer *buffer,
    5974             :     const Word32 sampleRate )
    5975             : {
    5976             :     Word16 cldfb2tdShift;
    5977             : 
    5978           0 :     cldfb2tdShift = buffer->config.is_cldfb ? 1 : 0;
    5979             : 
    5980           0 :     Word16 scale, temp = extract_l( Mpy_32_32( sampleRate, 10737418 /* 1 / FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
    5981           0 :     temp = BASOP_Util_Divide1616_Scale( buffer->config.numSamplesPerChannel, temp, &scale );
    5982           0 :     temp = shr( temp, sub( 15, scale ) ); /* Q0 */
    5983           0 :     temp = shr( temp, cldfb2tdShift );
    5984             : 
    5985           0 :     return temp;
    5986             : }
    5987             : 
    5988             : 
    5989      150000 : static ivas_error renderIsmToBinauralRoom(
    5990             :     input_ism *ismInput,
    5991             :     IVAS_REND_AudioBuffer outAudio,
    5992             :     Word16 *exp )
    5993             : {
    5994             :     Word16 position_changed;
    5995             :     Word16 i, j;
    5996             :     Word32 azi_rot, ele_rot; /* Q22 */
    5997             :     Word16 subframe_idx;
    5998             :     Word16 tmp;
    5999             :     rotation_matrix_fx Rmat;
    6000             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6001             :     ivas_error error;
    6002             :     pan_vector_fx currentPanGains;
    6003             :     IVAS_REND_AudioBuffer tmpMcBuffer;
    6004             :     IVAS_ISM_METADATA rotatedPosPrev;
    6005             :     IVAS_ISM_METADATA rotatedPos;
    6006             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    6007             :     Word8 combinedOrientationEnabled;
    6008             :     Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
    6009             : 
    6010     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6011             :     {
    6012     2400000 :         p_tmpRendBuffer[i] = tmpRendBuffer[i];
    6013             :     }
    6014             : 
    6015      150000 :     push_wmops( "renderIsmToBinauralRoom" );
    6016             : 
    6017      150000 :     rotatedPosPrev = defaultObjectPosition();
    6018      150000 :     rotatedPos = defaultObjectPosition();
    6019             : 
    6020      150000 :     hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
    6021      150000 :     combinedOrientationEnabled = 0;
    6022      150000 :     move16();
    6023             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    6024      150000 :     IF( *hCombinedOrientationData != NULL )
    6025             : #else
    6026             :     IF( hCombinedOrientationData != NULL )
    6027             : #endif
    6028             :     {
    6029       75000 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    6030             :         {
    6031       75000 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    6032             :             {
    6033       75000 :                 combinedOrientationEnabled = 1;
    6034       75000 :                 move16();
    6035       75000 :                 BREAK;
    6036             :             }
    6037             :         }
    6038             :     }
    6039             : 
    6040      150000 :     IF( combinedOrientationEnabled )
    6041             :     {
    6042      150000 :         FOR( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
    6043             :         {
    6044      300000 :             FOR( i = 0; i < 3; i++ )
    6045             :             {
    6046      225000 :                 test();
    6047      225000 :                 IF( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
    6048             :                 {
    6049      900000 :                     FOR( j = 0; j < 3; j++ )
    6050             :                     {
    6051      675000 :                         Rmat[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
    6052      675000 :                         move32();
    6053             :                     }
    6054             :                 }
    6055             :                 ELSE
    6056             :                 {
    6057             :                     /* Set to identity */
    6058           0 :                     set_zero_fx( Rmat[i], 3 );
    6059           0 :                     Rmat[i][i] = ONE_IN_Q30;
    6060           0 :                     move32();
    6061             :                 }
    6062             :             }
    6063             :         }
    6064             :     }
    6065             : 
    6066             :     /* get previous position */
    6067      150000 :     IF( combinedOrientationEnabled )
    6068             :     {
    6069       75000 :         rotateAziEle_fx_frac_az_el( ismInput->previousPos.azimuth_fx, ismInput->previousPos.elevation_fx, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
    6070       75000 :         rotatedPosPrev.azimuth_fx = azi_rot;
    6071       75000 :         move32();
    6072       75000 :         rotatedPosPrev.elevation_fx = ele_rot;
    6073       75000 :         move32();
    6074             :     }
    6075             :     ELSE
    6076             :     {
    6077       75000 :         rotatedPosPrev.azimuth_fx = ismInput->previousPos.azimuth_fx;
    6078       75000 :         move32();
    6079       75000 :         rotatedPosPrev.elevation_fx = ismInput->previousPos.elevation_fx;
    6080       75000 :         move32();
    6081             :     }
    6082             : 
    6083             :     /* get current position */
    6084      150000 :     IF( combinedOrientationEnabled )
    6085             :     {
    6086       75000 :         rotateAziEle_fx_frac_az_el( ismInput->currentPos.azimuth_fx, ismInput->currentPos.elevation_fx, &azi_rot, &ele_rot, Rmat, 0 );
    6087       75000 :         rotatedPos.azimuth_fx = azi_rot;
    6088       75000 :         move32();
    6089       75000 :         rotatedPos.elevation_fx = ele_rot;
    6090       75000 :         move32();
    6091             :     }
    6092             :     ELSE
    6093             :     {
    6094       75000 :         rotatedPos.azimuth_fx = ismInput->currentPos.azimuth_fx;
    6095       75000 :         move32();
    6096       75000 :         rotatedPos.elevation_fx = ismInput->currentPos.elevation_fx;
    6097       75000 :         move32();
    6098             :     }
    6099             : 
    6100      150000 :     test();
    6101      150000 :     position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &rotatedPos, &rotatedPosPrev );
    6102      150000 :     move16();
    6103             : 
    6104             :     /* set previous gains if this is the first frame */
    6105      150000 :     IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper, rotatedPosPrev.azimuth_fx, rotatedPosPrev.elevation_fx, ismInput->prev_pan_gains_fx ) ), IVAS_ERR_OK ) )
    6106             :     {
    6107           0 :         return error;
    6108             :     }
    6109             : 
    6110             :     /* compute gains only if position changed */
    6111      150000 :     IF( position_changed )
    6112             :     {
    6113       64693 :         IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper, rotatedPos.azimuth_fx, rotatedPos.elevation_fx, currentPanGains ) ),
    6114             :                    IVAS_ERR_OK ) )
    6115             :         {
    6116           0 :             return error;
    6117             :         }
    6118             :     }
    6119             : 
    6120             :     /* intermediate rendering to 7_1_4 */
    6121      150000 :     tmpMcBuffer = ismInput->base.inputBuffer;
    6122             : 
    6123      150000 :     IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
    6124             :     {
    6125           0 :         return error;
    6126             :     }
    6127             : 
    6128      150000 :     tmpMcBuffer.config.numChannels = tmp;
    6129      150000 :     move16();
    6130      150000 :     tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
    6131      150000 :     set_zero_fx( tmpMcBuffer.data_fx, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
    6132             : 
    6133      150000 :     IF( position_changed )
    6134             :     {
    6135       64693 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains, ismInput->prev_pan_gains_fx, tmpMcBuffer );
    6136             :     }
    6137             :     ELSE
    6138             :     {
    6139       85307 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, tmpMcBuffer );
    6140             :     }
    6141             : 
    6142      150000 :     copyBufferTo2dArray_fx( tmpMcBuffer, tmpRendBuffer );
    6143             : 
    6144             :     /* save gains for next frame */
    6145      600000 :     FOR( i = 0; i < 3; i++ )
    6146             :     {
    6147      450000 :         Copy32( Rmat[i], ismInput->rot_mat_prev[i], 3 );
    6148             :     }
    6149             : 
    6150      150000 :     IF( position_changed )
    6151             :     {
    6152       64693 :         Copy32( currentPanGains, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    6153             :     }
    6154             : 
    6155             :     CREND_HANDLE hCrend;
    6156      150000 :     hCrend = ismInput->crendWrapper->hCrend[0];
    6157      150000 :     IF( hCrend->reflections != NULL )
    6158             :     {
    6159           0 :         test();
    6160           0 :         IF( EQ_32( hCrend->reflections->use_er, 1 ) && EQ_32( hCrend->reflections->is_ready, 1 ) )
    6161             :         {
    6162           0 :             FOR( i = 0; i < 150; i++ )
    6163             :             {
    6164           0 :                 hCrend->reflections->shoebox_data.gains.data_fx[i] = L_shl( hCrend->reflections->shoebox_data.gains.data_fx[i], Q9 );
    6165           0 :                 move32();
    6166             :             }
    6167             :         }
    6168             :     }
    6169             : 
    6170             : #ifdef FIX_1843_IO_QFACTOR_INIT
    6171      150000 :     *ismInput->crendWrapper->p_io_qfactor = *exp;
    6172             : #endif
    6173             :     /* render 7_1_4 with BRIRs */
    6174      150000 :     IF( NE_32( ( error = ivas_rend_crendProcessSubframe( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, ismInput->base.inputBuffer.config.numSamplesPerChannel, *ismInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
    6175             :     {
    6176           0 :         return error;
    6177             :     }
    6178             : 
    6179      150000 :     IF( hCrend->hReverb != NULL )
    6180             :     {
    6181           0 :         *exp = sub( *exp, 2 );
    6182           0 :         move16();
    6183             :     }
    6184      150000 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
    6185             : 
    6186      150000 :     free( tmpMcBuffer.data_fx );
    6187             : 
    6188      150000 :     pop_wmops();
    6189             : 
    6190      150000 :     return IVAS_ERR_OK;
    6191             : }
    6192             : 
    6193             : 
    6194      150000 : static ivas_error renderIsmToBinauralReverb(
    6195             :     input_ism *ismInput,
    6196             :     IVAS_REND_AudioBuffer outAudio )
    6197             : {
    6198             :     Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6199             :     ivas_error error;
    6200             :     Word16 ism_md_subframe_update_ext, i;
    6201      150000 :     Word16 exp = *outAudio.pq_fact;
    6202      150000 :     move16();
    6203             : 
    6204      150000 :     push_wmops( "renderIsmToBinauralRoom" );
    6205             : 
    6206             :     /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
    6207      150000 :     ism_md_subframe_update_ext = extract_l( Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, 429496730 /* 1000 / FRAMES_PER_SEC / MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
    6208      150000 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
    6209             : 
    6210     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    6211             :     {
    6212     2400000 :         Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    6213             :     }
    6214             : 
    6215      150000 :     IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &ismInput->tdRendWrapper, ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos, ismInput->hReverb, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ), IVAS_ERR_OK ) )
    6216             :     {
    6217           0 :         return error;
    6218             :     }
    6219             : 
    6220     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    6221             :     {
    6222     2400000 :         Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( 11, exp ) ) ); /* Q(exp) */
    6223             :     }
    6224             : 
    6225      150000 :     IF( ismInput->hReverb != NULL )
    6226             :     {
    6227      450000 :         FOR( i = 0; i < outAudio.config.numChannels; i++ )
    6228             :         {
    6229   115500000 :             FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
    6230             :             {
    6231   115200000 :                 tmpRendBuffer_fx[i][j] = L_shl( tmpRendBuffer_fx[i][j], 2 ); /* Q(exp + 2) */
    6232   115200000 :                 move16();
    6233             :             }
    6234             :         }
    6235             :     }
    6236      150000 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    6237      150000 :     pop_wmops();
    6238             : 
    6239      150000 :     return IVAS_ERR_OK;
    6240             : }
    6241             : 
    6242             : 
    6243      569500 : static ivas_error renderIsmToMc(
    6244             :     input_ism *ismInput,
    6245             :     const IVAS_REND_AudioBuffer outAudio )
    6246             : {
    6247             :     Word8 position_changed;
    6248             :     pan_vector_fx currentPanGains_fx; /* Q31 */
    6249             :     ivas_error error;
    6250             : 
    6251      569500 :     push_wmops( "renderIsmToMc" );
    6252             : 
    6253      569500 :     ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6254      569500 :     move32();
    6255      569500 :     ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6256      569500 :     move32();
    6257      569500 :     ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6258      569500 :     move32();
    6259      569500 :     ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6260      569500 :     move32();
    6261             : 
    6262      569500 :     test();
    6263      569500 :     position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
    6264      569500 :     move16();
    6265      569500 :     IF( EQ_32( *ismInput->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_STEREO ) )
    6266             :     {
    6267       83500 :         IF( ismInput->nonDiegeticPan )
    6268             :         {
    6269        7500 :             currentPanGains_fx[0] = L_add( L_shr( ismInput->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); /* Q31 */
    6270        7500 :             currentPanGains_fx[1] = L_sub( ONE_IN_Q31, currentPanGains_fx[0] );                       /* Q31 */
    6271        7500 :             ismInput->prev_pan_gains_fx[0] = currentPanGains_fx[0];                                   /* Q31 */
    6272        7500 :             ismInput->prev_pan_gains_fx[1] = currentPanGains_fx[1];                                   /* Q31 */
    6273        7500 :             move32();
    6274        7500 :             move32();
    6275        7500 :             move32();
    6276        7500 :             move32();
    6277             :         }
    6278             :         ELSE
    6279             :         {
    6280       76000 :             set32_fx( currentPanGains_fx, 0, MAX_OUTPUT_CHANNELS );
    6281             : 
    6282             :             Word16 gains_fx[2];
    6283             :             Word16 azimuth_tmp, elevation_tmp;
    6284             : 
    6285       76000 :             azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
    6286       76000 :             elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
    6287             : 
    6288       76000 :             ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
    6289       76000 :             currentPanGains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
    6290       76000 :             currentPanGains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
    6291       76000 :             move32();
    6292       76000 :             move32();
    6293             : 
    6294       76000 :             azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
    6295       76000 :             elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
    6296             : 
    6297       76000 :             set32_fx( ismInput->prev_pan_gains_fx, 0, MAX_OUTPUT_CHANNELS );
    6298       76000 :             ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
    6299       76000 :             ismInput->prev_pan_gains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
    6300       76000 :             ismInput->prev_pan_gains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
    6301       76000 :             move32();
    6302       76000 :             move32();
    6303             :         }
    6304             :     }
    6305             :     ELSE
    6306             :     {
    6307             :         /* compute gains only if position changed */
    6308      486000 :         IF( position_changed )
    6309             :         {
    6310             :             // TODO tmu review when #215 is resolved
    6311      207304 :             IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
    6312             :                                                   ismInput->currentPos.azimuth_fx,
    6313             :                                                   ismInput->currentPos.elevation_fx,
    6314             :                                                   currentPanGains_fx ) ),
    6315             :                        IVAS_ERR_OK ) )
    6316             :             {
    6317           0 :                 return error;
    6318             :             }
    6319             :         }
    6320             : 
    6321             :         /* set previous gains if this is the first frame */
    6322      486000 :         IF( !ismInput->firstFrameRendered )
    6323             :         {
    6324             :             // TODO tmu review when #215 is resolved
    6325         188 :             IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
    6326             :                                                   ismInput->previousPos.azimuth_fx,
    6327             :                                                   ismInput->previousPos.elevation_fx,
    6328             :                                                   ismInput->prev_pan_gains_fx ) ),
    6329             :                        IVAS_ERR_OK ) )
    6330             :             {
    6331           0 :                 return error;
    6332             :             }
    6333             :             /* fix2float to be removed */
    6334             :         }
    6335             :     }
    6336             : 
    6337             :     /* Assume num channels in audio buffer to be 1.
    6338             :      * This should have been validated in IVAS_REND_FeedInputAudio() */
    6339      569500 :     IF( position_changed )
    6340             :     {
    6341      244300 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains_fx, ismInput->prev_pan_gains_fx, outAudio );
    6342             :     }
    6343             :     ELSE
    6344             :     {
    6345      325200 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, outAudio );
    6346             :     }
    6347             : 
    6348      569500 :     IF( position_changed )
    6349             :     {
    6350      244300 :         Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    6351             :     }
    6352             : 
    6353      569500 :     pop_wmops();
    6354             : 
    6355             : 
    6356      569500 :     return IVAS_ERR_OK;
    6357             : }
    6358             : 
    6359             : 
    6360      228000 : static ivas_error renderIsmToSba(
    6361             :     input_ism *ismInput,
    6362             :     const AUDIO_CONFIG outConfig,
    6363             :     const IVAS_REND_AudioBuffer outAudio )
    6364             : {
    6365             :     Word16 i;
    6366             :     Word8 position_changed;
    6367             :     Word16 ambiOrderOut;
    6368             :     Word16 numOutChannels;
    6369             :     pan_vector_fx currentPanGains_fx;
    6370             :     ivas_error error;
    6371      228000 :     error = IVAS_ERR_OK;
    6372      228000 :     move32();
    6373             : 
    6374      228000 :     ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6375      228000 :     ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6376      228000 :     ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6377      228000 :     ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    6378      228000 :     move32();
    6379      228000 :     move32();
    6380      228000 :     move32();
    6381      228000 :     move32();
    6382             : 
    6383      228000 :     push_wmops( "renderIsmToSba" );
    6384             : 
    6385      228000 :     IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
    6386             :     {
    6387           0 :         return error;
    6388             :     }
    6389             : 
    6390      228000 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &ambiOrderOut ) ), IVAS_ERR_OK ) )
    6391             :     {
    6392           0 :         return error;
    6393             :     }
    6394             : 
    6395      228000 :     test();
    6396      228000 :     position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
    6397      228000 :     move16();
    6398             : 
    6399             :     /* set previous gains if this is the first frame */
    6400             :     Word16 azimuth_tmp, elevation_tmp;
    6401      228000 :     IF( !ismInput->firstFrameRendered )
    6402             :     {
    6403             :         // TODO tmu review when #215 is resolved
    6404          84 :         azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
    6405          84 :         elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
    6406          84 :         ivas_dirac_dec_get_response_fx( azimuth_tmp, elevation_tmp, ismInput->prev_pan_gains_fx, ambiOrderOut, Q29 );
    6407        1428 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6408             :         {
    6409        1344 :             ismInput->prev_pan_gains_fx[i] = L_shl_sat( ismInput->prev_pan_gains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
    6410        1344 :             move32();
    6411             :         }
    6412             :     }
    6413             : 
    6414             :     /* compute gains only if position changed */
    6415      228000 :     IF( position_changed )
    6416             :     {
    6417             :         // TODO tmu review when #215 is resolved
    6418       88848 :         azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
    6419       88848 :         elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
    6420       88848 :         ivas_dirac_dec_get_response_fx( azimuth_tmp, elevation_tmp, currentPanGains_fx, ambiOrderOut, Q29 );
    6421     1510416 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6422             :         {
    6423     1421568 :             currentPanGains_fx[i] = L_shl_sat( currentPanGains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
    6424     1421568 :             move32();
    6425             :         }
    6426             :     }
    6427             : 
    6428             :     /* Assume num channels in audio buffer to be 1.
    6429             :      * This should have been validated in IVAS_REND_FeedInputAudio() */
    6430      228000 :     IF( position_changed )
    6431             :     {
    6432       88848 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, currentPanGains_fx, ismInput->prev_pan_gains_fx, outAudio );
    6433             :     }
    6434             :     ELSE
    6435             :     {
    6436      139152 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0, ismInput->prev_pan_gains_fx, NULL, outAudio );
    6437             :     }
    6438             : 
    6439      228000 :     IF( position_changed )
    6440             :     {
    6441       88848 :         Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    6442             :     }
    6443      228000 :     pop_wmops();
    6444             : 
    6445      228000 :     return error;
    6446             : }
    6447             : 
    6448             : 
    6449           0 : static ivas_error renderIsmToSplitBinaural(
    6450             :     input_ism *ismInput,
    6451             :     const IVAS_REND_AudioBuffer outAudio )
    6452             : {
    6453             :     ivas_error error;
    6454             :     Word32 tmpProcessing[MAX_NUM_OBJECTS][L_FRAME48k];
    6455             :     Word16 pos_idx;
    6456             :     const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
    6457             :     const SPLIT_REND_WRAPPER *pSplitRendWrapper;
    6458             :     IVAS_QUATERNION originalHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
    6459             :     IVAS_QUATERNION localHeadRot[MAX_PARAM_SPATIAL_SUBFRAMES];
    6460             :     Word16 i;
    6461             :     Word32 tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
    6462           0 :     Word16 output_frame = ismInput->base.inputBuffer.config.numSamplesPerChannel;
    6463             :     COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
    6464             :     Word16 ism_md_subframe_update_ext, exp;
    6465             : 
    6466           0 :     push_wmops( "renderIsmToSplitBinaural" );
    6467             : 
    6468           0 :     pSplitRendWrapper = ismInput->base.ctx.pSplitRendWrapper;
    6469           0 :     pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
    6470             : 
    6471           0 :     exp = *outAudio.pq_fact;
    6472             :     /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
    6473           0 :     ism_md_subframe_update_ext = (Word16) Mpy_32_32( ismInput->ism_metadata_delay_ms_fx, ONE_BY_SUBFRAME_LEN_MS_Q31 );
    6474             : 
    6475           0 :     pCombinedOrientationData = *ismInput->base.ctx.pCombinedOrientationData;
    6476             : 
    6477           0 :     IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
    6478             :     {
    6479           0 :         FOR( i = 1; i < pCombinedOrientationData->num_subframes; ++i )
    6480             :         {
    6481           0 :             Copy_Quat_fx( &pCombinedOrientationData->Quaternions[0], &pCombinedOrientationData->Quaternions[i] );
    6482             :         }
    6483             :     }
    6484             : 
    6485             :     /* Save current head positions */
    6486           0 :     FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
    6487             :     {
    6488           0 :         Copy_Quat_fx( &pCombinedOrientationData->Quaternions[i], &originalHeadRot[i] );
    6489             :     }
    6490             : 
    6491             :     /* Copy input audio to a processing buffer. */
    6492           0 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
    6493             : 
    6494             : 
    6495           0 :     FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
    6496             :     {
    6497             :         /* Update head positions */
    6498           0 :         IF( NE_16( pos_idx, 0 ) )
    6499             :         {
    6500             :             Word16 q_fact_orig;
    6501           0 :             FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
    6502             :             {
    6503           0 :                 pCombinedOrientationData->Quaternions[i].w_fx = L_negate( 12582912 ); // Q22
    6504           0 :                 q_fact_orig = originalHeadRot[i].q_fact;
    6505           0 :                 modify_Quat_q_fx( &originalHeadRot[i], &localHeadRot[i], Q22 );
    6506             :                 /*euler*/
    6507           0 :                 Quat2EulerDegree_fx( localHeadRot[i], &pCombinedOrientationData->Quaternions[i].z_fx, &pCombinedOrientationData->Quaternions[i].y_fx, &pCombinedOrientationData->Quaternions[i].x_fx );
    6508           0 :                 pCombinedOrientationData->Quaternions[i].x_fx = L_add( pCombinedOrientationData->Quaternions[i].x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
    6509           0 :                 pCombinedOrientationData->Quaternions[i].y_fx = L_add( pCombinedOrientationData->Quaternions[i].y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
    6510           0 :                 pCombinedOrientationData->Quaternions[i].z_fx = L_add( pCombinedOrientationData->Quaternions[i].z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
    6511             : 
    6512           0 :                 Euler2Quat_fx( deg2rad_fx( pCombinedOrientationData->Quaternions[i].x_fx ), deg2rad_fx( pCombinedOrientationData->Quaternions[i].y_fx ), deg2rad_fx( pCombinedOrientationData->Quaternions[i].z_fx ), &pCombinedOrientationData->Quaternions[i] );
    6513             : 
    6514           0 :                 modify_Quat_q_fx( &pCombinedOrientationData->Quaternions[i], &pCombinedOrientationData->Quaternions[i], q_fact_orig );
    6515             :             }
    6516             :         }
    6517             : 
    6518             : 
    6519           0 :         FOR( i = 0; i < MAX_NUM_OBJECTS; ++i )
    6520             :         {
    6521           0 :             Scale_sig32( tmpProcessing[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    6522             :         }
    6523             : 
    6524             :         /* Render */
    6525           0 :         IF( ( error = ivas_td_binaural_renderer_ext_fx( ( pos_idx == 0 ) ? &ismInput->tdRendWrapper : &ismInput->splitTdRendWrappers[sub( pos_idx, 1 )], ismInput->base.inConfig, NULL, ismInput->base.ctx.pCombinedOrientationData, &ismInput->currentPos,
    6526             :                                                         NULL, ism_md_subframe_update_ext, *ismInput->base.ctx.pOutSampleRate, output_frame, tmpProcessing, &exp ) ) != IVAS_ERR_OK )
    6527             :         {
    6528           0 :             return error;
    6529             :         }
    6530             : 
    6531           0 :         FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
    6532             :         {
    6533           0 :             Scale_sig32( tmpProcessing[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    6534             :         }
    6535             : 
    6536           0 :         IF( ismInput->hReverb != NULL )
    6537             :         {
    6538           0 :             FOR( i = 0; i < BINAURAL_CHANNELS; i++ )
    6539             :             {
    6540           0 :                 FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
    6541             :                 {
    6542           0 :                     tmpProcessing[i][j] = L_shl( tmpProcessing[i][j], Q2 ); /* Q(exp + 2) */
    6543           0 :                     move32();
    6544             :                 }
    6545             :             }
    6546             :         }
    6547             :         /* Copy rendered audio to tmp storage buffer. Copying directly to output would
    6548             :          * overwrite original audio, which is still needed for rendering next head pose. */
    6549           0 :         Copy32( tmpProcessing[0], tmpBinaural[i_mult( 2, pos_idx )], output_frame );
    6550           0 :         Copy32( tmpProcessing[1], tmpBinaural[add( i_mult( 2, pos_idx ), 1 )], output_frame );
    6551             : 
    6552             :         /* Overwrite processing buffer with original input audio again */
    6553           0 :         copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpProcessing );
    6554             :     }
    6555             : 
    6556             :     /* Restore original head rotation */
    6557           0 :     FOR( i = 0; i < pCombinedOrientationData->num_subframes; ++i )
    6558             :     {
    6559           0 :         Copy_Quat_fx( &originalHeadRot[i], &pCombinedOrientationData->Quaternions[i] );
    6560             :     }
    6561             : 
    6562           0 :     accumulate2dArrayToBuffer_fx( tmpBinaural, &outAudio );
    6563           0 :     pop_wmops();
    6564             : 
    6565             :     /* Encoding to split rendering bitstream done at a higher level */
    6566           0 :     return IVAS_ERR_OK;
    6567             : }
    6568             : 
    6569             : 
    6570         150 : static void renderIsmToMasa(
    6571             :     input_ism *ismInput,
    6572             :     IVAS_REND_AudioBuffer outAudio,
    6573             :     Word16 *exp )
    6574             : {
    6575             :     Word32 tmpRendBuffer_fx[MAX_NUM_OBJECTS][L_FRAME48k];
    6576             :     Word16 i, guard_bits, q_min, q_diff;
    6577             : 
    6578         150 :     push_wmops( "renderIsmToMasa" );
    6579             : 
    6580         150 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
    6581             : 
    6582         150 :     q_min = MAX_16;
    6583         150 :     move16();
    6584             : 
    6585         750 :     FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
    6586             :     {
    6587         600 :         q_min = s_min( q_min, L_norm_arr( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel ) );
    6588             :     }
    6589             : 
    6590         150 :     guard_bits = find_guarded_bits_fx( ismInput->base.inputBuffer.config.numSamplesPerChannel );
    6591         150 :     q_min = sub( add( q_min, *outAudio.pq_fact ), guard_bits );
    6592         150 :     q_diff = sub( q_min, *outAudio.pq_fact );
    6593             : 
    6594         750 :     FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
    6595             :     {
    6596         600 :         scale_sig32( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel, q_diff ); // *outAudio.pq_fact -> q_min
    6597             :     }
    6598             : 
    6599         150 :     ivas_omasa_ana_fx( ismInput->hOMasa, tmpRendBuffer_fx, &q_min, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
    6600             : 
    6601         150 :     *exp = q_min;
    6602         150 :     move16();
    6603             : 
    6604         150 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    6605             : 
    6606         150 :     pop_wmops();
    6607             : 
    6608         150 :     return;
    6609             : }
    6610             : 
    6611     1247650 : static ivas_error renderInputIsm(
    6612             :     input_ism *ismInput,
    6613             :     const AUDIO_CONFIG outConfig,
    6614             :     const IVAS_REND_AudioBuffer outAudio )
    6615             : {
    6616             :     ivas_error error;
    6617             :     IVAS_REND_AudioBuffer inAudio;
    6618     1247650 :     Word16 exp = *outAudio.pq_fact;
    6619     1247650 :     move16();
    6620             : 
    6621     1247650 :     error = IVAS_ERR_OK;
    6622     1247650 :     move32();
    6623     1247650 :     inAudio = ismInput->base.inputBuffer;
    6624             : 
    6625     1247650 :     IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
    6626             :     {
    6627           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" );
    6628             :     }
    6629     1247650 :     ismInput->base.numNewSamplesPerChannel = 0;
    6630     1247650 :     move32();
    6631             : 
    6632             :     /* Apply input gain to new audio */
    6633     1247650 :     v_multc_fixed( inAudio.data_fx, ismInput->base.gain_fx, inAudio.data_fx, imult1616( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
    6634     1247650 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 );
    6635     1247650 :     move16();
    6636     1247650 :     exp = *outAudio.pq_fact;
    6637     1247650 :     move16();
    6638             : 
    6639             :     /* set combined orientation subframe info to start info */
    6640     1247650 :     ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
    6641             : 
    6642             : 
    6643     1247650 :     SWITCH( getAudioConfigType( outConfig ) )
    6644             :     {
    6645      569500 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    6646      569500 :             error = renderIsmToMc( ismInput, outAudio );
    6647      569500 :             BREAK;
    6648      228000 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    6649      228000 :             error = renderIsmToSba( ismInput, outConfig, outAudio );
    6650      228000 :             BREAK;
    6651      450000 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    6652             :             SWITCH( outConfig )
    6653             :             {
    6654      150000 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    6655      150000 :                     error = renderIsmToBinaural( ismInput, outAudio );
    6656      150000 :                     BREAK;
    6657      150000 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    6658      150000 :                     error = renderIsmToBinauralRoom( ismInput, outAudio, &exp );
    6659      150000 :                     BREAK;
    6660           0 :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
    6661             :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
    6662           0 :                     error = renderIsmToSplitBinaural( ismInput, outAudio );
    6663           0 :                     break;
    6664      150000 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    6665      150000 :                     error = renderIsmToBinauralReverb( ismInput, outAudio );
    6666      150000 :                     BREAK;
    6667           0 :                 default:
    6668           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    6669             :             }
    6670      450000 :             BREAK;
    6671         150 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    6672         150 :             renderIsmToMasa( ismInput, outAudio, &exp );
    6673         150 :             BREAK;
    6674           0 :         default:
    6675           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    6676             :     }
    6677             : 
    6678             :     /* Check error here to keep switch statement more compact */
    6679     1247650 :     IF( NE_32( error, IVAS_ERR_OK ) )
    6680             :     {
    6681           0 :         return error;
    6682             :     }
    6683             : 
    6684     1247650 :     ismInput->firstFrameRendered = TRUE;
    6685     1247650 :     move16();
    6686             : 
    6687     1247650 :     *outAudio.pq_fact = exp;
    6688     1247650 :     move16();
    6689             : 
    6690     1247650 :     return error;
    6691             : }
    6692             : 
    6693     1126140 : static ivas_error renderActiveInputsIsm(
    6694             :     IVAS_REND_HANDLE hIvasRend,
    6695             :     IVAS_REND_AudioBuffer outAudio )
    6696             : {
    6697             :     Word16 i;
    6698             :     input_ism *pCurrentInput;
    6699             :     ivas_error error;
    6700     1126140 :     Word16 input_q = outAudio.q_factor;
    6701     1126140 :     move16();
    6702     5630700 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
    6703             :     {
    6704     4504560 :         IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    6705             :         {
    6706             :             /* Skip inactive inputs */
    6707     3256910 :             CONTINUE;
    6708             :         }
    6709             : 
    6710     1247650 :         *outAudio.pq_fact = input_q;
    6711     1247650 :         move16();
    6712     1247650 :         IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    6713             :         {
    6714           0 :             return error;
    6715             :         }
    6716  2925119650 :         FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
    6717             :         {
    6718  2923872000 :             outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
    6719  2923872000 :             move32();
    6720             :         }
    6721     1247650 :         *outAudio.pq_fact = sub( input_q, 1 );
    6722     1247650 :         move16();
    6723             :     }
    6724     1126140 :     return IVAS_ERR_OK;
    6725             : }
    6726             : 
    6727       87012 : static ivas_error renderLfeToBinaural_fx(
    6728             :     const input_mc *mcInput,
    6729             :     const AUDIO_CONFIG outConfig,
    6730             :     IVAS_REND_AudioBuffer outAudio,
    6731             :     Word16 in_q,
    6732             :     Word16 out_q )
    6733             : {
    6734             :     Word16 lfe_idx;
    6735             :     Word16 pose_idx, num_poses;
    6736             :     Word32 gain_fx;
    6737             :     Word16 ear_idx, i, r_shift;
    6738             :     Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL];
    6739             :     Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
    6740             :     const Word32 *lfeInput;
    6741             :     Word32 *writePtr;
    6742             : 
    6743       87012 :     assert( ( getAudioConfigType( outConfig ) == IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) && "Must be binaural output" );
    6744             : 
    6745       87012 :     push_wmops( "renderLfeToBinaural" );
    6746       87012 :     gain_fx = GAIN_LFE_WORD32; /* 1.88364911f in Q30 */
    6747       87012 :     move32();
    6748             : 
    6749       87012 :     IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    6750             :     {
    6751       48000 :         lfe_idx = LFE_CHANNEL;
    6752       48000 :         move16();
    6753             :     }
    6754       39012 :     ELSE IF( mcInput->customLsInput.num_lfe > 0 )
    6755             :     {
    6756           0 :         lfe_idx = mcInput->customLsInput.lfe_idx[0];
    6757           0 :         move16();
    6758             :     }
    6759             :     ELSE
    6760             :     {
    6761             :         /* no LFE to render */
    6762       39012 :         pop_wmops();
    6763       39012 :         return IVAS_ERR_OK;
    6764             :     }
    6765             : 
    6766             :     /* --- Prepare LFE signal to be added to binaural output --- */
    6767       48000 :     lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 );
    6768       48000 :     frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
    6769       48000 :     move16();
    6770       48000 :     num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
    6771       48000 :     move16();
    6772       48000 :     num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame );
    6773             : 
    6774             :     /* Assuming LFE should be delayed by less that the duration of one frame */
    6775       48000 :     assert( mcInput->binauralDelaySmp < frame_size );
    6776             : 
    6777             :     /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
    6778       48000 :     v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
    6779             : 
    6780             :     /* Continue filling tmp buffer, now with LFE signal from current frame */
    6781       48000 :     v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); /* Qx - 1 */
    6782             : 
    6783             :     /* Save remaining LFE samples of current frame for next frame */
    6784       48000 :     MVR2R_WORD32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame );
    6785       48000 :     r_shift = sub( sub( in_q, 1 ), out_q );
    6786             : 
    6787       48000 :     IF( r_shift != 0 )
    6788             :     {
    6789    14533750 :         FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ )
    6790             :         {
    6791    14496000 :             tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); /* Q(out_q) */
    6792    14496000 :             move32();
    6793             :         }
    6794             :     }
    6795             : 
    6796             :     /* Copy LFE to left and right binaural channels for all poses */
    6797       48000 :     IF( mcInput->base.ctx.pSplitRendWrapper != NULL )
    6798             :     {
    6799           0 :         num_poses = mcInput->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    6800           0 :         move16();
    6801             :     }
    6802             :     ELSE
    6803             :     {
    6804       48000 :         num_poses = 1;
    6805       48000 :         move16();
    6806             :     }
    6807             : 
    6808       96000 :     FOR( pose_idx = 0; pose_idx < num_poses; ++pose_idx )
    6809             :     {
    6810      144000 :         FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
    6811             :         {
    6812       96000 :             writePtr = getSmplPtr_fx( outAudio, add( i_mult( pose_idx, BINAURAL_CHANNELS ), ear_idx ), 0 );
    6813       96000 :             move32();
    6814       96000 :             v_add_fixed_no_hdrm( writePtr, tmpLfeBuffer, writePtr, frame_size ); /* Q(out_q) */
    6815             :         }
    6816             :     }
    6817             : 
    6818       48000 :     pop_wmops();
    6819             : 
    6820       48000 :     return IVAS_ERR_OK;
    6821             : }
    6822             : 
    6823       29004 : static ivas_error renderMcToBinaural(
    6824             :     input_mc *mcInput,
    6825             :     const AUDIO_CONFIG outConfig,
    6826             :     IVAS_REND_AudioBuffer outAudio )
    6827             : {
    6828             :     Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6829             :     AUDIO_CONFIG inConfig;
    6830             :     ivas_error error;
    6831             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    6832             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    6833             :     Word8 combinedOrientationEnabled;
    6834             :     Word16 subframe_idx;
    6835             :     Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS];
    6836             :     Word16 i;
    6837       29004 :     Word16 exp = *outAudio.pq_fact;
    6838       29004 :     move16();
    6839             : 
    6840      493068 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6841             :     {
    6842      464064 :         p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i];
    6843             :     }
    6844       29004 :     push_wmops( "renderMcToBinaural" );
    6845             : 
    6846       29004 :     inConfig = mcInput->base.inConfig;
    6847       29004 :     move32();
    6848       29004 :     hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
    6849       29004 :     combinedOrientationEnabled = 0;
    6850       29004 :     move16();
    6851             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    6852       29004 :     IF( *hCombinedOrientationData != NULL )
    6853             : #else
    6854             :     IF( hCombinedOrientationData != NULL )
    6855             : #endif
    6856             :     {
    6857       14502 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    6858             :         {
    6859       14502 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    6860             :             {
    6861       14502 :                 combinedOrientationEnabled = 1;
    6862       14502 :                 move16();
    6863       14502 :                 BREAK;
    6864             :             }
    6865             :         }
    6866             :     }
    6867             : 
    6868       29004 :     test();
    6869       29004 :     test();
    6870       29004 :     test();
    6871       29004 :     IF( ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) ) || ( combinedOrientationEnabled && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) ) )
    6872             :     {
    6873       18754 :         copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
    6874             : 
    6875      318818 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    6876             :         {
    6877      300064 :             Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    6878             :         }
    6879       18754 :         IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
    6880             :                                                                0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ),
    6881             :                    IVAS_ERR_OK ) )
    6882             :         {
    6883           0 :             return error;
    6884             :         }
    6885             : 
    6886      318818 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    6887             :         {
    6888      300064 :             Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    6889             :         }
    6890             :     }
    6891             :     ELSE
    6892             :     {
    6893             :         /* apply rotation */
    6894       10250 :         IF( combinedOrientationEnabled )
    6895             :         {
    6896        2250 :             tmpRotBuffer = mcInput->base.inputBuffer;
    6897        2250 :             tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    6898        2250 :             set32_fx( tmpRotBuffer.data_fx, 0, imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
    6899             : 
    6900        2250 :             IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev_fx[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ), IVAS_ERR_OK ) )
    6901             :             {
    6902           0 :                 return error;
    6903             :             }
    6904             : 
    6905        2250 :             exp = sub( *outAudio.pq_fact, 1 );
    6906             : 
    6907        2250 :             copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx );
    6908             : 
    6909        2250 :             free( tmpRotBuffer.data_fx );
    6910             :         }
    6911             :         ELSE
    6912             :         {
    6913        8000 :             copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
    6914             :         }
    6915             :         // Porting Crend_process function
    6916             :         CREND_HANDLE hCrend;
    6917       10250 :         hCrend = mcInput->crendWrapper->hCrend[0];
    6918             : 
    6919             : #ifdef FIX_1843_IO_QFACTOR_INIT
    6920       10250 :         *mcInput->crendWrapper->p_io_qfactor = exp;
    6921             : #endif
    6922             :         /* call CREND */
    6923       10250 :         IF( NE_32( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer_fx, p_tmpRendBuffer_fx, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
    6924             :         {
    6925           0 :             return error;
    6926             :         }
    6927             : 
    6928       10250 :         IF( hCrend->hReverb != NULL )
    6929             :         {
    6930           0 :             exp = sub( exp, 2 );
    6931             :         }
    6932             :     }
    6933             : 
    6934       29004 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    6935             : 
    6936       29004 :     IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
    6937             : 
    6938             :     {
    6939           0 :         return error;
    6940             :     }
    6941       29004 :     *outAudio.pq_fact = exp;
    6942       29004 :     move16();
    6943             : 
    6944       29004 :     pop_wmops();
    6945       29004 :     return IVAS_ERR_OK;
    6946             : }
    6947             : 
    6948       32000 : static ivas_error renderMcToBinauralRoom(
    6949             :     input_mc *mcInput,
    6950             :     const AUDIO_CONFIG outConfig,
    6951             :     IVAS_REND_AudioBuffer outAudio )
    6952             : {
    6953             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6954             :     AUDIO_CONFIG inConfig;
    6955             :     ivas_error error;
    6956             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    6957             :     Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
    6958             :     Word16 i;
    6959             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    6960             :     Word8 combinedOrientationEnabled;
    6961             :     Word16 subframe_idx;
    6962       32000 :     Word16 exp = *outAudio.pq_fact;
    6963       32000 :     move16();
    6964             : 
    6965      544000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6966             :     {
    6967      512000 :         p_tmpRendBuffer[i] = tmpRendBuffer[i];
    6968             :     }
    6969             : 
    6970       32000 :     push_wmops( "renderMcToBinauralRoom" );
    6971       32000 :     inConfig = mcInput->base.inConfig;
    6972       32000 :     move32();
    6973       32000 :     hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
    6974       32000 :     combinedOrientationEnabled = 0;
    6975       32000 :     move16();
    6976             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    6977       32000 :     IF( *hCombinedOrientationData != NULL )
    6978             : #else
    6979             :     IF( hCombinedOrientationData != NULL )
    6980             : #endif
    6981             :     {
    6982       16000 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    6983             :         {
    6984       16000 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    6985             :             {
    6986       16000 :                 combinedOrientationEnabled = 1;
    6987       16000 :                 move16();
    6988       16000 :                 BREAK;
    6989             :             }
    6990             :         }
    6991             :     }
    6992             : 
    6993       32000 :     test();
    6994       32000 :     test();
    6995       32000 :     test();
    6996       32000 :     test();
    6997       32000 :     test();
    6998       32000 :     IF( ( mcInput->hReverb != NULL && EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ) && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) || ( combinedOrientationEnabled && ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) ) ) ) )
    6999             :     {
    7000        5750 :         copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
    7001             : 
    7002       97750 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    7003             :         {
    7004       92000 :             Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    7005             :         }
    7006             : 
    7007        5750 :         IF( NE_32( ( error = ivas_td_binaural_renderer_ext_fx( &mcInput->tdRendWrapper, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pCombinedOrientationData, NULL, mcInput->hReverb,
    7008             :                                                                0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ),
    7009             :                    IVAS_ERR_OK ) )
    7010             :         {
    7011           0 :             return error;
    7012             :         }
    7013             : 
    7014       97750 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    7015             :         {
    7016       92000 :             Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    7017             :         }
    7018             :     }
    7019             :     ELSE
    7020             :     {
    7021             :         /* apply rotation */
    7022       26250 :         IF( combinedOrientationEnabled )
    7023             :         {
    7024       10250 :             tmpRotBuffer = mcInput->base.inputBuffer;
    7025       10250 :             tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    7026       10250 :             set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
    7027             : 
    7028       10250 :             IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev_fx[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
    7029             :                        IVAS_ERR_OK ) )
    7030             :             {
    7031           0 :                 return error;
    7032             :             }
    7033             : 
    7034       10250 :             exp = sub( *outAudio.pq_fact, 1 );
    7035             : 
    7036       10250 :             copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
    7037       10250 :             free( tmpRotBuffer.data_fx );
    7038             :         }
    7039             :         ELSE
    7040             :         {
    7041       16000 :             copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
    7042             :         }
    7043             :         // Porting Crend_process function
    7044             :         CREND_HANDLE hCrend;
    7045       26250 :         hCrend = mcInput->crendWrapper->hCrend[0];
    7046             : 
    7047             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7048       26250 :         *mcInput->crendWrapper->p_io_qfactor = exp;
    7049             : #endif
    7050             :         /* call CREND */
    7051       26250 :         IF( NE_32( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
    7052             :         {
    7053           0 :             return error;
    7054             :         }
    7055             : 
    7056       26250 :         IF( hCrend->hReverb != NULL )
    7057             :         {
    7058       10250 :             exp = sub( exp, Q2 );
    7059             :         }
    7060             :     }
    7061             : 
    7062       32000 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
    7063             : 
    7064       32000 :     IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
    7065             :     {
    7066           0 :         return error;
    7067             :     }
    7068       32000 :     *outAudio.pq_fact = exp;
    7069       32000 :     move16();
    7070             : 
    7071       32000 :     pop_wmops();
    7072       32000 :     return IVAS_ERR_OK;
    7073             : }
    7074             : 
    7075       26008 : static ivas_error renderMcCustomLsToBinauralRoom(
    7076             :     input_mc *mcInput,
    7077             :     const AUDIO_CONFIG outConfig,
    7078             :     IVAS_REND_AudioBuffer outAudio )
    7079             : {
    7080             :     Word16 i;
    7081             :     Word16 tmp;
    7082             :     Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7083             :     ivas_error error;
    7084             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    7085             :     IVAS_REND_AudioBuffer tmpMcBuffer;
    7086             :     IVAS_REND_AudioBuffer *tmpBufPtr;
    7087             :     Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
    7088             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    7089             :     Word8 combinedOrientationEnabled;
    7090             :     Word16 subframe_idx;
    7091       26008 :     Word16 exp = *outAudio.pq_fact;
    7092       26008 :     move16();
    7093       26008 :     push_wmops( "renderMcCustomLsToBinauralRoom" );
    7094       26008 :     tmpRotBuffer = outAudio; /* avoid compilation warning */
    7095             : 
    7096      442136 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    7097             :     {
    7098      416128 :         p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
    7099             :     }
    7100             : 
    7101       26008 :     hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
    7102       26008 :     combinedOrientationEnabled = 0;
    7103       26008 :     move16();
    7104             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    7105       26008 :     IF( *hCombinedOrientationData != NULL )
    7106             : #else
    7107             :     IF( hCombinedOrientationData != NULL )
    7108             : #endif
    7109             :     {
    7110       13004 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    7111             :         {
    7112       13004 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    7113             :             {
    7114       13004 :                 combinedOrientationEnabled = 1;
    7115       13004 :                 move16();
    7116       13004 :                 BREAK;
    7117             :             }
    7118             :         }
    7119             :     }
    7120             : 
    7121             :     /* apply rotation */
    7122       26008 :     IF( combinedOrientationEnabled )
    7123             :     {
    7124       13004 :         tmpRotBuffer = mcInput->base.inputBuffer;
    7125       13004 :         tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    7126       13004 :         set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
    7127             : 
    7128       13004 :         IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData, mcInput->rot_gains_prev_fx[0], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
    7129             :                    IVAS_ERR_OK ) )
    7130             :         {
    7131           0 :             return error;
    7132             :         }
    7133       13004 :         exp = sub( *outAudio.pq_fact, Q1 );
    7134             :     }
    7135             : 
    7136             :     /* intermediate conversion to 7_1_4 */
    7137       26008 :     tmpMcBuffer = mcInput->base.inputBuffer;
    7138             : 
    7139       26008 :     IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
    7140             :     {
    7141           0 :         return error;
    7142             :     }
    7143             : 
    7144       26008 :     tmpMcBuffer.config.numChannels = tmp;
    7145       26008 :     move16();
    7146       26008 :     tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
    7147       26008 :     set32_fx( tmpMcBuffer.data_fx, 0, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
    7148             : 
    7149       26008 :     IF( combinedOrientationEnabled )
    7150             :     {
    7151       13004 :         tmpBufPtr = &tmpRotBuffer;
    7152             :     }
    7153             :     ELSE
    7154             :     {
    7155       13004 :         tmpBufPtr = &mcInput->base.inputBuffer;
    7156             :     }
    7157      406136 :     FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
    7158             :     {
    7159      380128 :         renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer );
    7160             :     }
    7161       26008 :     copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
    7162             : 
    7163             :     CREND_HANDLE hCrend;
    7164       26008 :     hCrend = mcInput->crendWrapper->hCrend[0];
    7165             : 
    7166             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7167       26008 :     *mcInput->crendWrapper->p_io_qfactor = exp;
    7168             : #endif
    7169             :     /* call CREND */
    7170       26008 :     IF( NE_32( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
    7171             :     {
    7172           0 :         return error;
    7173             :     }
    7174             : 
    7175       26008 :     IF( hCrend->hReverb != NULL )
    7176             :     {
    7177       13004 :         exp = sub( exp, 2 );
    7178             :     }
    7179             : 
    7180       26008 :     accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
    7181             : 
    7182       26008 :     IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
    7183             :     {
    7184           0 :         return error;
    7185             :     }
    7186       26008 :     *outAudio.pq_fact = exp;
    7187       26008 :     move16();
    7188       26008 :     IF( combinedOrientationEnabled )
    7189             :     {
    7190       13004 :         free( tmpRotBuffer.data_fx );
    7191             :     }
    7192       26008 :     free( tmpMcBuffer.data_fx );
    7193             : 
    7194       26008 :     pop_wmops();
    7195       26008 :     return IVAS_ERR_OK;
    7196             : }
    7197             : 
    7198      196617 : static void renderMcToMc(
    7199             :     const input_mc *mcInput,
    7200             :     IVAS_REND_AudioBuffer outAudio )
    7201             : {
    7202             :     Word16 i;
    7203             :     IVAS_REND_AudioBuffer inAudio;
    7204             : 
    7205      196617 :     push_wmops( "renderMcToMc" );
    7206      196617 :     inAudio = mcInput->base.inputBuffer;
    7207             : 
    7208     1507289 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    7209             :     {
    7210     1310672 :         renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
    7211             :     }
    7212             : 
    7213      196617 :     pop_wmops();
    7214      196617 :     return;
    7215             : }
    7216             : 
    7217       75756 : static void renderMcToSba(
    7218             :     const input_mc *mcInput,
    7219             :     IVAS_REND_AudioBuffer outAudio )
    7220             : {
    7221             :     Word16 i;
    7222             :     IVAS_REND_AudioBuffer inAudio;
    7223             : 
    7224       75756 :     push_wmops( "renderMcToSba" );
    7225       75756 :     inAudio = mcInput->base.inputBuffer;
    7226             : 
    7227      591852 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    7228             :     {
    7229      516096 :         renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
    7230             :     }
    7231       75756 :     pop_wmops();
    7232       75756 :     return;
    7233             : }
    7234             : 
    7235         150 : static void renderMcToMasa(
    7236             :     input_mc *mcInput,
    7237             :     IVAS_REND_AudioBuffer outAudio )
    7238             : {
    7239         150 :     push_wmops( "renderMcToMasa" );
    7240             :     Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7241         150 :     copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
    7242         150 :     ivas_mcmasa_ana_fx( mcInput->hMcMasa, tmpRendBuffer_fx, *( outAudio.pq_fact ), mcInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, mcInput->base.inputBuffer.config.numChannels );
    7243         150 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    7244             : 
    7245         150 :     pop_wmops();
    7246         150 :     return;
    7247             : }
    7248             : 
    7249           0 : static ivas_error renderMcToSplitBinaural(
    7250             :     input_mc *mcInput,
    7251             :     const AUDIO_CONFIG outConfig,
    7252             :     IVAS_REND_AudioBuffer outAudio )
    7253             : {
    7254             :     Word16 i, j, pos_idx;
    7255             :     Word16 sf;
    7256             :     Word16 output_frame;
    7257             :     ivas_error error;
    7258             :     const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
    7259             :     const SPLIT_REND_WRAPPER *pSplitRendWrapper;
    7260             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7261             :     Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
    7262             :     Word32 tmpSplitBinauralBuffer[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
    7263             :     AUDIO_CONFIG inConfig;
    7264             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    7265             :     COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
    7266             :     COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
    7267           0 :     Word16 exp = *outAudio.pq_fact;
    7268           0 :     move16();
    7269             :     CREND_HANDLE hCrend;
    7270             :     IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
    7271             :     Word16 q_fact_orig;
    7272             : 
    7273           0 :     push_wmops( "renderMcToSplitBinaural" );
    7274           0 :     inConfig = mcInput->base.inConfig;
    7275           0 :     move32();
    7276           0 :     output_frame = mcInput->base.inputBuffer.config.numSamplesPerChannel;
    7277           0 :     move16();
    7278             : 
    7279           0 :     pSplitRendWrapper = mcInput->base.ctx.pSplitRendWrapper;
    7280           0 :     pMultiBinPoseData = &pSplitRendWrapper->multiBinPoseData;
    7281           0 :     move32();
    7282           0 :     move32();
    7283             : 
    7284           0 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    7285             :     {
    7286           0 :         p_tmpRendBuffer[i] = tmpRendBuffer[i];
    7287           0 :         move32();
    7288             :     }
    7289             : 
    7290             :     /* save current head positions */
    7291           0 :     pCombinedOrientationDataLocal = *mcInput->base.ctx.pCombinedOrientationData;
    7292           0 :     move32();
    7293           0 :     combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
    7294           0 :     move32();
    7295           0 :     IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
    7296             :     {
    7297           0 :         FOR( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
    7298             :         {
    7299           0 :             Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[0], &combinedOrientationDataLocal.Quaternions[sf] );
    7300           0 :             FOR( i = 0; i < 3; i++ )
    7301             :             {
    7302           0 :                 FOR( j = 0; j < 3; j++ )
    7303             :                 {
    7304           0 :                     combinedOrientationDataLocal.Rmat_fx[sf][i][j] = combinedOrientationDataLocal.Rmat_fx[0][i][j];
    7305           0 :                     move32();
    7306             :                 }
    7307             :             }
    7308             :         }
    7309             :     }
    7310             : 
    7311             :     /* temporary buffer for rotation in source format for CREND */
    7312           0 :     tmpRotBuffer = mcInput->base.inputBuffer;
    7313           0 :     move32();
    7314           0 :     IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
    7315             :     {
    7316           0 :         tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    7317             :     }
    7318             : 
    7319           0 :     FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
    7320             :     {
    7321           0 :         Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[i], &Quaternions_orig[i] );
    7322             :     }
    7323             : 
    7324           0 :     FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
    7325             :     {
    7326             :         /* Update head positions */
    7327           0 :         FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
    7328             :         {
    7329           0 :             Quaternions_abs.w_fx = L_negate( 12582912 ); // Q22
    7330           0 :             q_fact_orig = Quaternions_orig[i].q_fact;
    7331           0 :             modify_Quat_q_fx( &combinedOrientationDataLocal.Quaternions[i], &combinedOrientationDataLocal.Quaternions[i], Q22 );
    7332             :             /*euler*/
    7333           0 :             Quat2EulerDegree_fx( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z_fx, &Quaternions_abs.y_fx, &Quaternions_abs.x_fx );
    7334           0 :             Quaternions_abs.x_fx = L_add( Quaternions_abs.x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
    7335           0 :             Quaternions_abs.y_fx = L_add( Quaternions_abs.y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
    7336           0 :             Quaternions_abs.z_fx = L_add( Quaternions_abs.z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
    7337             : 
    7338           0 :             Euler2Quat_fx( deg2rad_fx( Quaternions_abs.x_fx ), deg2rad_fx( Quaternions_abs.y_fx ), deg2rad_fx( Quaternions_abs.z_fx ), &Quaternions_abs );
    7339             : 
    7340           0 :             modify_Quat_q_fx( &Quaternions_abs, &Quaternions_abs, q_fact_orig );
    7341             : 
    7342           0 :             Copy_Quat_fx( &Quaternions_abs, &combinedOrientationDataLocal.Quaternions[i] );
    7343           0 :             QuatToRotMat_fx( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat_fx[i] );
    7344           0 :             modify_Rmat_q_fx( combinedOrientationDataLocal.Rmat_fx[i], combinedOrientationDataLocal.Rmat_fx[i], sub( shl( q_fact_orig, 1 ), 32 ), Q30 );
    7345             :         }
    7346             : 
    7347           0 :         IF( EQ_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
    7348             :         {
    7349             :             /* tdrend processing overview:
    7350             :              *  1. copy from inputBuffer to tmpRendBuffer
    7351             :              *  2. td_binaural_renderer_ext: inplace processing in tmpRendBuffer
    7352             :              *  3. copy from tmpRendBuffer to tmpSplitBinBuffer
    7353             :              *  4. LFE mixing
    7354             :              *  5. tmpSplitBinBuffer accumulated to outBuffer */
    7355             : 
    7356             :             /* copy input to tdrend input/output buffer */
    7357           0 :             copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
    7358             : 
    7359             :             /* perform rotation in source format to tmpRotBuffer */
    7360           0 :             pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
    7361             : 
    7362           0 :             FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    7363             :             {
    7364           0 :                 Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    7365             :             }
    7366             :             /* Render */
    7367           0 :             IF( ( error = ivas_td_binaural_renderer_ext_fx( ( 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, &exp ) ) != IVAS_ERR_OK )
    7368             :             {
    7369           0 :                 return error;
    7370             :             }
    7371           0 :             FOR( i = 0; i < BINAURAL_CHANNELS; ++i )
    7372             :             {
    7373           0 :                 Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    7374             :             }
    7375             : 
    7376             :             /* Copy rendered audio to tmp storage buffer. Copying directly to output would
    7377             :              * overwrite original audio, which is still needed for rendering next head pose. */
    7378           0 :             Copy32( tmpRendBuffer[0], tmpSplitBinauralBuffer[i_mult( 2, pos_idx )], output_frame );
    7379           0 :             Copy32( tmpRendBuffer[1], tmpSplitBinauralBuffer[add( i_mult( 2, pos_idx ), 1 )], output_frame );
    7380             :         }
    7381             :         ELSE
    7382             :         {
    7383           0 :             hCrend = mcInput->crendWrapper->hCrend[0];
    7384             :             /* crend processing overview:
    7385             :              *  1. rotateFrameMc: inputBuffer to tmpRotBuffer
    7386             :              *  2. crend_process: tmpRotBuffer to tmpRendBuffer
    7387             :              *  3. copy from tmpRendBuffer to tmpSplitBinBuffer
    7388             :              *  4. LFE mixing
    7389             :              *  5. tmpSplitBinBuffer accumulated to outBuffer */
    7390             : 
    7391             : 
    7392             :             /* copy input for in-place rotation */
    7393           0 :             set32_fx( tmpRotBuffer.data_fx, 0, i_mult( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
    7394             : 
    7395             :             /* perform rotation in source format to tmpRotBuffer */
    7396           0 :             pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
    7397           0 :             IF( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, mcInput->rot_gains_prev_fx[pos_idx], mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ) != IVAS_ERR_OK )
    7398             :             {
    7399           0 :                 return error;
    7400             :             }
    7401           0 :             IF( EQ_16( pos_idx, 0 ) )
    7402             :             {
    7403           0 :                 exp = sub( *outAudio.pq_fact, 1 );
    7404             :             }
    7405             : 
    7406           0 :             copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
    7407             : 
    7408             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7409           0 :             *mcInput->crendWrapper->p_io_qfactor = exp;
    7410             : #endif
    7411             :             /* call CREND (rotation already performed) */
    7412           0 :             IF( NE_32( ( error = ivas_rend_crendProcessSubframe( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpRendBuffer, p_tmpRendBuffer, mcInput->base.inputBuffer.config.numSamplesPerChannel, *mcInput->base.ctx.pOutSampleRate, pos_idx ) ), IVAS_ERR_OK ) )
    7413             :             {
    7414           0 :                 return error;
    7415             :             }
    7416             : 
    7417           0 :             IF( EQ_16( pos_idx, 0 ) )
    7418             :             {
    7419           0 :                 IF( hCrend->hReverb != NULL )
    7420             :                 {
    7421           0 :                     exp = sub( exp, 2 );
    7422             :                 }
    7423             :             }
    7424             : 
    7425             :             /* Copy rendererd audio to tmp storage buffer, Copying directly to output would
    7426             :              * overwrite original audio, which is still needed for rendering next head pose. */
    7427           0 :             Copy32( tmpRendBuffer[0], tmpSplitBinauralBuffer[i_mult( 2, pos_idx )], output_frame );
    7428           0 :             Copy32( tmpRendBuffer[1], tmpSplitBinauralBuffer[add( i_mult( 2, pos_idx ), 1 )], output_frame );
    7429             :         }
    7430             : 
    7431             :         /* restore original headrotation data */
    7432           0 :         FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
    7433             :         {
    7434           0 :             Copy_Quat_fx( &Quaternions_orig[i], &combinedOrientationDataLocal.Quaternions[i] );
    7435             :         }
    7436             :     }
    7437             : 
    7438           0 :     IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_5_1 ) && NE_32( inConfig, IVAS_AUDIO_CONFIG_7_1 ) )
    7439             :     {
    7440             :         /* free temporary buffer for rotation in source format for CREND */
    7441           0 :         free( tmpRotBuffer.data_fx );
    7442             :     }
    7443             : 
    7444           0 :     accumulate2dArrayToBuffer_fx( tmpSplitBinauralBuffer, &outAudio );
    7445             : 
    7446           0 :     IF( ( error = renderLfeToBinaural_fx( mcInput, outConfig, outAudio, *outAudio.pq_fact, exp ) ) != IVAS_ERR_OK )
    7447             :     {
    7448           0 :         return error;
    7449             :     }
    7450           0 :     *outAudio.pq_fact = exp;
    7451             : 
    7452           0 :     pop_wmops();
    7453           0 :     return IVAS_ERR_OK;
    7454             : }
    7455             : 
    7456             : 
    7457      359535 : static ivas_error renderInputMc(
    7458             :     input_mc *mcInput,
    7459             :     const AUDIO_CONFIG outConfig,
    7460             :     IVAS_REND_AudioBuffer outAudio )
    7461             : {
    7462             :     ivas_error error;
    7463             :     IVAS_REND_AudioBuffer inAudio;
    7464      359535 :     error = IVAS_ERR_OK;
    7465      359535 :     move32();
    7466             : 
    7467      359535 :     inAudio = mcInput->base.inputBuffer;
    7468             : 
    7469      359535 :     IF( NE_32( mcInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
    7470             :     {
    7471           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" );
    7472             :     }
    7473      359535 :     mcInput->base.numNewSamplesPerChannel = 0;
    7474      359535 :     move32();
    7475      359535 :     v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
    7476      359535 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 ); // reducing the Q by 1 compensating for the v_mult_fixed done
    7477      359535 :     move16();
    7478             :     /* set combined orientation subframe info to start info */
    7479      359535 :     ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
    7480             : 
    7481      359535 :     SWITCH( getAudioConfigType( outConfig ) )
    7482             :     {
    7483      196617 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    7484      196617 :             renderMcToMc( mcInput, outAudio );
    7485      196617 :             BREAK;
    7486       75756 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    7487       75756 :             renderMcToSba( mcInput, outAudio );
    7488       75756 :             BREAK;
    7489       87012 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    7490             :             SWITCH( outConfig )
    7491             :             {
    7492       29004 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    7493       29004 :                     error = renderMcToBinaural( mcInput, outConfig, outAudio );
    7494       29004 :                     BREAK;
    7495       58008 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    7496             :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    7497       58008 :                     IF( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
    7498             :                     {
    7499       26008 :                         error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
    7500             :                     }
    7501             :                     ELSE
    7502             :                     {
    7503       32000 :                         error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
    7504             :                     }
    7505       58008 :                     BREAK;
    7506           0 :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
    7507             :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
    7508           0 :                     error = renderMcToSplitBinaural( mcInput, outConfig, outAudio );
    7509           0 :                     break;
    7510           0 :                 default:
    7511           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    7512             :             }
    7513       87012 :             BREAK;
    7514         150 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    7515         150 :             renderMcToMasa( mcInput, outAudio );
    7516         150 :             BREAK;
    7517           0 :         default:
    7518           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    7519             :     }
    7520      359535 :     return error;
    7521             : }
    7522             : 
    7523             : 
    7524     1126140 : static ivas_error renderActiveInputsMc(
    7525             :     IVAS_REND_HANDLE hIvasRend,
    7526             :     IVAS_REND_AudioBuffer outAudio )
    7527             : {
    7528             :     Word16 i;
    7529             :     input_mc *pCurrentInput;
    7530             :     ivas_error error;
    7531     2252280 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMc ); i < RENDERER_MAX_MC_INPUTS; ( ++i, ++pCurrentInput ) )
    7532             :     {
    7533     1126140 :         IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    7534             :         {
    7535             :             /* Skip inactive inputs */
    7536      766605 :             CONTINUE;
    7537             :         }
    7538             : 
    7539      359535 :         *outAudio.pq_fact = outAudio.q_factor;
    7540      359535 :         move16();
    7541      359535 :         IF( NE_32( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    7542             :         {
    7543           0 :             return error;
    7544             :         }
    7545             :     }
    7546             : 
    7547     1126140 :     return IVAS_ERR_OK;
    7548             : }
    7549             : 
    7550             : 
    7551      115801 : static void renderSbaToMc(
    7552             :     const input_sba *sbaInput,
    7553             :     IVAS_REND_AudioBuffer outAudio )
    7554             : {
    7555             :     Word16 i;
    7556             :     IVAS_REND_AudioBuffer inAudio;
    7557             : 
    7558      115801 :     push_wmops( "renderSbaToMc" );
    7559      115801 :     inAudio = sbaInput->base.inputBuffer;
    7560             : 
    7561     1225294 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    7562             :     {
    7563     1109493 :         renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
    7564             :     }
    7565             : 
    7566      115801 :     pop_wmops();
    7567      115801 :     return;
    7568             : }
    7569             : 
    7570             : 
    7571       45768 : static void renderSbaToSba(
    7572             :     const input_sba *sbaInput,
    7573             :     IVAS_REND_AudioBuffer outAudio )
    7574             : {
    7575             :     Word16 i;
    7576             :     IVAS_REND_AudioBuffer inAudio;
    7577             : 
    7578       45768 :     push_wmops( "renderSbaToSba" );
    7579       45768 :     inAudio = sbaInput->base.inputBuffer;
    7580             : 
    7581      483942 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    7582             :     {
    7583      438174 :         renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
    7584             :     }
    7585             : 
    7586       45768 :     pop_wmops();
    7587       45768 :     return;
    7588             : }
    7589             : 
    7590             : 
    7591           0 : static ivas_error renderSbaToMultiBinaural(
    7592             :     input_sba *sbaInput,
    7593             :     const AUDIO_CONFIG outConfig,
    7594             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7595             :     Word32 out[][L_FRAME48k],
    7596             :     const Word16 *pq_fact )
    7597             : #else
    7598             :     Word32 out[][L_FRAME48k] )
    7599             : #endif
    7600             : {
    7601             :     Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7602             :     Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
    7603             :     Word16 sf;
    7604             :     Word16 i, j, pos_idx;
    7605             :     COMBINED_ORIENTATION_DATA combinedOrientationDataLocal;
    7606             :     COMBINED_ORIENTATION_HANDLE pCombinedOrientationDataLocal;
    7607             :     ivas_error error;
    7608             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    7609             :     const MULTI_BIN_REND_POSE_DATA *pMultiBinPoseData;
    7610             : 
    7611           0 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    7612             :     {
    7613           0 :         p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
    7614           0 :         move32();
    7615             :     }
    7616           0 :     push_wmops( "renderSbaToMultiBinaural" );
    7617           0 :     pMultiBinPoseData = &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData;
    7618           0 :     move32();
    7619             : 
    7620           0 :     pCombinedOrientationDataLocal = *sbaInput->base.ctx.pCombinedOrientationData;
    7621           0 :     combinedOrientationDataLocal = *pCombinedOrientationDataLocal;
    7622           0 :     move32();
    7623           0 :     move32();
    7624             : 
    7625           0 :     IF( EQ_32( pMultiBinPoseData->poseCorrectionMode, ISAR_SPLIT_REND_POSE_CORRECTION_MODE_CLDFB ) )
    7626             :     {
    7627           0 :         FOR( sf = 1; sf < combinedOrientationDataLocal.num_subframes; ++sf )
    7628             :         {
    7629           0 :             Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[0], &combinedOrientationDataLocal.Quaternions[sf] );
    7630           0 :             FOR( i = 0; i < 3; i++ )
    7631             :             {
    7632           0 :                 FOR( j = 0; j < 3; j++ )
    7633             :                 {
    7634           0 :                     combinedOrientationDataLocal.Rmat_fx[sf][i][j] = combinedOrientationDataLocal.Rmat_fx[0][i][j];
    7635           0 :                     move32();
    7636             :                 }
    7637             :             }
    7638             :         }
    7639             :     }
    7640             : 
    7641           0 :     tmpRotBuffer = sbaInput->base.inputBuffer;
    7642           0 :     tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    7643             : 
    7644           0 :     FOR( pos_idx = 0; pos_idx < pMultiBinPoseData->num_poses; pos_idx++ )
    7645             :     {
    7646             :         IVAS_QUATERNION Quaternions_orig[MAX_PARAM_SPATIAL_SUBFRAMES], Quaternions_abs;
    7647             :         Word16 q_fact_orig;
    7648           0 :         FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
    7649             :         {
    7650           0 :             Copy_Quat_fx( &combinedOrientationDataLocal.Quaternions[i], &Quaternions_orig[i] );
    7651             : 
    7652           0 :             Quaternions_abs.w_fx = L_negate( 12582912 ); // Q22
    7653           0 :             q_fact_orig = combinedOrientationDataLocal.Quaternions[i].q_fact;
    7654           0 :             modify_Quat_q_fx( &combinedOrientationDataLocal.Quaternions[i], &combinedOrientationDataLocal.Quaternions[i], Q22 );
    7655             :             /*euler*/
    7656           0 :             Quat2EulerDegree_fx( combinedOrientationDataLocal.Quaternions[i], &Quaternions_abs.z_fx, &Quaternions_abs.y_fx, &Quaternions_abs.x_fx );
    7657           0 :             Quaternions_abs.x_fx = L_add( Quaternions_abs.x_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][0] );
    7658           0 :             Quaternions_abs.y_fx = L_add( Quaternions_abs.y_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][1] );
    7659           0 :             Quaternions_abs.z_fx = L_add( Quaternions_abs.z_fx, pMultiBinPoseData->relative_head_poses_fx[pos_idx][2] );
    7660             : 
    7661           0 :             Euler2Quat_fx( deg2rad_fx( Quaternions_abs.x_fx ), deg2rad_fx( Quaternions_abs.y_fx ), deg2rad_fx( Quaternions_abs.z_fx ), &Quaternions_abs );
    7662             : 
    7663           0 :             modify_Quat_q_fx( &Quaternions_abs, &Quaternions_abs, q_fact_orig );
    7664             : 
    7665           0 :             Copy_Quat_fx( &Quaternions_abs, &combinedOrientationDataLocal.Quaternions[i] );
    7666           0 :             QuatToRotMat_fx( combinedOrientationDataLocal.Quaternions[i], combinedOrientationDataLocal.Rmat_fx[i] );
    7667           0 :             modify_Rmat_q_fx( combinedOrientationDataLocal.Rmat_fx[i], combinedOrientationDataLocal.Rmat_fx[i], sub( shl( q_fact_orig, 1 ), 32 ), Q30 );
    7668             :         }
    7669             : 
    7670             :         /* copy input for in-place rotation */
    7671           0 :         Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, tmpRotBuffer.config.numChannels * tmpRotBuffer.config.numSamplesPerChannel );
    7672             : 
    7673           0 :         pCombinedOrientationDataLocal = &combinedOrientationDataLocal;
    7674             : 
    7675           0 :         IF( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, &pCombinedOrientationDataLocal, sbaInput->rot_gains_prev_fx[pos_idx], tmpRotBuffer ) ) != IVAS_ERR_OK )
    7676             :         {
    7677           0 :             return error;
    7678             :         }
    7679             : 
    7680           0 :         copyBufferTo2dArray_fx( tmpRotBuffer, tmpCrendBuffer );
    7681             : 
    7682           0 :         assert( sbaInput->crendWrapper->hCrend[0]->hReverb == NULL );
    7683             : 
    7684             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7685           0 :         *sbaInput->crendWrapper->p_io_qfactor = *pq_fact;
    7686             : #endif
    7687             :         /* call CREND */
    7688           0 :         IF( NE_32( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, pos_idx ) ), IVAS_ERR_OK ) )
    7689             :         {
    7690           0 :             return error;
    7691             :         }
    7692             : 
    7693           0 :         FOR( i = 0; i < combinedOrientationDataLocal.num_subframes; i++ )
    7694             :         {
    7695           0 :             Copy_Quat_fx( &Quaternions_orig[i], &combinedOrientationDataLocal.Quaternions[i] );
    7696             :         }
    7697             : 
    7698             :         /* move to output */
    7699           0 :         FOR( i = 0; i < BINAURAL_CHANNELS; i++ )
    7700             :         {
    7701           0 :             Copy32( tmpCrendBuffer[i], out[pos_idx * BINAURAL_CHANNELS + i], tmpRotBuffer.config.numSamplesPerChannel );
    7702             :         }
    7703             :     }
    7704             : 
    7705           0 :     free( tmpRotBuffer.data_fx );
    7706             : 
    7707           0 :     pop_wmops();
    7708           0 :     return IVAS_ERR_OK;
    7709             : }
    7710             : 
    7711             : 
    7712           0 : static ivas_error renderSbaToMultiBinauralCldfb(
    7713             :     input_sba *sbaInput,
    7714             :     Word32 Cldfb_Out_Real[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
    7715             :     Word32 Cldfb_Out_Imag[][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX],
    7716             :     const Word16 low_res_pre_rend_rot,
    7717             :     const Word16 num_subframes,
    7718             :     const Word16 Q_in )
    7719             : {
    7720             :     Word32 Cldfb_RealBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    7721             :     Word32 Cldfb_ImagBuffer[MAX_OUTPUT_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    7722             : 
    7723           0 :     copyBufferToCLDFBarray_fx( sbaInput->base.inputBuffer, Cldfb_RealBuffer, Cldfb_ImagBuffer );
    7724             : 
    7725           0 :     ivas_rend_CldfbMultiBinRendProcess( sbaInput->cldfbRendWrapper.hCldfbRend, sbaInput->base.ctx.pCombinedOrientationData, &sbaInput->base.ctx.pSplitRendWrapper->multiBinPoseData,
    7726             :                                         Cldfb_RealBuffer, Cldfb_ImagBuffer, Cldfb_Out_Real, Cldfb_Out_Imag, low_res_pre_rend_rot, num_subframes, Q_in );
    7727             : 
    7728           0 :     return IVAS_ERR_OK;
    7729             : }
    7730             : 
    7731             : 
    7732           0 : static ivas_error renderSbaToSplitBinaural(
    7733             :     input_sba *sbaInput,
    7734             :     const AUDIO_CONFIG outConfig,
    7735             :     IVAS_REND_AudioBuffer outAudio )
    7736             : {
    7737             :     Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7738             :     ivas_error error;
    7739             :     Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    7740             :     Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    7741             :     Word16 low_res_pre_rend_rot;
    7742             : 
    7743           0 :     low_res_pre_rend_rot = 1;
    7744             : 
    7745           0 :     push_wmops( "renderSbaToSplitBinaural" );
    7746             : 
    7747           0 :     IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
    7748             :     {
    7749           0 :         if ( ( error = renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, low_res_pre_rend_rot,
    7750           0 :                                                       getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ), *outAudio.pq_fact ) ) != IVAS_ERR_OK )
    7751             :         {
    7752           0 :             return error;
    7753             :         }
    7754             : 
    7755           0 :         accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
    7756             :     }
    7757             :     else
    7758             :     {
    7759             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7760           0 :         IF( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer, outAudio.pq_fact ) ) != IVAS_ERR_OK )
    7761             : #else
    7762             :         IF( ( error = renderSbaToMultiBinaural( sbaInput, outConfig, tmpCrendBuffer ) ) != IVAS_ERR_OK )
    7763             : #endif
    7764             :         {
    7765           0 :             return error;
    7766             :         }
    7767             : 
    7768           0 :         IF( sbaInput->crendWrapper->hCrend[0]->hReverb != NULL )
    7769             :         {
    7770           0 :             *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
    7771           0 :             move16();
    7772             :         }
    7773             : 
    7774           0 :         accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
    7775             :     }
    7776             : 
    7777           0 :     pop_wmops();
    7778           0 :     return IVAS_ERR_OK;
    7779             : }
    7780             : 
    7781             : 
    7782       30012 : static ivas_error renderSbaToBinaural(
    7783             :     input_sba *sbaInput,
    7784             :     const AUDIO_CONFIG outConfig,
    7785             :     IVAS_REND_AudioBuffer outAudio )
    7786             : {
    7787             :     ivas_error error;
    7788             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    7789             :     Word16 i;
    7790             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    7791             :     Word8 combinedOrientationEnabled;
    7792             :     Word16 subframe_idx;
    7793             :     Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7794             :     Word32 *output_fx[MAX_OUTPUT_CHANNELS];
    7795             : 
    7796       30012 :     push_wmops( "renderSbaToBinaural" );
    7797             : 
    7798       30012 :     IF( EQ_32( sbaInput->base.ctx.hhRendererConfig[0]->split_rend_config.rendererSelection, ISAR_SPLIT_REND_RENDERER_SELECTION_FASTCONV ) )
    7799             :     {
    7800             :         Word32 Cldfb_RealBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    7801             :         Word32 Cldfb_ImagBuffer_Binaural[BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    7802             : 
    7803           0 :         IF( ( error = renderSbaToMultiBinauralCldfb( sbaInput, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, 0,
    7804             :                                                      getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ), *outAudio.pq_fact ) ) != IVAS_ERR_OK )
    7805             :         {
    7806           0 :             return error;
    7807             :         }
    7808             : 
    7809           0 :         accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
    7810             :     }
    7811             :     ELSE
    7812             :     {
    7813      510204 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    7814             :         {
    7815      480192 :             output_fx[i] = output_buffer_fx[i];
    7816      480192 :             move32();
    7817             :         }
    7818             : 
    7819       30012 :         hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
    7820       30012 :         combinedOrientationEnabled = 0;
    7821       30012 :         move16();
    7822             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    7823       30012 :         IF( *hCombinedOrientationData != NULL )
    7824             : #else
    7825             :         IF( hCombinedOrientationData != NULL )
    7826             : #endif
    7827             :         {
    7828       15006 :             FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    7829             :             {
    7830       15006 :                 IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    7831             :                 {
    7832       15006 :                     combinedOrientationEnabled = 1;
    7833       15006 :                     move16();
    7834       15006 :                     BREAK;
    7835             :                 }
    7836             :             }
    7837             :         }
    7838             : 
    7839             :         /* apply rotation */
    7840       30012 :         IF( combinedOrientationEnabled )
    7841             :         {
    7842       15006 :             tmpRotBuffer = sbaInput->base.inputBuffer;
    7843             : 
    7844       15006 :             tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    7845             : 
    7846             :             /* copy input for in-place rotation */
    7847       15006 :             Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
    7848             : 
    7849       15006 :             IF( NE_16( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx[0], tmpRotBuffer ) ),
    7850             :                        IVAS_ERR_OK ) )
    7851             :             {
    7852           0 :                 return error;
    7853             :             }
    7854             : 
    7855       15006 :             copyBufferTo2dArray_fx( tmpRotBuffer, output_buffer_fx );
    7856       15006 :             free( tmpRotBuffer.data_fx );
    7857             :         }
    7858             :         ELSE
    7859             :         {
    7860       15006 :             copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, output_buffer_fx );
    7861             :         }
    7862             : 
    7863             :         CREND_HANDLE hCrend;
    7864       30012 :         hCrend = sbaInput->crendWrapper->hCrend[0];
    7865             : 
    7866             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7867       30012 :         *sbaInput->crendWrapper->p_io_qfactor = *outAudio.pq_fact;
    7868             : #endif
    7869             :         /* call CREND */
    7870       30012 :         IF( NE_32( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, NULL, output_fx, output_fx, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
    7871             :         {
    7872           0 :             return error;
    7873             :         }
    7874             : 
    7875       30012 :         IF( hCrend->hReverb != NULL )
    7876             :         {
    7877           0 :             *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
    7878           0 :             move16();
    7879             :         }
    7880             : 
    7881       30012 :         accumulate2dArrayToBuffer_fx( output_buffer_fx, &outAudio );
    7882             :     }
    7883             : 
    7884       30012 :     pop_wmops();
    7885       30012 :     return IVAS_ERR_OK;
    7886             : }
    7887             : 
    7888             : 
    7889       60024 : static ivas_error renderSbaToBinauralRoom(
    7890             :     input_sba *sbaInput,
    7891             :     const AUDIO_CONFIG outConfig,
    7892             :     IVAS_REND_AudioBuffer outAudio )
    7893             : {
    7894             :     Word16 i;
    7895             :     Word16 tmp;
    7896             :     Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    7897             :     ivas_error error;
    7898             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    7899             :     IVAS_REND_AudioBuffer tmpMcBuffer;
    7900             :     IVAS_REND_AudioBuffer *tmpBufPtr;
    7901             :     Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
    7902             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    7903             :     Word8 combinedOrientationEnabled;
    7904             :     Word16 subframe_idx;
    7905             : 
    7906       60024 :     tmpRotBuffer = outAudio; /* avoid compilation warning */
    7907       60024 :     push_wmops( "renderSbaToBinauralRoom" );
    7908             :     Word16 nchan_out;
    7909             :     CREND_HANDLE hCrend;
    7910       60024 :     hCrend = sbaInput->crendWrapper->hCrend[0];
    7911             : 
    7912       60024 :     IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ), IVAS_ERR_OK ) )
    7913             :     {
    7914           0 :         return error;
    7915             :     }
    7916             : 
    7917     1020408 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    7918             :     {
    7919      960384 :         p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
    7920             :     }
    7921             : 
    7922       60024 :     hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
    7923       60024 :     combinedOrientationEnabled = 0;
    7924       60024 :     move16();
    7925             : #ifdef FIX_1135_EXT_RENDERER_HANDLES
    7926       60024 :     IF( *hCombinedOrientationData != NULL )
    7927             : #else
    7928             :     IF( hCombinedOrientationData != NULL )
    7929             : #endif
    7930             :     {
    7931       30012 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    7932             :         {
    7933       30012 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    7934             :             {
    7935       30012 :                 combinedOrientationEnabled = 1;
    7936       30012 :                 move16();
    7937       30012 :                 BREAK;
    7938             :             }
    7939             :         }
    7940             :     }
    7941             : 
    7942             :     /* apply rotation */
    7943       60024 :     IF( combinedOrientationEnabled )
    7944             :     {
    7945       30012 :         tmpRotBuffer = sbaInput->base.inputBuffer;
    7946       30012 :         tmpRotBuffer.data_fx = malloc( imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) * sizeof( Word32 ) );
    7947             : 
    7948             :         /* copy input for in-place rotation */
    7949       30012 :         Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
    7950             : 
    7951       30012 :         IF( NE_32( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData, sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx[0], tmpRotBuffer ) ),
    7952             :                    IVAS_ERR_OK ) )
    7953             :         {
    7954           0 :             return error;
    7955             :         }
    7956             :     }
    7957             : 
    7958             :     /* intermediate rendering to 7_1_4 */
    7959       60024 :     tmpMcBuffer = sbaInput->base.inputBuffer;
    7960             : 
    7961       60024 :     IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
    7962             :     {
    7963           0 :         return error;
    7964             :     }
    7965             : 
    7966       60024 :     tmpMcBuffer.config.numChannels = tmp;
    7967       60024 :     move16();
    7968       60024 :     tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) );
    7969       60024 :     set32_fx( tmpMcBuffer.data_fx, 0, i_mult( tmpMcBuffer.config.numChannels, tmpMcBuffer.config.numSamplesPerChannel ) );
    7970             : 
    7971       60024 :     IF( combinedOrientationEnabled )
    7972             :     {
    7973       30012 :         tmpBufPtr = &tmpRotBuffer;
    7974             :     }
    7975             :     ELSE
    7976             :     {
    7977       30012 :         tmpBufPtr = &sbaInput->base.inputBuffer;
    7978             :     }
    7979      640256 :     FOR( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
    7980             :     {
    7981      580232 :         renderBufferChannel_fx( *tmpBufPtr, i, sbaInput->hoaDecMtx_fx[i], tmpMcBuffer );
    7982             :     }
    7983       60024 :     copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
    7984             : 
    7985             : #ifdef FIX_1843_IO_QFACTOR_INIT
    7986       60024 :     *sbaInput->crendWrapper->p_io_qfactor = *outAudio.pq_fact;
    7987             : #endif
    7988             :     /* call CREND */
    7989       60024 :     IF( NE_32( ( error = ivas_rend_crendProcessSubframe( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL, NULL, p_tmpCrendBuffer, p_tmpCrendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, *sbaInput->base.ctx.pOutSampleRate, 0 ) ), IVAS_ERR_OK ) )
    7990             :     {
    7991           0 :         return error;
    7992             :     }
    7993             : 
    7994       60024 :     IF( hCrend->hReverb != NULL )
    7995             :     {
    7996       30012 :         *outAudio.pq_fact = sub( *outAudio.pq_fact, 2 );
    7997       30012 :         move16();
    7998             :     }
    7999             : 
    8000       60024 :     accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
    8001             : 
    8002       60024 :     IF( combinedOrientationEnabled )
    8003             :     {
    8004       30012 :         free( tmpRotBuffer.data_fx );
    8005             :     }
    8006       60024 :     free( tmpMcBuffer.data_fx );
    8007             : 
    8008       60024 :     pop_wmops();
    8009       60024 :     return IVAS_ERR_OK;
    8010             : }
    8011             : 
    8012             : 
    8013         150 : static void renderSbaToMasa(
    8014             :     input_sba *sbaInput,
    8015             :     IVAS_REND_AudioBuffer outAudio )
    8016             : {
    8017             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    8018             : 
    8019         150 :     push_wmops( "renderMcToMasa" );
    8020         150 :     copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, tmpRendBuffer );
    8021         150 :     ivas_dirac_ana_fx( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, *outAudio.pq_fact );
    8022         150 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
    8023             : 
    8024         150 :     pop_wmops();
    8025         150 :     return;
    8026             : }
    8027             : 
    8028             : 
    8029      251755 : static ivas_error renderInputSba(
    8030             :     input_sba *sbaInput,
    8031             :     const AUDIO_CONFIG outConfig,
    8032             :     IVAS_REND_AudioBuffer outAudio )
    8033             : {
    8034             :     ivas_error error;
    8035             :     IVAS_REND_AudioBuffer inAudio;
    8036             :     Word16 cldfb2tdShift;
    8037      251755 :     error = IVAS_ERR_OK;
    8038      251755 :     move32();
    8039      251755 :     inAudio = sbaInput->base.inputBuffer;
    8040             : 
    8041      251755 :     cldfb2tdShift = outAudio.config.is_cldfb ? 1 : 0;
    8042      251755 :     IF( NE_32( L_shl( sbaInput->base.numNewSamplesPerChannel, cldfb2tdShift ), outAudio.config.numSamplesPerChannel ) &&
    8043             :         NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    8044             :     {
    8045           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" );
    8046             :     }
    8047      251755 :     sbaInput->base.numNewSamplesPerChannel = 0;
    8048      251755 :     move32();
    8049      251755 :     *outAudio.pq_fact = outAudio.q_factor;
    8050      251755 :     move16();
    8051             :     /* Apply input gain to new audio */
    8052      251755 :     v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
    8053      251755 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
    8054      251755 :     move16();
    8055             : 
    8056             :     /* set combined orientation subframe info to start info */
    8057      251755 :     ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
    8058             : 
    8059      251755 :     SWITCH( getAudioConfigType( outConfig ) )
    8060             :     {
    8061      115801 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    8062      115801 :             renderSbaToMc( sbaInput, outAudio );
    8063      115801 :             BREAK;
    8064       45768 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    8065       45768 :             renderSbaToSba( sbaInput, outAudio );
    8066       45768 :             BREAK;
    8067       90036 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    8068             :             SWITCH( outConfig )
    8069             :             {
    8070           0 :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
    8071             :                 case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
    8072           0 :                     error = renderSbaToSplitBinaural( sbaInput, outConfig, outAudio );
    8073           0 :                     break;
    8074       30012 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    8075       30012 :                     error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
    8076       30012 :                     BREAK;
    8077       60024 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    8078             :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    8079       60024 :                     error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
    8080       60024 :                     BREAK;
    8081           0 :                 default:
    8082           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    8083             :             }
    8084       90036 :             BREAK;
    8085         150 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    8086         150 :             renderSbaToMasa( sbaInput, outAudio );
    8087         150 :             BREAK;
    8088           0 :         default:
    8089           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    8090             :     }
    8091             : 
    8092      251755 :     return error;
    8093             : }
    8094             : 
    8095             : 
    8096     1126140 : static ivas_error renderActiveInputsSba(
    8097             :     IVAS_REND_HANDLE hIvasRend,
    8098             :     IVAS_REND_AudioBuffer outAudio )
    8099             : {
    8100             :     Word16 i;
    8101             :     input_sba *pCurrentInput;
    8102             :     ivas_error error;
    8103             : 
    8104     2252280 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsSba ); i < RENDERER_MAX_SBA_INPUTS; ( ++i, ++pCurrentInput ) )
    8105             :     {
    8106     1126140 :         IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8107             :         {
    8108             :             /* Skip inactive inputs */
    8109      874385 :             CONTINUE;
    8110             :         }
    8111      251755 :         *outAudio.pq_fact = outAudio.q_factor;
    8112      251755 :         move16();
    8113      251755 :         IF( NE_32( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    8114             :         {
    8115           0 :             return error;
    8116             :         }
    8117             :     }
    8118             : 
    8119     1126140 :     return IVAS_ERR_OK;
    8120             : }
    8121             : 
    8122             : 
    8123       17250 : static void copyMasaMetadataToDiracRenderer_fx(
    8124             :     MASA_METADATA_FRAME *meta,
    8125             :     SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
    8126             :     const Word16 maxBin )
    8127             : {
    8128             :     Word16 band, sf, bin;
    8129             :     Word16 meta_write_index;
    8130             : 
    8131       17250 :     hSpatParamRendCom->numParametricDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
    8132       17250 :     hSpatParamRendCom->numSimultaneousDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
    8133       17250 :     move16();
    8134       17250 :     move16();
    8135             : 
    8136       86250 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    8137             :     {
    8138       69000 :         meta_write_index = add( hSpatParamRendCom->dirac_bs_md_write_idx, sf ) % hSpatParamRendCom->dirac_md_buffer_length;
    8139             : 
    8140     1725000 :         FOR( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
    8141             :         {
    8142     5796000 :             FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
    8143             :             {
    8144     4140000 :                 hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    8145     4140000 :                 move16();
    8146     4140000 :                 hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    8147     4140000 :                 move16();
    8148     4140000 :                 hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band];
    8149     4140000 :                 move32();
    8150     4140000 :                 hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( ONE_IN_Q30, meta->directional_meta[0].energy_ratio_fx[sf][band] );
    8151     4140000 :                 move32();
    8152     4140000 :                 hSpatParamRendCom->spreadCoherence_fx[meta_write_index][bin] = meta->directional_meta[0].spread_coherence_fx[sf][band];
    8153     4140000 :                 move16();
    8154     4140000 :                 hSpatParamRendCom->surroundingCoherence_fx[meta_write_index][bin] = meta->common_meta.surround_coherence_fx[sf][band];
    8155     4140000 :                 move16();
    8156             : 
    8157     4140000 :                 IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) )
    8158             :                 {
    8159     2160000 :                     hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    8160     2160000 :                     move16();
    8161     2160000 :                     hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    8162     2160000 :                     move16();
    8163     2160000 :                     hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band];
    8164     2160000 :                     move32();
    8165     2160000 :                     hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin], meta->directional_meta[1].energy_ratio_fx[sf][band] );
    8166     2160000 :                     move32();
    8167     2160000 :                     hSpatParamRendCom->spreadCoherence2_fx[meta_write_index][bin] = meta->directional_meta[1].spread_coherence_fx[sf][band];
    8168     2160000 :                     move16();
    8169             :                 }
    8170             :             }
    8171             :         }
    8172             :     }
    8173             : 
    8174       17250 :     hSpatParamRendCom->dirac_bs_md_write_idx = add( hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
    8175       17250 :     move16();
    8176             : 
    8177       17250 :     return;
    8178             : }
    8179             : 
    8180             : 
    8181         150 : static void renderMasaToMasa(
    8182             :     input_masa *masaInput,
    8183             :     IVAS_REND_AudioBuffer outAudio )
    8184             : {
    8185             :     Word16 sf, band, dir, numDirs;
    8186             :     Word32 ratioSum_fx; /* Q30 */
    8187             :     MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
    8188             :     MASA_METADATA_FRAME *inMeta;
    8189             :     Word32 tmpBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    8190             :     Word16 ts, i, j, l_ts;
    8191             :     Word32 Chan_RealBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
    8192             :     Word32 Chan_ImagBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
    8193             :     Word16 band_m_idx, block_m_idx;
    8194             :     Word16 mrange[2];
    8195             :     Word16 brange[2];
    8196             :     Word16 numAnalysisChannels;
    8197         150 :     copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_fx );
    8198         150 :     Word16 q_cldfb = *outAudio.pq_fact;
    8199         150 :     Word16 q_cldfb_out = *outAudio.pq_fact;
    8200         150 :     Word16 scale_factor = 31;
    8201             :     Word16 scale_fac_arr[MASA_MAX_TRANSPORT_CHANNELS];
    8202         150 :     move16();
    8203         150 :     move16();
    8204         150 :     move16();
    8205             :     /* Calculate energy */
    8206             :     // l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
    8207         150 :     l_ts = shr( masaInput->base.inputBuffer.config.numSamplesPerChannel, 4 );
    8208         150 :     numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
    8209         150 :     move16();
    8210             :     /* do processing over all CLDFB time slots */
    8211         750 :     FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
    8212             :     {
    8213         600 :         mrange[0] = DirAC_block_grouping[block_m_idx];
    8214         600 :         mrange[1] = DirAC_block_grouping[block_m_idx + 1];
    8215         600 :         move16();
    8216         600 :         move16();
    8217             : 
    8218         600 :         set_zero_fx( masaInput->hMasaPrerend->energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
    8219         600 :         set16_fx( masaInput->hMasaPrerend->energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
    8220             : 
    8221        3000 :         FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
    8222             :         {
    8223        7200 :             FOR( i = 0; i < numAnalysisChannels; i++ )
    8224             :             {
    8225        4800 :                 scale_factor = 31;
    8226        4800 :                 move16();
    8227        4800 :                 masaInput->hMasaPrerend->cldfbAnaEnc[i]->Q_cldfb_state = q_cldfb;
    8228        4800 :                 q_cldfb_out = q_cldfb;
    8229        4800 :                 move16();
    8230        4800 :                 move16();
    8231        4800 :                 cldfbAnalysis_ts_fx_fixed_q( &( tmpBuffer_fx[i][l_ts * ts] ), Chan_RealBuffer_fx[i], Chan_ImagBuffer_fx[i], l_ts, masaInput->hMasaPrerend->cldfbAnaEnc[i], &q_cldfb_out );
    8232        4800 :                 scale_factor = s_min( scale_factor, s_min( getScaleFactor32( Chan_RealBuffer_fx[i], l_ts ), getScaleFactor32( Chan_ImagBuffer_fx[i], l_ts ) ) );
    8233        4800 :                 scale_factor = sub( scale_factor, 1 );
    8234        4800 :                 scale_sig32( Chan_RealBuffer_fx[i], l_ts, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
    8235        4800 :                 scale_sig32( Chan_ImagBuffer_fx[i], l_ts, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
    8236        4800 :                 scale_fac_arr[i] = scale_factor;
    8237        4800 :                 move16();
    8238             :             }
    8239             : 
    8240        2400 :             scale_factor = MAX_16;
    8241        2400 :             move16();
    8242        7200 :             FOR( i = 0; i < numAnalysisChannels; i++ )
    8243             :             {
    8244        4800 :                 scale_factor = s_min( scale_factor, scale_fac_arr[i] );
    8245             :             }
    8246             : 
    8247        7200 :             FOR( i = 0; i < numAnalysisChannels; i++ )
    8248             :             {
    8249        4800 :                 IF( NE_16( scale_factor, scale_fac_arr[i] ) )
    8250             :                 {
    8251       48861 :                     FOR( j = 0; j < l_ts; j++ )
    8252             :                     {
    8253       48060 :                         Chan_RealBuffer_fx[i][j] = L_shr( Chan_RealBuffer_fx[i][j], sub( scale_fac_arr[i], scale_factor ) ); /* Q(q_cldfb_out+scale_factor) */
    8254       48060 :                         move32();
    8255       48060 :                         Chan_ImagBuffer_fx[i][j] = L_shr( Chan_ImagBuffer_fx[i][j], sub( scale_fac_arr[i], scale_factor ) ); /* Q(q_cldfb_out+scale_factor) */
    8256       48060 :                         move32();
    8257             :                     }
    8258             :                 }
    8259             :             }
    8260             : 
    8261        2400 :             Word16 q_add = sub( 31, add( scale_factor, q_cldfb_out ) );
    8262             :             /* Compute channel energy for metadata processing */
    8263       60000 :             FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
    8264             :             {
    8265       57600 :                 brange[0] = MASA_band_grouping_24[band_m_idx];
    8266       57600 :                 move16();
    8267       57600 :                 brange[1] = MASA_band_grouping_24[band_m_idx + 1];
    8268       57600 :                 move16();
    8269      201600 :                 FOR( j = brange[0]; j < brange[1]; j++ )
    8270             :                 {
    8271      432000 :                     FOR( i = 0; i < numAnalysisChannels; i++ )
    8272             :                     {
    8273      288000 :                         Word32 temp = L_add( Mpy_32_32( Chan_RealBuffer_fx[0][j], Chan_RealBuffer_fx[0][j] ), Mpy_32_32( Chan_ImagBuffer_fx[0][j], Chan_ImagBuffer_fx[0][j] ) ); /* 2 * Q(q_cldfb_out + scale_factor) - 31 */
    8274      288000 :                         masaInput->hMasaPrerend->energy_fx[block_m_idx][band_m_idx] = BASOP_Util_Add_Mant32Exp( masaInput->hMasaPrerend->energy_fx[block_m_idx][band_m_idx], masaInput->hMasaPrerend->energy_e[block_m_idx][band_m_idx], temp, shl( q_add, 1 ), &masaInput->hMasaPrerend->energy_e[block_m_idx][band_m_idx] );
    8275      288000 :                         move32();
    8276             :                     }
    8277             :                 }
    8278             :             }
    8279             :         }
    8280             :     }
    8281             : 
    8282             :     /* Copy audio channels if mismatch in number of transports */
    8283         150 :     test();
    8284         150 :     test();
    8285         150 :     IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 1 ) && EQ_16( outAudio.config.numChannels, 2 ) )
    8286             :     {
    8287           0 :         Copy32( tmpBuffer_fx[0], tmpBuffer_fx[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
    8288             :     }
    8289         150 :     ELSE IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 2 ) && EQ_16( outAudio.config.numChannels, 1 ) )
    8290             :     {
    8291             :         //  v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
    8292           0 :         v_add_fixed_no_hdrm( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
    8293             :     }
    8294             : 
    8295             :     /* Copy metadata */
    8296         150 :     outMeta = masaInput->hMasaPrerend->hMasaOut;
    8297         150 :     inMeta = &masaInput->masaMetadata;
    8298         150 :     numDirs = add( inMeta->descriptive_meta.numberOfDirections, 1 );
    8299             : 
    8300         750 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    8301             :     {
    8302       15000 :         FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    8303             :         {
    8304             :             /* Remainder is always set to zero and energy removal is compensated in following steps
    8305             :              * to other ratios. */
    8306             :             //     inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
    8307       14400 :             inMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0;
    8308       14400 :             move32();
    8309       14400 :             ratioSum_fx = 0;
    8310       14400 :             move32();
    8311       43200 :             FOR( dir = 0; dir < numDirs; dir++ )
    8312             :             {
    8313       28800 :                 ratioSum_fx = L_add( ratioSum_fx, inMeta->directional_meta[dir].energy_ratio_fx[sf][band] );
    8314             :             }
    8315       14400 :             ratioSum_fx = L_add( ratioSum_fx, inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
    8316             : 
    8317       14400 :             IF( ratioSum_fx == 0 )
    8318             :             {
    8319           0 :                 FOR( dir = 0; dir < numDirs; dir++ )
    8320             :                 {
    8321           0 :                     inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0;
    8322           0 :                     move32();
    8323             :                 }
    8324           0 :                 inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30;
    8325           0 :                 move32();
    8326             :             }
    8327       14400 :             ELSE IF( NE_32( ratioSum_fx, ONE_IN_Q30 ) )
    8328             :             {
    8329       14400 :                 Word16 tmp_e = 0;
    8330       14400 :                 move16();
    8331       14400 :                 Word32 tmp = 0;
    8332       14400 :                 move32();
    8333       43200 :                 FOR( dir = 0; dir < numDirs; dir++ )
    8334             :                 {
    8335       28800 :                     tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
    8336       28800 :                     inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
    8337       28800 :                     move32();
    8338             :                 }
    8339       14400 :                 tmp_e = 0;
    8340       14400 :                 move16();
    8341       14400 :                 tmp = 0;
    8342       14400 :                 move32();
    8343       14400 :                 tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
    8344       14400 :                 inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
    8345       14400 :                 move32();
    8346             :             }
    8347             :         }
    8348             :     }
    8349             : 
    8350         750 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    8351             :     {
    8352       15000 :         FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    8353             :         {
    8354       14400 :             outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
    8355       14400 :             move16();
    8356       43200 :             FOR( dir = 0; dir < numDirs; dir++ )
    8357             :             {
    8358       28800 :                 outMeta->directionIndex[dir][sf][band] = index_theta_phi_16_fx( &inMeta->directional_meta[dir].elevation_fx[sf][band], &inMeta->directional_meta[dir].azimuth_fx[sf][band], masaInput->hMasaPrerend->sph_grid16 );
    8359       28800 :                 outMeta->directToTotalRatio[dir][sf][band] = (UWord8) L_shr( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], Q22 );
    8360       28800 :                 outMeta->diffuseToTotalRatio[sf][band] = (UWord8) sub( outMeta->diffuseToTotalRatio[sf][band], outMeta->directToTotalRatio[dir][sf][band] );
    8361       28800 :                 outMeta->spreadCoherence[dir][sf][band] = (UWord8) shr( inMeta->directional_meta[dir].spread_coherence_fx[sf][band], Q7 );
    8362             : 
    8363       28800 :                 move16();
    8364       28800 :                 move16();
    8365       28800 :                 move16();
    8366       28800 :                 move16();
    8367             :             }
    8368       14400 :             outMeta->surroundCoherence[sf][band] = (UWord8) shr( inMeta->common_meta.surround_coherence_fx[sf][band], Q7 );
    8369       14400 :             move16();
    8370             :         }
    8371             :     }
    8372             : 
    8373         150 :     copy_masa_descriptive_meta_fx( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
    8374             : 
    8375         150 :     accumulate2dArrayToBuffer_fx( tmpBuffer_fx, &outAudio );
    8376             : 
    8377         150 :     return;
    8378             : }
    8379             : 
    8380       18150 : static ivas_error renderInputMasa(
    8381             :     input_masa *masaInput,
    8382             :     const AUDIO_CONFIG outConfig,
    8383             :     IVAS_REND_AudioBuffer outAudio )
    8384             : {
    8385             :     IVAS_REND_AudioBuffer inAudio;
    8386             :     Word16 ch;
    8387             :     Word16 maxBin;
    8388             :     Word32 *tmpBuffer_fx[MAX_OUTPUT_CHANNELS];
    8389             :     Word32 tmpBuffer_buff_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    8390             :     Word16 cldfb2tdShift;
    8391             :     Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    8392             :     Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    8393             : 
    8394       18150 :     IF( !masaInput->metadataHasBeenFed )
    8395             :     {
    8396           0 :         return IVAS_ERR_MISSING_METADATA;
    8397             :     }
    8398             : 
    8399       18150 :     inAudio = masaInput->base.inputBuffer;
    8400             : 
    8401       18150 :     cldfb2tdShift = outAudio.config.is_cldfb ? 1 : 0;
    8402       18150 :     IF( ( NE_32( L_shl( masaInput->base.numNewSamplesPerChannel, cldfb2tdShift ), outAudio.config.numSamplesPerChannel ) ) &&
    8403             :         NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    8404             :     {
    8405           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" );
    8406             :     }
    8407       18150 :     masaInput->base.numNewSamplesPerChannel = 0;
    8408       18150 :     move32();
    8409             : 
    8410       18150 :     *outAudio.pq_fact = outAudio.q_factor;
    8411       18150 :     move16();
    8412             :     /* Apply input gain to new audio */
    8413       18150 :     v_multc_fixed( inAudio.data_fx, masaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
    8414       18150 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
    8415       18150 :     move16();
    8416             : 
    8417       18150 :     maxBin = extract_l( Mpy_32_32( *masaInput->base.ctx.pOutSampleRate, INV_CLDFB_BANDWIDTH_Q31 ) ); /* Q0 */
    8418             : 
    8419             :     /* set combined orientation subframe info to start info */
    8420       18150 :     ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
    8421             : 
    8422       18150 :     IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    8423             :     {
    8424             :         /* MASA prerendering path for MASA -> MASA */
    8425         150 :         renderMasaToMasa( masaInput, outAudio );
    8426             :     }
    8427             :     ELSE
    8428             :     {
    8429             :         /* MASA external renderer -> other formats */
    8430             :         Word16 num_subframes, exp;
    8431      306000 :         FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
    8432             :         {
    8433      288000 :             tmpBuffer_fx[ch] = tmpBuffer_buff_fx[ch];
    8434             :         }
    8435       18000 :         copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_buff_fx );
    8436             : 
    8437       18000 :         num_subframes = BASOP_Util_Divide3232_Scale( L_mult0( masaInput->base.inputBuffer.config.numSamplesPerChannel, IVAS_NUM_FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ), *masaInput->base.ctx.pOutSampleRate, &exp );
    8438       18000 :         num_subframes = shr( num_subframes, sub( 15, exp ) ); /* Q0 */
    8439             : 
    8440       18000 :         IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) || EQ_32( outConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) )
    8441           0 :         {
    8442             :             /* split rendering. use the combined of the first subframe in all subframes */
    8443             :             Word16 sf, i, j;
    8444             :             COMBINED_ORIENTATION_HANDLE pCombinedOrientationData;
    8445           0 :             pCombinedOrientationData = *masaInput->base.ctx.pCombinedOrientationData;
    8446           0 :             FOR( sf = 1; sf < pCombinedOrientationData->num_subframes; sf++ )
    8447             :             {
    8448           0 :                 Copy_Quat_fx( &pCombinedOrientationData->Quaternions[0], &pCombinedOrientationData->Quaternions[sf] );
    8449           0 :                 FOR( i = 0; i < 3; i++ )
    8450             :                 {
    8451           0 :                     FOR( j = 0; j < 3; j++ )
    8452             :                     {
    8453           0 :                         pCombinedOrientationData->Rmat_fx[sf][i][j] = pCombinedOrientationData->Rmat_fx[0][i][j];
    8454           0 :                         move32();
    8455             :                     }
    8456             :                 }
    8457             :             }
    8458             : 
    8459           0 :             copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
    8460           0 :             Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    8461           0 :             Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    8462             :             // scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
    8463             : 
    8464           0 :             ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes, masaInput->base.ctx.pSplitRendWrapper, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
    8465             : 
    8466           0 :             accumulateCLDFBArrayToBuffer_fx( Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, &outAudio );
    8467             : 
    8468           0 :             *outAudio.pq_fact = Q6;
    8469           0 :             move16();
    8470             :         }
    8471             :         ELSE
    8472             :         {
    8473             :             /* non-split path */
    8474       18000 :             SWITCH( masaInput->hMasaExtRend->renderer_type )
    8475             :             {
    8476       12750 :                 case RENDERER_DIRAC:
    8477             : 
    8478       12750 :                     copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
    8479       12750 :                     intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 1 );
    8480      123000 :                     FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
    8481             :                     {
    8482      110250 :                         masaInput->hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state = Q11;
    8483      110250 :                         move16();
    8484             :                     }
    8485      216750 :                     FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
    8486             :                     {
    8487      204000 :                         Scale_sig32( tmpBuffer_buff_fx[ch], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    8488             :                     }
    8489             : 
    8490       12750 :                     scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    8491             : 
    8492       12750 :                     ivas_masa_ext_dirac_render_fx( masaInput->hMasaExtRend, tmpBuffer_fx, num_subframes );
    8493             : 
    8494       12750 :                     *outAudio.pq_fact = Q11;
    8495       12750 :                     move16();
    8496             : 
    8497      123000 :                     FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
    8498             :                     {
    8499      110250 :                         scale_sig32( masaInput->hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, masaInput->hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state ) ); /* Q11 */
    8500      110250 :                         masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
    8501      110250 :                         move16();
    8502             :                     }
    8503             : 
    8504       12750 :                     intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 0 );
    8505       12750 :                     BREAK;
    8506        4500 :                 case RENDERER_STEREO_PARAMETRIC:
    8507             :                 case RENDERER_BINAURAL_PARAMETRIC:
    8508             :                 case RENDERER_BINAURAL_PARAMETRIC_ROOM:
    8509             : 
    8510        4500 :                     copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
    8511             : 
    8512        4500 :                     Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    8513        4500 :                     Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    8514             : 
    8515        4500 :                     scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
    8516             : 
    8517        4500 :                     ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes, NULL, NULL, NULL );
    8518        4500 :                     *outAudio.pq_fact = Q11;
    8519        4500 :                     move16();
    8520        4500 :                     BREAK;
    8521         750 :                 case RENDERER_DISABLE:
    8522         750 :                     BREAK; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
    8523           0 :                 default:
    8524           0 :                     return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
    8525             :             }
    8526       18000 :             accumulate2dArrayToBuffer_fx( tmpBuffer_buff_fx, &outAudio );
    8527             :         }
    8528             :     }
    8529             : 
    8530       18150 :     return IVAS_ERR_OK;
    8531             : }
    8532             : 
    8533             : 
    8534     1126140 : static ivas_error renderActiveInputsMasa(
    8535             :     IVAS_REND_HANDLE hIvasRend,
    8536             :     IVAS_REND_AudioBuffer outAudio )
    8537             : {
    8538             :     Word16 i;
    8539             :     input_masa *pCurrentInput;
    8540             :     ivas_error error;
    8541             : 
    8542     2252280 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMasa ); i < RENDERER_MAX_MASA_INPUTS; ( ++i, ++pCurrentInput ) )
    8543             :     {
    8544     1126140 :         IF( EQ_16( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8545             :         {
    8546             :             /* Skip inactive inputs */
    8547     1107990 :             CONTINUE;
    8548             :         }
    8549             : 
    8550       18150 :         *outAudio.pq_fact = outAudio.q_factor;
    8551       18150 :         move16();
    8552             : 
    8553       18150 :         IF( NE_32( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    8554             :         {
    8555           0 :             return error;
    8556             :         }
    8557             :     }
    8558             : 
    8559     1126140 :     return IVAS_ERR_OK;
    8560             : }
    8561             : 
    8562             : 
    8563             : /*---------------------------------------------------------------------*
    8564             :  * IVAS_REND_GetMasaMetadata( )
    8565             :  *
    8566             :  * Get metadata of the estimated MASA frame
    8567             :  *---------------------------------------------------------------------*/
    8568             : 
    8569           0 : ivas_error IVAS_REND_GetMasaMetadata(
    8570             :     IVAS_REND_HANDLE hIvasRend,                        /* i/o: IVAS renderer handle                                                    */
    8571             :     MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o  : pointer to handle, which will be set to point to analyzed MASA metadata */
    8572             :     const IVAS_REND_AudioConfigType inputType          /* i  : Input type                                                              */
    8573             : )
    8574             : {
    8575           0 :     IF( hIvasRend == NULL )
    8576             :     {
    8577           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    8578             :     }
    8579             : 
    8580             :     /* Get the metadata handle */
    8581           0 :     IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
    8582             :     {
    8583           0 :         *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
    8584             :     }
    8585           0 :     ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    8586             :     {
    8587           0 :         *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
    8588             :     }
    8589           0 :     ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    8590             :     {
    8591           0 :         *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
    8592             :     }
    8593             :     ELSE
    8594             :     {
    8595           0 :         return IVAS_ERR_NOT_SUPPORTED_OPTION;
    8596             :     }
    8597             : 
    8598           0 :     return IVAS_ERR_OK;
    8599             : }
    8600             : 
    8601             : 
    8602             : /*---------------------------------------------------------------------*
    8603             :  * IVAS_REND_MergeMasaMetadata( )
    8604             :  *
    8605             :  * Merge MASA metadata from two formats
    8606             :  *---------------------------------------------------------------------*/
    8607             : 
    8608         450 : ivas_error IVAS_REND_MergeMasaMetadata(
    8609             :     IVAS_REND_HANDLE hIvasRend,                        /* i/o: IVAS renderer handle                                             */
    8610             :     MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o  : pointer to handle, which will be set to point to merged metadata */
    8611             :     const IVAS_REND_AudioConfigType inputType1,        /* i  : Input type 1                                                     */
    8612             :     const IVAS_REND_AudioConfigType inputType2         /* i  : Input type 2                                                     */
    8613             : )
    8614             : {
    8615             :     MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
    8616             :     Word32( *inEne1_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    8617             :     Word32( *inEne2_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    8618             :     Word16( *inEne1_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    8619             :     Word16( *inEne2_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    8620             : 
    8621         450 :     IF( hIvasRend == NULL )
    8622             :     {
    8623           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    8624             :     }
    8625             : 
    8626             :     /* Input1 metadata and energy */
    8627         450 :     IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
    8628             :     {
    8629             : 
    8630           0 :         *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
    8631           0 :         inEne1_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
    8632           0 :         inEne1_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
    8633             :     }
    8634         450 :     ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    8635             :     {
    8636             : 
    8637           0 :         *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
    8638           0 :         inEne1_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
    8639           0 :         inEne1_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
    8640             :     }
    8641         450 :     ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    8642             :     {
    8643             : 
    8644         450 :         *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
    8645         450 :         inEne1_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
    8646         450 :         inEne1_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
    8647             :     }
    8648           0 :     ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    8649             :     {
    8650             : 
    8651           0 :         *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
    8652           0 :         inEne1_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
    8653           0 :         inEne1_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
    8654             :     }
    8655             :     ELSE
    8656             :     {
    8657           0 :         return IVAS_ERR_NOT_SUPPORTED_OPTION;
    8658             :     }
    8659             : 
    8660             :     /* Input2 metadata and energy */
    8661         450 :     IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
    8662             :     {
    8663         150 :         inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
    8664         150 :         inEne2_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
    8665         150 :         inEne2_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
    8666             :     }
    8667         300 :     ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    8668             :     {
    8669         150 :         inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
    8670         150 :         inEne2_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
    8671         150 :         inEne2_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
    8672             :     }
    8673         150 :     ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    8674             :     {
    8675           0 :         inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
    8676           0 :         inEne2_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
    8677           0 :         inEne2_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
    8678             :     }
    8679         150 :     ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    8680             :     {
    8681             : 
    8682         150 :         inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
    8683         150 :         inEne2_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
    8684         150 :         inEne2_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
    8685             :     }
    8686             :     ELSE
    8687             :     {
    8688           0 :         return IVAS_ERR_NOT_SUPPORTED_OPTION;
    8689             :     }
    8690             : 
    8691             :     /* Merge metadata */
    8692         450 :     ivas_prerend_merge_masa_metadata_fx( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1_fx, *inEne1_e, inMeta2, inputType2, *inEne2_fx, *inEne2_e );
    8693             : 
    8694             : 
    8695         450 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
    8696             :     {
    8697           0 :         ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 0u;
    8698           0 :         move16();
    8699             :     }
    8700             :     ELSE
    8701             :     {
    8702         450 :         ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 1u;
    8703         450 :         move16();
    8704             :     }
    8705             : 
    8706         450 :     return IVAS_ERR_OK;
    8707             : }
    8708             : 
    8709             : 
    8710             : /*---------------------------------------------------------------------*
    8711             :  * IVAS_REND_SetTotalNumberOfObjects( )
    8712             :  *
    8713             :  * Set the total number of objects to the first object data
    8714             :  *---------------------------------------------------------------------*/
    8715             : 
    8716         182 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
    8717             :     IVAS_REND_HANDLE hIvasRend,     /* i/o: IVAS renderer handle    */
    8718             :     const UWord16 total_num_objects /* i  : total number of objects */
    8719             : )
    8720             : {
    8721         182 :     IF( hIvasRend == NULL )
    8722             :     {
    8723           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    8724             :     }
    8725             : 
    8726         182 :     hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
    8727         182 :     move16();
    8728             : 
    8729         182 :     return IVAS_ERR_OK;
    8730             : }
    8731             : 
    8732             : 
    8733             : /*---------------------------------------------------------------------*
    8734             :  * IVAS_REND_SetIsmMetadataDelay( )
    8735             :  *
    8736             :  * Set the Metadata Delay in ms in order to sync with audio delay
    8737             :  *---------------------------------------------------------------------*/
    8738             : 
    8739         182 : ivas_error IVAS_REND_SetIsmMetadataDelay(
    8740             :     IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle                                */
    8741             :     const Word32 sync_md_delay  /* i  : ISM Metadata Delay in ms to sync with audio delay   */
    8742             : )
    8743             : {
    8744             :     Word16 i;
    8745             : 
    8746         182 :     IF( hIvasRend == NULL )
    8747             :     {
    8748           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    8749             :     }
    8750         910 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    8751             :     {
    8752         728 :         hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay;
    8753         728 :         move32();
    8754             :     }
    8755             : 
    8756         182 :     return IVAS_ERR_OK;
    8757             : }
    8758             : 
    8759             : 
    8760             : /*-------------------------------------------------------------------*
    8761             :  * getSamplesInternal()
    8762             :  *
    8763             :  *
    8764             :  *-------------------------------------------------------------------*/
    8765             : 
    8766     1126140 : static ivas_error getSamplesInternal(
    8767             :     IVAS_REND_HANDLE hIvasRend,      /* i/o: Renderer handle                                                */
    8768             :     IVAS_REND_AudioBuffer outAudio,  /* i/o: buffer for output audio                                        */
    8769             :     IVAS_REND_BitstreamBuffer *hBits /* i/o: buffer for input/output bitstream. Needed in split rendering   */
    8770             : )
    8771             : {
    8772             :     ivas_error error;
    8773             :     Word16 numOutChannels;
    8774             :     Word16 cldfb2tdSampleShift;
    8775             :     IVAS_REND_AudioBuffer outAudioOrig;
    8776             : 
    8777             :     /* Validate function arguments */
    8778     1126140 :     test();
    8779     1126140 :     IF( hIvasRend == NULL || outAudio.data_fx == NULL )
    8780             :     {
    8781           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    8782             :     }
    8783             : 
    8784     1126140 :     test();
    8785     1126140 :     cldfb2tdSampleShift = ( outAudio.config.is_cldfb ) ? 1 : 0;
    8786             : 
    8787     1126140 :     IF( outAudio.config.numSamplesPerChannel <= 0 || ( MAX_BUFFER_LENGTH_PER_CHANNEL < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 0 ) ||
    8788             :         ( ( shl( MAX_BUFFER_LENGTH_PER_CHANNEL, cldfb2tdSampleShift ) ) < outAudio.config.numSamplesPerChannel && outAudio.config.is_cldfb == 1 ) )
    8789             :     {
    8790           0 :         return IVAS_ERR_INVALID_BUFFER_SIZE;
    8791             :     }
    8792             : 
    8793     1126140 :     test();
    8794     1126140 :     IF( LE_16( outAudio.config.numChannels, 0 ) || LT_16( MAX_OUTPUT_CHANNELS, outAudio.config.numChannels ) )
    8795             :     {
    8796           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    8797             :     }
    8798             : 
    8799     1126140 :     test();
    8800     1126140 :     test();
    8801     1126140 :     test();
    8802     1126140 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
    8803             :         NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) &&
    8804             :         NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) &&
    8805             :         NE_32( L_shr( L_mult0( outAudio.config.numSamplesPerChannel, 1000 ), cldfb2tdSampleShift ),
    8806             :                imult3216( hIvasRend->sampleRateOut, i_mult( hIvasRend->num_subframes, BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ) )
    8807             :     {
    8808           0 :         return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
    8809             :     }
    8810             : 
    8811             :     /* Check that there is allowed configuration for MASA format output */
    8812     1126140 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    8813             :     {
    8814             :         Word16 i;
    8815         150 :         Word16 numMasaInputs = 0;
    8816         150 :         move16();
    8817         150 :         Word16 numOtherInputs = 0;
    8818         150 :         move16();
    8819             : 
    8820         300 :         FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
    8821             :         {
    8822             :             // numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    8823             : 
    8824         150 :             IF( EQ_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8825             :             {
    8826           0 :                 numMasaInputs = add( numMasaInputs, 0 );
    8827             :             }
    8828             :             ELSE
    8829             :             {
    8830         150 :                 numMasaInputs = add( numMasaInputs, 1 );
    8831             :             }
    8832             :         }
    8833             : 
    8834         300 :         FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
    8835             :         {
    8836             :             // numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    8837             : 
    8838         150 :             IF( EQ_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8839             :             {
    8840           0 :                 numOtherInputs = add( numOtherInputs, 0 );
    8841             :             }
    8842             :             ELSE
    8843             :             {
    8844         150 :                 numOtherInputs = add( numOtherInputs, 1 );
    8845             :             }
    8846             :         }
    8847             : 
    8848         300 :         FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
    8849             :         {
    8850             :             // numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    8851             : 
    8852         150 :             IF( EQ_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8853             :             {
    8854           0 :                 numOtherInputs = add( numOtherInputs, 0 );
    8855             :             }
    8856             :             ELSE
    8857             :             {
    8858         150 :                 numOtherInputs = add( numOtherInputs, 1 );
    8859             :             }
    8860             :         }
    8861             : 
    8862             :         /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
    8863             :         // numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    8864         150 :         IF( EQ_32( hIvasRend->inputsIsm[0].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8865             :         {
    8866           0 :             numOtherInputs = add( numOtherInputs, 0 );
    8867             :         }
    8868             :         ELSE
    8869             :         {
    8870         150 :             numOtherInputs = add( numOtherInputs, 1 );
    8871             :         }
    8872             : 
    8873         150 :         test();
    8874         150 :         IF( numMasaInputs == 0 || numOtherInputs == 0 )
    8875             :         {
    8876           0 :             return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    8877             :         }
    8878             :     }
    8879             : 
    8880     1126140 :     IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
    8881             :     {
    8882           0 :         return error;
    8883             :     }
    8884             : 
    8885     1126140 :     IF( NE_16( numOutChannels, outAudio.config.numChannels ) && NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) && NE_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    8886             :     {
    8887           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    8888             :     }
    8889             : 
    8890             :     /* Clear original output buffer */
    8891     1126140 :     set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) );
    8892             : 
    8893     1126140 :     outAudioOrig = outAudio;
    8894             : 
    8895             :     /* Use internal buffer if outputting split rendering bitstream */
    8896     1126140 :     test();
    8897     1126140 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
    8898             :         EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    8899             :     {
    8900             :         Word16 num_poses_orig;
    8901           0 :         num_poses_orig = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
    8902           0 :         move16();
    8903           0 :         outAudio.config = hIvasRend->splitRendEncBuffer.config;
    8904           0 :         outAudio.data_fx = hIvasRend->splitRendEncBuffer.data_fx;
    8905             : 
    8906           0 :         ISAR_PRE_REND_GetMultiBinPoseData( &hIvasRend->hRendererConfig->split_rend_config, &hIvasRend->splitRendWrapper->multiBinPoseData, hIvasRend->headRotData.sr_pose_pred_axis );
    8907             : 
    8908           0 :         assert( num_poses_orig == hIvasRend->splitRendWrapper->multiBinPoseData.num_poses && "number of poses should not change dynamically" );
    8909             : 
    8910             :         /* Clear output buffer for split rendering bitstream */
    8911           0 :         set32_fx( outAudio.data_fx, 0, outAudio.config.numChannels * outAudio.config.numSamplesPerChannel );
    8912             :     }
    8913             : 
    8914     1126140 :     IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    8915             :     {
    8916           0 :         return error;
    8917             :     }
    8918     1126140 :     IF( NE_32( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    8919             :     {
    8920           0 :         return error;
    8921             :     }
    8922     1126140 :     IF( NE_32( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    8923             :     {
    8924           0 :         return error;
    8925             :     }
    8926     1126140 :     IF( NE_32( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    8927             :     {
    8928           0 :         return error;
    8929             :     }
    8930             : 
    8931     1126140 :     test();
    8932     1126140 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    8933             :     {
    8934             :         ISAR_SPLIT_REND_BITS_DATA bits;
    8935             :         Word16 cldfb_in_flag, i, j, k, ch, ro_md_flag;
    8936             :         Word32 Cldfb_RealBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    8937             :         Word32 Cldfb_ImagBuffer_Binaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][CLDFB_NO_COL_MAX][CLDFB_NO_CHANNELS_MAX];
    8938             : 
    8939           0 :         FOR( i = 0; i < MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS; i++ )
    8940             :         {
    8941           0 :             FOR( j = 0; j < CLDFB_NO_COL_MAX; j++ )
    8942             :             {
    8943           0 :                 FOR( k = 0; k < CLDFB_NO_CHANNELS_MAX; k++ )
    8944             :                 {
    8945           0 :                     Cldfb_RealBuffer_Binaural[i][j][k] = 0;
    8946           0 :                     Cldfb_ImagBuffer_Binaural[i][j][k] = 0;
    8947           0 :                     move32();
    8948           0 :                     move32();
    8949             :                 }
    8950             :             }
    8951             :         }
    8952             : 
    8953             :         Word32 *tmpBinaural[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS], tmpBinaural_buff[MAX_HEAD_ROT_POSES * BINAURAL_CHANNELS][L_FRAME48k];
    8954             : 
    8955           0 :         FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
    8956             :         {
    8957           0 :             tmpBinaural[ch] = tmpBinaural_buff[ch];
    8958           0 :             move32();
    8959             :         }
    8960             : 
    8961           0 :         IF( EQ_16( outAudio.config.is_cldfb, 1 ) )
    8962             :         {
    8963           0 :             cldfb_in_flag = 1;
    8964           0 :             move16();
    8965           0 :             copyBufferToCLDFBarray_fx( outAudio, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural );
    8966             :         }
    8967             :         ELSE
    8968             :         {
    8969           0 :             cldfb_in_flag = 0;
    8970           0 :             move16();
    8971           0 :             copyBufferTo2dArray_fx( outAudio, tmpBinaural_buff );
    8972             :         }
    8973             : 
    8974             :         /* Encode split rendering bitstream */
    8975           0 :         convertBitsBufferToInternalBitsBuff( *hBits, &bits );
    8976             : 
    8977           0 :         ro_md_flag = 0;
    8978           0 :         move16();
    8979           0 :         FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    8980             :         {
    8981           0 :             IF( NE_32( hIvasRend->inputsIsm[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    8982             :             {
    8983           0 :                 ro_md_flag = 1;
    8984           0 :                 move16();
    8985           0 :                 break;
    8986             :             }
    8987             :         }
    8988             : 
    8989           0 :         Word16 q1 = 31, q2 = 31, Q_buff;
    8990             :         Word16 Q_out[CLDFB_NO_COL_MAX];
    8991           0 :         Q_out[0] = 31;
    8992           0 :         Word16 num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
    8993             : 
    8994           0 :         for ( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ )
    8995             :         {
    8996           0 :             for ( j = 0; j < CLDFB_NO_COL_MAX; j++ )
    8997             :             {
    8998           0 :                 q1 = s_min( q1, L_norm_arr( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) );
    8999           0 :                 q2 = s_min( q2, L_norm_arr( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX ) );
    9000             :             }
    9001             :         }
    9002           0 :         Q_buff = s_min( q1, q2 );
    9003           0 :         for ( i = 0; i < num_poses * BINAURAL_CHANNELS; i++ )
    9004             :         {
    9005           0 :             for ( j = 0; j < CLDFB_NO_COL_MAX; j++ )
    9006             :             {
    9007           0 :                 scale_sig32( Cldfb_RealBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff );
    9008           0 :                 scale_sig32( Cldfb_ImagBuffer_Binaural[i][j], CLDFB_NO_CHANNELS_MAX, Q_buff );
    9009             :             }
    9010             :         }
    9011           0 :         Q_buff = Q_buff + *outAudio.pq_fact;
    9012             : 
    9013           0 :         IF( EQ_16( cldfb_in_flag, 0 ) )
    9014             :         {
    9015             :             /*TD input*/
    9016           0 :             num_poses = hIvasRend->splitRendWrapper->multiBinPoseData.num_poses;
    9017             : 
    9018           0 :             FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
    9019             :             {
    9020           0 :                 Q_out[0] = s_min( Q_out[0], L_norm_arr( tmpBinaural_buff[i], L_FRAME48k ) );
    9021             :             }
    9022             : 
    9023           0 :             FOR( i = 0; i < num_poses * BINAURAL_CHANNELS; ++i )
    9024             :             {
    9025           0 :                 scale_sig32( tmpBinaural_buff[i], L_FRAME48k, Q_out[0] );
    9026             :             }
    9027             : 
    9028           0 :             Q_out[0] = Q_out[0] + *outAudio.pq_fact;
    9029             :         }
    9030             : 
    9031           0 :         if ( ( error = ISAR_PRE_REND_MultiBinToSplitBinaural( hIvasRend->splitRendWrapper, hIvasRend->headRotData.headPositions[0], hIvasRend->hRendererConfig->split_rend_config.splitRendBitRate, hIvasRend->hRendererConfig->split_rend_config.codec,
    9032           0 :                                                               hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms,
    9033           0 :                                                               hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms,
    9034           0 :                                                               &bits, Cldfb_RealBuffer_Binaural, Cldfb_ImagBuffer_Binaural, ( const Word16 )( ( BINAURAL_MAXBANDS * hIvasRend->sampleRateOut ) / 48000 ), tmpBinaural, 1, cldfb_in_flag, ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0, ro_md_flag, Q_buff, &Q_out[0] ) ) != IVAS_ERR_OK )
    9035             :         {
    9036           0 :             return error;
    9037             :         }
    9038             : 
    9039           0 :         Word16 pcm_out_flag = ( hIvasRend->outputConfig == IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) ? 1 : 0;
    9040           0 :         IF( NE_16( pcm_out_flag, 0 ) )
    9041             :         {
    9042           0 :             FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
    9043             :             {
    9044           0 :                 scale_sig32( tmpBinaural_buff[j], L_FRAME48k, sub( *outAudio.pq_fact, Q_out[j] ) ); // *outAudio.pq_fact
    9045             :             }
    9046             :         }
    9047             : 
    9048           0 :         convertInternalBitsBuffToBitsBuffer( hBits, bits );
    9049             : 
    9050             :         /* reset to outAudioOrig in case of PCM output */
    9051           0 :         outAudio.config = outAudioOrig.config;
    9052           0 :         outAudio.data_fx = outAudioOrig.data_fx;
    9053             : 
    9054           0 :         IF( NE_16( pcm_out_flag, 0 ) )
    9055             :         {
    9056           0 :             accumulate2dArrayToBuffer_fx( tmpBinaural_buff, &outAudio );
    9057             :         }
    9058             :     }
    9059             : 
    9060     1126140 :     if ( outAudio.config.is_cldfb == 0 )
    9061             :     {
    9062     1126140 :         Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact );
    9063             : #ifndef DISABLE_LIMITER
    9064     1126140 :         limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact );
    9065             : #endif
    9066             :     }
    9067             : 
    9068             :     /* update global cominbed orientation start index */
    9069     1126140 :     ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
    9070             : 
    9071     1126140 :     return IVAS_ERR_OK;
    9072             : }
    9073             : 
    9074             : 
    9075             : /*-------------------------------------------------------------------*
    9076             :  * IVAS_REND_GetSamples()
    9077             :  *
    9078             :  *
    9079             :  *-------------------------------------------------------------------*/
    9080             : 
    9081     1126140 : ivas_error IVAS_REND_GetSamples(
    9082             :     IVAS_REND_HANDLE hIvasRend,    /* i/o: Renderer handle          */
    9083             :     IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio  */
    9084             : )
    9085             : {
    9086     1126140 :     return getSamplesInternal( hIvasRend, outAudio, NULL );
    9087             : }
    9088             : 
    9089             : 
    9090             : /*-------------------------------------------------------------------*
    9091             :  * IVAS_REND_GetSplitBinauralBitstream()
    9092             :  *
    9093             :  *
    9094             :  *-------------------------------------------------------------------*/
    9095             : 
    9096           0 : ivas_error IVAS_REND_GetSplitBinauralBitstream(
    9097             :     IVAS_REND_HANDLE hIvasRend,      /* i/o: Renderer handle             */
    9098             :     IVAS_REND_AudioBuffer outAudio,  /* i/o: buffer for output audio     */
    9099             :     IVAS_REND_BitstreamBuffer *hBits /* o  : buffer for output bitstream */
    9100             : )
    9101             : {
    9102             :     Word16 cldfb_in_flag;
    9103             : 
    9104           0 :     cldfb_in_flag = getCldfbRendFlag( hIvasRend, IVAS_REND_AUDIO_CONFIG_TYPE_UNKNOWN );
    9105           0 :     hIvasRend->splitRendEncBuffer.config.is_cldfb = cldfb_in_flag;
    9106             : 
    9107           0 :     if ( hIvasRend->hRendererConfig->split_rend_config.dof == 0 || hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode == ISAR_SPLIT_REND_POSE_CORRECTION_MODE_NONE )
    9108             :     {
    9109           0 :         hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = outAudio.config.numSamplesPerChannel;
    9110             :     }
    9111             :     else
    9112             :     {
    9113           0 :         hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel = (Word16) ( hIvasRend->sampleRateOut / FRAMES_PER_SEC );
    9114             :     }
    9115             : 
    9116           0 :     hIvasRend->splitRendEncBuffer.config.numSamplesPerChannel *= cldfb_in_flag ? 2 : 1;
    9117             : 
    9118             :     /* hIvasRend->splitRendEncBuffer used for BINAURAL_SPLIT_CODED output
    9119             :            outAudio used for BINAURAL_SPLIT_PCM output */
    9120           0 :     return getSamplesInternal( hIvasRend, outAudio, hBits );
    9121             : }
    9122             : 
    9123             : 
    9124             : /*-------------------------------------------------------------------*
    9125             :  * IVAS_REND_GetSplitRendBitstreamHeader()
    9126             :  *
    9127             :  *
    9128             :  *-------------------------------------------------------------------*/
    9129             : 
    9130           0 : ivas_error IVAS_REND_GetSplitRendBitstreamHeader(
    9131             :     IVAS_REND_HANDLE hIvasRend,                           /* i/o: IVAS renderer handle                  */
    9132             :     ISAR_SPLIT_REND_CODEC *pCodec,                        /* o  : pointer to codec setting              */
    9133             :     ISAR_SPLIT_REND_POSE_CORRECTION_MODE *poseCorrection, /* o  : pointer to pose correction mode       */
    9134             :     Word16 *pCodec_frame_size_ms,                         /* o  : pointer to codec frame size setting   */
    9135             :     Word16 *pIsar_frame_size_ms                           /* o  : pointer to ISAR frame size setting    */
    9136             : )
    9137             : {
    9138           0 :     test();
    9139           0 :     IF( hIvasRend == NULL || hIvasRend->hRendererConfig == NULL )
    9140             :     {
    9141           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    9142             :     }
    9143             : 
    9144           0 :     *pCodec = hIvasRend->hRendererConfig->split_rend_config.codec;
    9145           0 :     *pCodec_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.codec_frame_size_ms;
    9146           0 :     *pIsar_frame_size_ms = hIvasRend->hRendererConfig->split_rend_config.isar_frame_size_ms;
    9147           0 :     *poseCorrection = hIvasRend->hRendererConfig->split_rend_config.poseCorrectionMode;
    9148             : 
    9149           0 :     return IVAS_ERR_OK;
    9150             : }
    9151             : 
    9152             : 
    9153             : /*-------------------------------------------------------------------*
    9154             :  * IVAS_REND_Close()
    9155             :  *
    9156             :  *
    9157             :  *-------------------------------------------------------------------*/
    9158             : 
    9159         666 : void IVAS_REND_Close(
    9160             :     IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
    9161             : )
    9162             : {
    9163             :     UWord16 i;
    9164             :     IVAS_REND_HANDLE hIvasRend;
    9165             : 
    9166             :     /* Validate function arguments */
    9167         666 :     test();
    9168         666 :     IF( phIvasRend == NULL || *phIvasRend == NULL )
    9169             :     {
    9170           0 :         return;
    9171             :     }
    9172         666 :     hIvasRend = *phIvasRend;
    9173             : 
    9174         666 :     IF( hIvasRend->efapOutWrapper.hEfap != NULL )
    9175             :     {
    9176         471 :         efap_free_data_fx( &hIvasRend->efapOutWrapper.hEfap );
    9177             :     }
    9178             : 
    9179             :     /* clear inputs */
    9180        3330 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    9181             :     {
    9182        2664 :         clearInputIsm( &hIvasRend->inputsIsm[i] );
    9183             :     }
    9184        1332 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    9185             :     {
    9186         666 :         clearInputMc( &hIvasRend->inputsMc[i] );
    9187             :     }
    9188        1332 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    9189             :     {
    9190         666 :         clearInputSba( &hIvasRend->inputsSba[i] );
    9191             :     }
    9192        1332 :     FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
    9193             :     {
    9194         666 :         clearInputMasa( &hIvasRend->inputsMasa[i] );
    9195             :     }
    9196             : 
    9197             :     /* clear Config. Renderer */
    9198         666 :     ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
    9199             : 
    9200         666 :     ivas_limiter_close_fx( &hIvasRend->hLimiter );
    9201             : 
    9202             :     /* Split binaural rendering */
    9203         666 :     IF( hIvasRend->splitRendWrapper != NULL )
    9204             :     {
    9205           0 :         ISAR_PRE_REND_close( hIvasRend->splitRendWrapper, &hIvasRend->splitRendEncBuffer );
    9206           0 :         free( hIvasRend->splitRendWrapper );
    9207           0 :         hIvasRend->splitRendWrapper = NULL;
    9208             :     }
    9209             : 
    9210         666 :     closeHeadRotation( hIvasRend );
    9211             : 
    9212         666 :     ivas_external_orientation_close_fx( &hIvasRend->hExternalOrientationData );
    9213         666 :     ivas_combined_orientation_close_fx( &hIvasRend->hCombinedOrientationData );
    9214             : 
    9215             :     /* Fastconv HRTF memories */
    9216         666 :     ivas_binaural_hrtf_close( &hIvasRend->hHrtfs.hHrtfFastConv );
    9217             : 
    9218             :     /* Parametric binauralizer HRTF filters */
    9219         666 :     ivas_HRTF_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfTD ) );
    9220         666 :     ivas_HRTF_CRend_binary_close_fx( &( hIvasRend->hHrtfs.hSetOfHRTF ) );
    9221         666 :     ivas_HRTF_fastconv_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfFastConv ) );
    9222         666 :     ivas_HRTF_parambin_binary_close_fx( &( hIvasRend->hHrtfs.hHrtfParambin ) );
    9223         666 :     ivas_HRTF_statistics_close( &( hIvasRend->hHrtfs.hHrtfStatistics ) );
    9224             : 
    9225         666 :     free( hIvasRend );
    9226         666 :     *phIvasRend = NULL;
    9227             : 
    9228         666 :     return;
    9229             : }
    9230             : 
    9231             : /*-------------------------------------------------------------------*
    9232             :  * IVAS_REND_openCldfb()
    9233             :  *
    9234             :  *
    9235             :  *-------------------------------------------------------------------*/
    9236             : 
    9237           0 : ivas_error IVAS_REND_openCldfb(
    9238             :     IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
    9239             :     IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS],
    9240             :     const Word16 num_in_chs,
    9241             :     const Word16 num_out_chs,
    9242             :     const Word32 output_Fs )
    9243             : {
    9244             :     Word16 n;
    9245             :     ivas_error error;
    9246             : 
    9247           0 :     FOR( n = 0; n < num_in_chs; n++ )
    9248             :     {
    9249           0 :         IF( ( error = openCldfb_ivas_fx( &( cldfbAna[n] ), CLDFB_ANALYSIS, output_Fs, CLDFB_PROTOTYPE_5_00MS, DEC ) ) != IVAS_ERR_OK )
    9250             :         {
    9251           0 :             return error;
    9252             :         }
    9253             :     }
    9254           0 :     FOR( ; n < IVAS_MAX_INPUT_CHANNELS; n++ )
    9255             :     {
    9256           0 :         cldfbAna[n] = NULL;
    9257             :     }
    9258             : 
    9259           0 :     FOR( n = 0; n < num_out_chs; n++ )
    9260             :     {
    9261           0 :         IF( ( error = openCldfb_ivas_fx( &( cldfbSyn[n] ), CLDFB_SYNTHESIS, output_Fs, CLDFB_PROTOTYPE_5_00MS, DEC ) ) != IVAS_ERR_OK )
    9262             :         {
    9263           0 :             return error;
    9264             :         }
    9265             :     }
    9266           0 :     FOR( ; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
    9267             :     {
    9268           0 :         cldfbSyn[n] = NULL;
    9269             :     }
    9270             : 
    9271           0 :     return IVAS_ERR_OK;
    9272             : }
    9273             : 
    9274             : 
    9275             : /*-------------------------------------------------------------------*
    9276             :  * IVAS_REND_closeCldfb()
    9277             :  *
    9278             :  *
    9279             :  *-------------------------------------------------------------------*/
    9280             : 
    9281           0 : void IVAS_REND_closeCldfb(
    9282             :     IVAS_CLDFB_FILTER_BANK_HANDLE cldfbAna[IVAS_MAX_INPUT_CHANNELS],
    9283             :     IVAS_CLDFB_FILTER_BANK_HANDLE cldfbSyn[IVAS_MAX_OUTPUT_CHANNELS] )
    9284             : {
    9285             :     Word16 n;
    9286             : 
    9287           0 :     FOR( n = 0; n < IVAS_MAX_INPUT_CHANNELS; n++ )
    9288             :     {
    9289           0 :         IF( cldfbAna[n] != NULL )
    9290             :         {
    9291           0 :             deleteCldfb_ivas_fx( &( cldfbAna[n] ) );
    9292           0 :             cldfbAna[n] = NULL;
    9293             :         }
    9294             :     }
    9295             : 
    9296           0 :     FOR( n = 0; n < IVAS_MAX_OUTPUT_CHANNELS; n++ )
    9297             :     {
    9298           0 :         IF( cldfbSyn[n] != NULL )
    9299             :         {
    9300           0 :             deleteCldfb_ivas_fx( &( cldfbSyn[n] ) );
    9301           0 :             cldfbSyn[n] = NULL;
    9302             :         }
    9303             :     }
    9304             : 
    9305           0 :     return;
    9306             : }
    9307             : 
    9308             : 
    9309             : /*-------------------------------------------------------------------*
    9310             :  * IVAS_REND_cldfbSynthesis_wrapper()
    9311             :  *
    9312             :  *
    9313             :  *-------------------------------------------------------------------*/
    9314             : 
    9315           0 : void IVAS_REND_cldfbAnalysis_ts_wrapper(
    9316             :     const Word32 *timeIn,                          /* i  : time buffer         */
    9317             :     Word32 realBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o  : real value buffer   */
    9318             :     Word32 imagBuffer[IVAS_CLDFB_NO_CHANNELS_MAX], /* o  : imag value buffer   */
    9319             :     const Word16 samplesToProcess,                 /* i  : samples to process  */
    9320             :     IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb,         /* i  : filterbank state    */
    9321             :     Word16 Q_in,
    9322             :     Word16 *Q_out )
    9323             : {
    9324             : 
    9325           0 :     Word16 Q_cldfb = Q_in;
    9326           0 :     assert( Q_in == h_cldfb->Q_cldfb_state );
    9327           0 :     cldfbAnalysis_ts_fx_fixed_q( timeIn, realBuffer, imagBuffer, samplesToProcess, h_cldfb, &Q_cldfb );
    9328             : 
    9329           0 :     *Q_out = sub( Q_in, 5 );
    9330             : 
    9331           0 :     return;
    9332             : }
    9333             : 
    9334             : 
    9335             : /*-------------------------------------------------------------------*
    9336             :  * IVAS_REND_cldfbSynthesis_wrapper()
    9337             :  *
    9338             :  *
    9339             :  *-------------------------------------------------------------------*/
    9340             : 
    9341           0 : void IVAS_REND_cldfbSynthesis_wrapper(
    9342             :     Word32 **realBuffer,                   /* i  : real values                 */
    9343             :     Word32 **imagBuffer,                   /* i  : imag values                 */
    9344             :     Word32 *timeOut,                       /* o  : output time domain samples  */
    9345             :     const Word16 samplesToProcess,         /* i  : number of processed samples */
    9346             :     IVAS_CLDFB_FILTER_BANK_HANDLE h_cldfb, /* i  : filter bank state           */
    9347             :     Word16 Q_cldfb,
    9348             :     Word16 *Q_out )
    9349             : {
    9350             : 
    9351           0 :     Scale_sig32( h_cldfb->cldfb_state_fx, h_cldfb->p_filter_length, sub( sub( Q_cldfb, 1 ), h_cldfb->Q_cldfb_state ) );
    9352           0 :     cldfbSynthesis_ivas_fx( realBuffer, imagBuffer, timeOut, samplesToProcess, 0, 0, h_cldfb ); // Q_cldfb - 1
    9353           0 :     *Q_out = sub( Q_cldfb, 1 );
    9354           0 :     move16();
    9355           0 :     h_cldfb->Q_cldfb_state = *Q_out;
    9356           0 :     move16();
    9357             : 
    9358           0 :     return;
    9359             : }
    9360             : 
    9361             : 
    9362             : /*---------------------------------------------------------------------*
    9363             :  * IVAS_REND_GetHrtfHandle( )
    9364             :  *
    9365             :  *
    9366             :  *---------------------------------------------------------------------*/
    9367             : 
    9368           0 : ivas_error IVAS_REND_GetHrtfHandle(
    9369             :     IVAS_REND_HANDLE hIvasRend,    /* i/o: IVAS renderer handle     */
    9370             :     IVAS_DEC_HRTF_HANDLE **hHrtfTD /* o  : HRTF handle              */
    9371             : )
    9372             : {
    9373           0 :     if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfTD == NULL )
    9374             :     {
    9375           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    9376             :     }
    9377             : 
    9378           0 :     *hHrtfTD = &hIvasRend->hHrtfs.hHrtfTD;
    9379             : 
    9380           0 :     return IVAS_ERR_OK;
    9381             : }
    9382             : 
    9383             : 
    9384             : /*---------------------------------------------------------------------*
    9385             :  * IVAS_REND_GetHrtfCRendHandle( )
    9386             :  *
    9387             :  *
    9388             :  *---------------------------------------------------------------------*/
    9389             : 
    9390           0 : ivas_error IVAS_REND_GetHrtfCRendHandle(
    9391             :     IVAS_REND_HANDLE hIvasRend,             /* i/o: IVAS renderer handle     */
    9392             :     IVAS_DEC_HRTF_CREND_HANDLE **hSetOfHRTF /* o  : Set of HRTF handle       */
    9393             : )
    9394             : {
    9395           0 :     if ( hIvasRend == NULL || hIvasRend->hHrtfs.hSetOfHRTF == NULL )
    9396             :     {
    9397           0 :         return IVAS_ERR_WRONG_PARAMS;
    9398             :     }
    9399             : 
    9400           0 :     *hSetOfHRTF = &hIvasRend->hHrtfs.hSetOfHRTF;
    9401             : 
    9402           0 :     return IVAS_ERR_OK;
    9403             : }
    9404             : 
    9405             : 
    9406             : /*---------------------------------------------------------------------*
    9407             :  * IVAS_REND_GetHrtfFastConvHandle( )
    9408             :  *
    9409             :  *
    9410             :  *---------------------------------------------------------------------*/
    9411             : 
    9412           0 : ivas_error IVAS_REND_GetHrtfFastConvHandle(
    9413             :     IVAS_REND_HANDLE hIvasRend,                   /* i/o: IVAS renderer handle   */
    9414             :     IVAS_DEC_HRTF_FASTCONV_HANDLE **hHrtfFastConv /* o  : FASTCONV HRTF handle   */
    9415             : )
    9416             : {
    9417           0 :     if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfFastConv == NULL )
    9418             :     {
    9419           0 :         return IVAS_ERR_WRONG_PARAMS;
    9420             :     }
    9421             : 
    9422           0 :     *hHrtfFastConv = &hIvasRend->hHrtfs.hHrtfFastConv;
    9423             : 
    9424           0 :     return IVAS_ERR_OK;
    9425             : }
    9426             : 
    9427             : 
    9428             : /*---------------------------------------------------------------------*
    9429             :  * IVAS_REND_GetHrtfParamBinHandle( )
    9430             :  *
    9431             :  *
    9432             :  *---------------------------------------------------------------------*/
    9433             : 
    9434           0 : ivas_error IVAS_REND_GetHrtfParamBinHandle(
    9435             :     IVAS_REND_HANDLE hIvasRend,                   /* i/o: IVAS renderer handle                */
    9436             :     IVAS_DEC_HRTF_PARAMBIN_HANDLE **hHrtfParambin /* o  : Parametric binauralizer HRTF handle */
    9437             : )
    9438             : {
    9439           0 :     if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfParambin == NULL )
    9440             :     {
    9441           0 :         return IVAS_ERR_WRONG_PARAMS;
    9442             :     }
    9443             : 
    9444           0 :     *hHrtfParambin = &hIvasRend->hHrtfs.hHrtfParambin;
    9445             : 
    9446           0 :     return IVAS_ERR_OK;
    9447             : }
    9448             : 
    9449             : 
    9450             : /*---------------------------------------------------------------------*
    9451             :  * IVAS_REND_GetHrtfStatisticsHandle( )
    9452             :  *
    9453             :  *
    9454             :  *---------------------------------------------------------------------*/
    9455             : 
    9456           0 : ivas_error IVAS_REND_GetHrtfStatisticsHandle(
    9457             :     IVAS_REND_HANDLE hIvasRend,                       /* i/o: IVAS renderer handle    */
    9458             :     IVAS_DEC_HRTF_STATISTICS_HANDLE **hHrtfStatistics /* o  : HRTF statistics handle  */
    9459             : )
    9460             : {
    9461           0 :     if ( hIvasRend == NULL || hIvasRend->hHrtfs.hHrtfStatistics == NULL )
    9462             :     {
    9463           0 :         return IVAS_ERR_WRONG_PARAMS;
    9464             :     }
    9465             : 
    9466           0 :     *hHrtfStatistics = &hIvasRend->hHrtfs.hHrtfStatistics;
    9467             : 
    9468           0 :     return IVAS_ERR_OK;
    9469             : }
    9470             : 
    9471          34 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
    9472             :     input_masa *inputMasa )
    9473             : {
    9474             :     Word16 nchan_out_woLFE;
    9475             :     Word16 nchan_transport;
    9476             :     UWord16 i, j, k;
    9477             :     Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS];   /*Q22*/
    9478             :     Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
    9479             :     Word32 output_Fs;
    9480             :     ivas_error error;
    9481             :     DIRAC_REND_HANDLE hDirACRend;
    9482             :     SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
    9483             : 
    9484          34 :     error = IVAS_ERR_OK;
    9485          34 :     move32();
    9486             : 
    9487          34 :     hDirACRend = NULL;
    9488          34 :     output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
    9489          34 :     move32();
    9490             : 
    9491          34 :     hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
    9492             : 
    9493             :     /*-----------------------------------------------------------------*
    9494             :      * prepare library opening
    9495             :      *-----------------------------------------------------------------*/
    9496             : 
    9497          34 :     IF( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
    9498             :     {
    9499           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
    9500             :     }
    9501             : 
    9502          34 :     IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    9503             :     {
    9504          18 :         nchan_transport = 2;
    9505          18 :         move16();
    9506             :     }
    9507             :     ELSE
    9508             :     {
    9509          16 :         nchan_transport = 1;
    9510          16 :         move16();
    9511             :     }
    9512             : 
    9513             :     /*-----------------------------------------------------------------*
    9514             :      * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
    9515             :      *-----------------------------------------------------------------*/
    9516             : 
    9517          34 :     ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
    9518             : 
    9519          34 :     IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    9520             :     {
    9521             :         /* Copy from ivas_ls_custom_setup */
    9522           0 :         hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
    9523           0 :         move16();
    9524           0 :         hDirACRend->hOutSetup.ls_azimuth_fx = inputMasa->base.ctx.pCustomLsOut->ls_azimuth_fx;
    9525           0 :         hDirACRend->hOutSetup.ls_elevation_fx = inputMasa->base.ctx.pCustomLsOut->ls_elevation_fx;
    9526             : 
    9527           0 :         hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
    9528           0 :         move16();
    9529           0 :         hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
    9530           0 :         move16();
    9531             : 
    9532           0 :         hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
    9533           0 :         move16();
    9534           0 :         hDirACRend->hOutSetup.is_planar_setup = (Word8) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
    9535           0 :         move16();
    9536             :     }
    9537             : 
    9538          34 :     nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
    9539          34 :     move16();
    9540             : 
    9541          34 :     test();
    9542          34 :     IF( hDirACRend->hOutSetup.ls_azimuth_fx != NULL && hDirACRend->hOutSetup.ls_elevation_fx != NULL )
    9543             :     {
    9544          20 :         Copy32( hDirACRend->hOutSetup.ls_azimuth_fx, ls_azimuth_fx, nchan_out_woLFE );
    9545          20 :         Copy32( hDirACRend->hOutSetup.ls_elevation_fx, ls_elevation_fx, nchan_out_woLFE );
    9546             :     }
    9547             : 
    9548          34 :     IF( EQ_16( hDirACRend->hOutSetup.ambisonics_order, -1 ) )
    9549             :     {
    9550          22 :         hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
    9551          22 :         move16();
    9552          22 :         test();
    9553          22 :         if ( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_STEREO ) )
    9554             :         {
    9555           2 :             hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
    9556           2 :             move16();
    9557             :         }
    9558             :     }
    9559          12 :     ELSE IF( GE_16( hDirACRend->hOutSetup.ambisonics_order, SBA_FOA_ORDER ) )
    9560             :     {
    9561          12 :         Copy32( ls_azimuth_4d4_fx, ls_azimuth_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
    9562          12 :         Copy32( ls_elevation_4d4_fx, ls_elevation_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
    9563             :     }
    9564             : 
    9565             :     /*-----------------------------------------------------------------*
    9566             :      * set input parameters
    9567             :      *-----------------------------------------------------------------*/
    9568             : 
    9569          34 :     test();
    9570          34 :     IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
    9571             :     {
    9572           2 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
    9573           2 :         move32();
    9574           2 :         hDirACRend->panningConf = DIRAC_PANNING_HOA3;
    9575           2 :         move32();
    9576           2 :         nchan_out_woLFE = 1;
    9577           2 :         move16();
    9578             :     }
    9579          32 :     ELSE IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
    9580             :     {
    9581          20 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
    9582          20 :         hDirACRend->panningConf = DIRAC_PANNING_VBAP;
    9583          20 :         move32();
    9584          20 :         move32();
    9585             :     }
    9586          12 :     ELSE IF( !hDirACRend->hOutSetup.is_loudspeaker_setup && GT_16( nchan_transport, 1 ) )
    9587             :     {
    9588           6 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
    9589           6 :         move32();
    9590           6 :         hDirACRend->panningConf = DIRAC_PANNING_HOA3;
    9591           6 :         move32();
    9592             :     }
    9593             :     ELSE
    9594             :     {
    9595           6 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
    9596           6 :         move32();
    9597           6 :         hDirACRend->panningConf = DIRAC_PANNING_HOA3;
    9598           6 :         move32();
    9599             :     }
    9600             : 
    9601          34 :     IF( ( hDirACRend->frequency_axis_fx = (Word16 *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( Word16 ) ) ) == NULL )
    9602             :     {
    9603           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9604             :     }
    9605          34 :     set16_fx( hDirACRend->frequency_axis_fx, 0, hSpatParamRendCom->num_freq_bands );
    9606          34 :     ivas_dirac_dec_get_frequency_axis_fx( hDirACRend->frequency_axis_fx, output_Fs, hSpatParamRendCom->num_freq_bands );
    9607             : 
    9608          34 :     test();
    9609          34 :     IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) && EQ_16( nchan_transport, 2 ) )
    9610             :     {
    9611           8 :         IF( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
    9612             :         {
    9613           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9614             :         }
    9615           8 :         ivas_masa_init_stereotype_detection_fx( hDirACRend->masa_stereo_type_detect );
    9616             :     }
    9617             :     ELSE
    9618             :     {
    9619          26 :         hDirACRend->masa_stereo_type_detect = NULL;
    9620             :     }
    9621             : 
    9622          34 :     hSpatParamRendCom->numIsmDirections = 0;
    9623          34 :     move16();
    9624             : 
    9625             :     /*-----------------------------------------------------------------*
    9626             :      * (re)configure sub-modules
    9627             :      *-----------------------------------------------------------------*/
    9628             : 
    9629             :     /* prototype signal computation */
    9630             :     /* allocate output setup related arrays */
    9631          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
    9632             :     {
    9633             :         /* Directional and diffuses components in output LS format */
    9634          20 :         hDirACRend->num_outputs_diff = nchan_out_woLFE;
    9635          20 :         move16();
    9636          20 :         hDirACRend->num_outputs_dir = nchan_out_woLFE;
    9637          20 :         move16();
    9638             :     }
    9639          14 :     ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    9640             :     {
    9641             :         /* Directional and diffuses components in SHD */
    9642             :         /* Diffuseness components up to 1st order */
    9643           6 :         hDirACRend->num_outputs_diff = imult1616( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ), ( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ) ) );
    9644           6 :         hDirACRend->num_outputs_dir = ivas_sba_get_nchan_fx( hDirACRend->hOutSetup.ambisonics_order, 0 );
    9645             :     }
    9646           8 :     ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
    9647             :     {
    9648           6 :         hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
    9649           6 :         move16();
    9650           6 :         hDirACRend->num_outputs_dir = nchan_out_woLFE;
    9651           6 :         move16();
    9652             :     }
    9653           2 :     ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
    9654             :     {
    9655           2 :         hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
    9656           2 :         move16();
    9657           2 :         hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
    9658           2 :         move16();
    9659             :     }
    9660             :     ELSE
    9661             :     {
    9662           0 :         assert( 0 && "DirAC: not existing synthesis methods!" );
    9663             :     }
    9664             : 
    9665          34 :     IF( ( hDirACRend->proto_index_dir = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
    9666             :     {
    9667           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9668             :     }
    9669             : 
    9670          34 :     IF( ( hDirACRend->proto_index_diff = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_diff ) ) == NULL )
    9671             :     {
    9672           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9673             :     }
    9674             : 
    9675          34 :     set16_fx( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
    9676          34 :     set16_fx( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
    9677             : 
    9678          34 :     hDirACRend->sba_map_tc = sba_map_tc;
    9679             : 
    9680          34 :     IF( EQ_16( nchan_transport, 1 ) )
    9681             :     {
    9682          16 :         hDirACRend->num_protos_ambi = 1;
    9683          16 :         move16();
    9684          16 :         hDirACRend->num_protos_dir = 1;
    9685          16 :         move16();
    9686          16 :         hDirACRend->num_protos_diff = 1;
    9687          16 :         move16();
    9688             :     }
    9689          18 :     ELSE IF( EQ_16( nchan_transport, 2 ) )
    9690             :     {
    9691          18 :         IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    9692             :         {
    9693           0 :             hDirACRend->num_protos_ambi = 2;
    9694           0 :             move16();
    9695           0 :             hDirACRend->num_protos_diff = 1;
    9696           0 :             move16();
    9697           0 :             hDirACRend->num_protos_dir = 2;
    9698           0 :             move16();
    9699           0 :             hDirACRend->proto_index_dir[1] = 1;
    9700           0 :             move16();
    9701             :         }
    9702          18 :         ELSE IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
    9703             :         {
    9704             :             /* Following the foa rendering for code compatibility */
    9705           2 :             hDirACRend->num_protos_ambi = 2;
    9706           2 :             move16();
    9707           2 :             hDirACRend->num_protos_dir = 2;
    9708           2 :             move16();
    9709           2 :             hDirACRend->num_protos_diff = 3;
    9710           2 :             move16();
    9711           2 :             hDirACRend->proto_index_dir[0] = 0;
    9712           2 :             move16();
    9713           2 :             hDirACRend->proto_index_diff[0] = 0;
    9714           2 :             move16();
    9715             :         }
    9716             :         ELSE
    9717             :         {
    9718          16 :             hDirACRend->num_protos_ambi = 2;
    9719          16 :             move16();
    9720          16 :             hDirACRend->num_protos_diff = 3;
    9721          16 :             move16();
    9722             : 
    9723         142 :             FOR( k = 0; k < hDirACRend->num_outputs_diff; k++ )
    9724             :             {
    9725         126 :                 IF( ls_azimuth_fx[k] > 0 )
    9726             :                 {
    9727          58 :                     hDirACRend->proto_index_diff[k] = 1;
    9728             :                 }
    9729          68 :                 ELSE IF( ls_azimuth_fx[k] < 0 )
    9730             :                 {
    9731          58 :                     hDirACRend->proto_index_diff[k] = 2;
    9732             :                 }
    9733             :                 ELSE
    9734             :                 {
    9735          10 :                     hDirACRend->proto_index_diff[k] = 0;
    9736             :                 }
    9737         126 :                 move16();
    9738             :             }
    9739             : 
    9740          16 :             IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
    9741             :             {
    9742          10 :                 hDirACRend->num_protos_dir = 3;
    9743          10 :                 move16();
    9744          10 :                 Copy( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
    9745             :             }
    9746             :             ELSE
    9747             :             {
    9748           6 :                 hDirACRend->num_protos_dir = 2;
    9749           6 :                 move16();
    9750           6 :                 hDirACRend->proto_index_dir[1] = 1;
    9751           6 :                 move16();
    9752             :             }
    9753             :         }
    9754             :     }
    9755             : 
    9756             :     /* direct/diffuse responses */
    9757          34 :     IF( ( hDirACRend->diffuse_response_function_fx = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
    9758             :     {
    9759           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9760             :     }
    9761             : 
    9762          34 :     test();
    9763          34 :     test();
    9764          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
    9765             :     {
    9766          28 :         initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
    9767          28 :                                  hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
    9768             :     }
    9769             :     ELSE
    9770             :     {
    9771           6 :         initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
    9772           6 :                                  hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
    9773             :     }
    9774             : 
    9775          34 :     hDirACRend->hoa_encoder_fx = NULL;
    9776          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
    9777             :     {
    9778           6 :         IF( ( hDirACRend->hoa_encoder_fx = (Word32 *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( Word32 ) ) ) == NULL )
    9779             :         {
    9780           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9781             :         }
    9782             : 
    9783           6 :         set32_fx( hDirACRend->hoa_encoder_fx, 0, imult1616( nchan_out_woLFE, hDirACRend->num_outputs_diff ) );
    9784           6 :         compute_hoa_encoder_mtx_fx( ls_azimuth_fx, ls_elevation_fx, hDirACRend->hoa_encoder_fx, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
    9785             :     }
    9786             : 
    9787             :     /* VBAP */
    9788          34 :     inputMasa->hMasaExtRend->hVBAPdata = NULL;
    9789             : 
    9790          34 :     IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_VBAP ) )
    9791             :     {
    9792          20 :         IF( NE_32( ( error = vbap_init_data_fx( &( inputMasa->hMasaExtRend->hVBAPdata ), ls_azimuth_fx, ls_elevation_fx, nchan_out_woLFE, MASA_FORMAT ) ), IVAS_ERR_OK ) )
    9793             :         {
    9794           0 :             return error;
    9795             :         }
    9796             :     }
    9797             : 
    9798             :     /* HOA panning/dec */
    9799          34 :     hDirACRend->hoa_decoder = NULL;
    9800          34 :     IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) )
    9801             :     {
    9802          14 :         IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
    9803             :         {
    9804           2 :             IF( NE_32( ( error = ivas_sba_get_hoa_dec_matrix_fx( hDirACRend->hOutSetup, &inputMasa->hMasaExtRend->hoa_dec_mtx, hDirACRend->hOutSetup.ambisonics_order ) ), IVAS_ERR_OK ) )
    9805             :             {
    9806           0 :                 return error;
    9807             :             }
    9808             : 
    9809           2 :             hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
    9810             :         }
    9811             :     }
    9812             : 
    9813             :     /* decorrelation */
    9814          34 :     hDirACRend->proto_signal_decorr_on = 1;
    9815          34 :     move16();
    9816          34 :     if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
    9817             :     {
    9818           2 :         hDirACRend->proto_signal_decorr_on = 0;
    9819           2 :         move16();
    9820             :     }
    9821             : 
    9822          34 :     IF( hDirACRend->proto_signal_decorr_on )
    9823             :     {
    9824          32 :         IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDirACRend->h_freq_domain_decorr_ap_params ),
    9825             :                                                             &( hDirACRend->h_freq_domain_decorr_ap_state ),
    9826             :                                                             hSpatParamRendCom->num_freq_bands,
    9827             :                                                             hDirACRend->num_outputs_diff,
    9828             :                                                             hDirACRend->num_protos_diff,
    9829             :                                                             hDirACRend->synthesisConf,
    9830             :                                                             hDirACRend->frequency_axis_fx,
    9831             :                                                             nchan_transport,
    9832             :                                                             output_Fs ) ),
    9833             :                    IVAS_ERR_OK ) )
    9834             :         {
    9835           0 :             return error;
    9836             :         }
    9837             :     }
    9838             : 
    9839             :     /* output synthesis */
    9840          34 :     IF( NE_32( ( ivas_dirac_dec_output_synthesis_open_fx( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ), IVAS_ERR_OK ) )
    9841             :     {
    9842           0 :         return error;
    9843             :     }
    9844          34 :     hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
    9845          34 :     move16();
    9846             : 
    9847          34 :     test();
    9848          34 :     if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    9849             :     {
    9850          12 :         hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
    9851          12 :         move16();
    9852             :     }
    9853             : 
    9854             :     /*-----------------------------------------------------------------*
    9855             :      * memory allocation
    9856             :      *-----------------------------------------------------------------*/
    9857             : 
    9858          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    9859             :     {
    9860           6 :         hDirACRend->proto_frame_f_fx = NULL;
    9861             :     }
    9862             :     ELSE
    9863             :     {
    9864          28 :         IF( ( hDirACRend->proto_frame_f_fx = (Word32 *) malloc( sizeof( Word32 ) * shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 ) ) ) == NULL )
    9865             :         {
    9866           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    9867             :         }
    9868          28 :         hDirACRend->proto_frame_f_len = shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 );
    9869          28 :         move16();
    9870             :     }
    9871             : 
    9872             : 
    9873          34 :     hDirACRend->buffer_energy_fx = NULL;
    9874         136 :     FOR( i = 0; i < DIRAC_NUM_DIMS; i++ )
    9875             :     {
    9876        3366 :         FOR( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
    9877             :         {
    9878        3264 :             hDirACRend->buffer_intensity_real_fx[i][j] = NULL;
    9879             :         }
    9880             :     }
    9881             : 
    9882             :     /* output synthesis */
    9883          34 :     ivas_dirac_dec_output_synthesis_init_fx( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
    9884             : 
    9885             :     /* Allocate stack memory */
    9886          34 :     IF( NE_32( ( error = ivas_dirac_alloc_mem_fx( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ), IVAS_ERR_OK ) )
    9887             :     {
    9888           0 :         return error;
    9889             :     }
    9890             : 
    9891          34 :     inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
    9892             : 
    9893          34 :     return error;
    9894             : }
    9895             : 
    9896             : 
    9897          12 : static ivas_error ivas_masa_ext_rend_parambin_init(
    9898             :     input_masa *inputMasa,                  /* i/o: MASA external renderer structure        */
    9899             :     const RENDER_CONFIG_DATA *hRendCfg,     /* i  : Renderer configuration data handle      */
    9900             :     HRTFS_STATISTICS_HANDLE hHrtfStatistics /* i  : HRTF statistics                         */
    9901             : )
    9902             : {
    9903             :     DIRAC_DEC_BIN_HANDLE hDiracDecBin;
    9904             : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
    9905             :     HRTFS_PARAMBIN_HANDLE *phHrtfParambin;
    9906             : #else
    9907             :     HRTFS_PARAMBIN_HANDLE hHrtfParambin;
    9908             : #endif
    9909             :     Word16 nBins;
    9910             :     Word32 output_Fs;
    9911             :     RENDERER_TYPE renderer_type;
    9912             :     Word16 j, k, bin;
    9913             :     Word32 binCenterFreq_fx;
    9914             :     Word16 tmpFloat_fx;
    9915             :     ivas_error error;
    9916             :     Word16 frequency_axis_fx[CLDFB_NO_CHANNELS_MAX];
    9917             : #ifdef FIX_587_DEFAULT_REVERB
    9918             :     const IVAS_ROOM_ACOUSTICS_CONFIG_DATA *pRoomAcoustics;
    9919             : #endif
    9920             : 
    9921             :     Word16 pos_idx, num_poses;
    9922             :     Word16 tmp;
    9923             :     Word16 tmp_e;
    9924             :     Word16 tmp2;
    9925             : 
    9926          12 :     error = IVAS_ERR_OK;
    9927          12 :     move32();
    9928             : 
    9929             : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
    9930          12 :     phHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
    9931             : #else
    9932             :     hHrtfParambin = *( inputMasa->hMasaExtRend->hHrtfParambin );
    9933             : #endif
    9934             :     /* Set common variables and defaults */
    9935          12 :     output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
    9936          12 :     move32();
    9937          12 :     nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
    9938          12 :     move16();
    9939          12 :     renderer_type = inputMasa->hMasaExtRend->renderer_type;
    9940          12 :     move32();
    9941             : 
    9942          12 :     num_poses = 1;
    9943          12 :     move16();
    9944          12 :     if ( inputMasa->base.ctx.pSplitRendWrapper != NULL )
    9945             :     {
    9946           0 :         num_poses = inputMasa->base.ctx.pSplitRendWrapper->multiBinPoseData.num_poses;
    9947           0 :         move16();
    9948             :     }
    9949             : 
    9950          24 :     for ( pos_idx = 0; pos_idx < num_poses; pos_idx++ )
    9951             :     {
    9952          12 :         hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin[pos_idx];
    9953             : 
    9954             :         /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
    9955          12 :         IF( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
    9956             :         {
    9957           0 :             return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
    9958             :         }
    9959             : 
    9960          12 :         hDiracDecBin->hTdDecorr = NULL;
    9961          12 :         hDiracDecBin->hReverb = NULL;
    9962          12 :         hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
    9963          12 :         hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
    9964          12 :         hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
    9965          12 :         hDiracDecBin->useTdDecorr = 0;     /* Always use frequency domain decorrelator in external renderer */
    9966          12 :         move16();
    9967             : 
    9968          36 :         FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
    9969             :         {
    9970         168 :             FOR( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
    9971             :             {
    9972         144 :                 set16_fx( hDiracDecBin->processMtxRe_fx[j][k], 0, nBins );
    9973         144 :                 set16_fx( hDiracDecBin->processMtxIm_fx[j][k], 0, nBins );
    9974             :             }
    9975             : 
    9976          72 :             FOR( k = 0; k < BINAURAL_CHANNELS; k++ )
    9977             :             {
    9978          48 :                 set16_fx( hDiracDecBin->processMtxDecRe_fx[j][k], 0, nBins );
    9979          48 :                 set16_fx( hDiracDecBin->processMtxDecIm_fx[j][k], 0, nBins );
    9980             :             }
    9981          24 :             hDiracDecBin->q_processMtx = Q15;
    9982          24 :             hDiracDecBin->q_processMtxSCCR = Q15;
    9983          24 :             hDiracDecBin->q_processMtxPrev = Q15;
    9984          24 :             hDiracDecBin->q_processMtxPrevSCCR = Q15;
    9985          24 :             hDiracDecBin->q_processMtxDec = Q15;
    9986          24 :             hDiracDecBin->q_processMtxDecPrev = Q15;
    9987          24 :             move16();
    9988          24 :             move16();
    9989          24 :             move16();
    9990          24 :             move16();
    9991          24 :             move16();
    9992          24 :             move16();
    9993          24 :             set_zero_fx( hDiracDecBin->ChEnePrev_fx[j], nBins );
    9994          24 :             set_zero_fx( hDiracDecBin->ChEneOutPrev_fx[j], nBins );
    9995          24 :             set16_fx( hDiracDecBin->ChEnePrev_e[j], 0, nBins );
    9996          24 :             set16_fx( hDiracDecBin->ChEneOutPrev_e[j], 0, nBins );
    9997             :         }
    9998          12 :         set_zero_fx( hDiracDecBin->ChCrossRePrev_fx, nBins );
    9999          12 :         set_zero_fx( hDiracDecBin->ChCrossImPrev_fx, nBins );
   10000          12 :         set_zero_fx( hDiracDecBin->ChCrossReOutPrev_fx, nBins );
   10001          12 :         set_zero_fx( hDiracDecBin->ChCrossImOutPrev_fx, nBins );
   10002          12 :         set16_fx( hDiracDecBin->ChCrossRePrev_e, 0, nBins );
   10003          12 :         set16_fx( hDiracDecBin->ChCrossImPrev_e, 0, nBins );
   10004          12 :         set16_fx( hDiracDecBin->ChCrossReOutPrev_e, 0, nBins );
   10005          12 :         set16_fx( hDiracDecBin->ChCrossImOutPrev_e, 0, nBins );
   10006          12 :         hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
   10007          12 :         move16();
   10008             : 
   10009         732 :         FOR( bin = 0; bin < nBins; bin++ )
   10010             :         {
   10011         720 :             binCenterFreq_fx = L_mult0( extract_l( L_shr( output_Fs, 1 ) ), div_s( add( shl( bin, 1 ), 1 ), shl( nBins, 1 ) ) ) /*( (float) bin + 0.5f ) / (float) nBins * ( (float) output_Fs / 2.0f )*/; /*Q15*/
   10012             :             /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
   10013         720 :             tmp = BASOP_Util_Divide3232_Scale( binCenterFreq_fx, L_shl( 2700, Q15 ), &tmp_e );
   10014         720 :             IF( tmp_e < 0 )
   10015             :             {
   10016          36 :                 tmp = shl( tmp, tmp_e ); /*q15*/
   10017          36 :                 tmp_e = 0;
   10018          36 :                 move16();
   10019             :             }
   10020         720 :             tmpFloat_fx = s_max( 0, sub( shl_sat( 1, sub( 15, tmp_e ) ), tmp ) ) /*max( 0.0f, 1.0f - binCenterFreq / 2700.0f )*/;                                                             /*Q30*/
   10021         720 :             tmp2 = extract_l( Mult_32_32( binCenterFreq_fx, 1952258 /*=2^31*180/(550)/360*/ ) % 32767 );                                                                                      //*binCenterFreq_fx * EVS_PI / 550.0f*/
   10022         720 :             hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( L_mult0( divide3232( tmpFloat_fx, Mult_32_16( binCenterFreq_fx, 187 /*2^15*pi/550*/ ) ), getSineWord16R2( tmp2 ) ), tmp_e ); /*tmpFloat * sinf( binCenterFreq * EVS_PI / 550.0f ) / ( binCenterFreq * EVS_PI / 550.0f );*/
   10023         720 :             hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( hDiracDecBin->diffuseFieldCoherence_fx[bin], 1 );                                                                            /* Q31 */
   10024         720 :             move32();
   10025         720 :             move32();
   10026             :         }
   10027             : 
   10028             :         /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
   10029          12 :         set_zero_fx( hDiracDecBin->diffuseFieldCoherenceX_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
   10030          12 :         set_zero_fx( hDiracDecBin->diffuseFieldCoherenceY_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
   10031          12 :         set_zero_fx( hDiracDecBin->diffuseFieldCoherenceZ_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
   10032             : 
   10033          12 :         IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC ) ) /* Indication of binaural rendering without room effect */
   10034             :         {
   10035           8 :             set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
   10036           8 :             hDiracDecBin->q_earlyPartEneCorrection = Q28;
   10037           8 :             move16();
   10038           8 :             hDiracDecBin->hReverb = NULL;
   10039             :         }
   10040           4 :         ELSE IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) /* Indication of binaural rendering with room effect */
   10041             :         {
   10042             : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
   10043             : #ifdef NONBE_FIX_981_PARAMBIN_DEFAULT_EARLY_PART
   10044           0 :             IF( EQ_32( *inputMasa->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) )
   10045             :             {
   10046           0 :                 Copy32( ( *phHrtfParambin )->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
   10047             : #ifdef FIX_587_DEFAULT_REVERB
   10048           0 :                 pRoomAcoustics = NULL;
   10049             : #endif
   10050             :             }
   10051             :             ELSE
   10052             :             {
   10053           0 :                 set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28, CLDFB_NO_CHANNELS_MAX );
   10054             : #ifdef FIX_587_DEFAULT_REVERB
   10055           0 :                 pRoomAcoustics = &( hRendCfg->roomAcoustics );
   10056             : #endif
   10057             :             }
   10058             : #else
   10059             :             Copy32( ( *phHrtfParambin )->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
   10060             : #endif
   10061             : #else
   10062             :             Copy32( hHrtfParambin->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
   10063             : #endif
   10064           0 :             hDiracDecBin->q_earlyPartEneCorrection = Q28;
   10065           0 :             move16();
   10066             : 
   10067           0 :             IF( hDiracDecBin->hReverb == NULL && pos_idx == 0 ) /* open reverb only for the main direction */
   10068             :             {
   10069             : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
   10070             : #ifdef FIX_587_DEFAULT_REVERB
   10071             : #ifdef FIX_1139_REV_COLORATION_SHORT_T60
   10072           0 :                 IF( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx, hDiracDecBin->earlyPartEneCorrection_fx ) ), IVAS_ERR_OK ) )
   10073             : #else
   10074             :                 if ( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, pRoomAcoustics, output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) )
   10075             : #endif
   10076             : #else
   10077             :                 if ( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRendCfg->roomAcoustics ), output_Fs, ( *phHrtfParambin )->parametricReverberationTimes_fx, ( *phHrtfParambin )->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) )
   10078             : #endif
   10079             : #else
   10080             :                 IF( NE_32( ( error = ivas_binaural_reverb_init( &hDiracDecBin->hReverb, hHrtfStatistics, nBins, CLDFB_NO_COL_MAX / MAX_PARAM_SPATIAL_SUBFRAMES, &( hRendCfg->roomAcoustics ), output_Fs, hHrtfParambin->parametricReverberationTimes_fx, hHrtfParambin->parametricReverberationEneCorrections_fx ) ), IVAS_ERR_OK ) )
   10081             : #endif
   10082             :                 {
   10083           0 :                     return error;
   10084             :                 }
   10085             :             }
   10086             :         }
   10087           4 :         ELSE IF( EQ_16( renderer_type, RENDERER_STEREO_PARAMETRIC ) )
   10088             :         {
   10089           4 :             set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
   10090           4 :             hDiracDecBin->q_earlyPartEneCorrection = Q28;
   10091           4 :             move16();
   10092           4 :             hDiracDecBin->hReverb = NULL;
   10093           4 :             hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
   10094           4 :             move16();
   10095             :         }
   10096             :         ELSE /* Not valid renderer type for this renderer */
   10097             :         {
   10098           0 :             assert( false );
   10099             :         }
   10100             : 
   10101          12 :         IF( pos_idx == 0 ) /* open decorrelator only for the main direction */
   10102             :         {
   10103             :             /* Always open frequency domain decorrelator */
   10104          12 :             ivas_dirac_dec_get_frequency_axis_fx( frequency_axis_fx, output_Fs, nBins );
   10105             : 
   10106          12 :             IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
   10107             :                                                                 &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
   10108             :                                                                 nBins,
   10109             :                                                                 BINAURAL_CHANNELS,
   10110             :                                                                 BINAURAL_CHANNELS,
   10111             :                                                                 DIRAC_SYNTHESIS_PSD_LS,
   10112             :                                                                 frequency_axis_fx,
   10113             :                                                                 BINAURAL_CHANNELS,
   10114             :                                                                 output_Fs ) ),
   10115             :                        IVAS_ERR_OK ) )
   10116             :             {
   10117           0 :                 return error;
   10118             :             }
   10119             :         }
   10120             : 
   10121             :         /* External renderer uses constant regularization factor */
   10122          12 :         hDiracDecBin->reqularizationFactor_fx = 6554; /* 0.4f in Q14 */
   10123          12 :         move16();
   10124             : 
   10125             : #ifdef NONBE_FIX_991_PARAMBIN_BINARY_HRTF
   10126          12 :         hDiracDecBin->phHrtfParambin = phHrtfParambin;
   10127             : #endif
   10128             : 
   10129          12 :         inputMasa->hMasaExtRend->hDiracDecBin[pos_idx] = hDiracDecBin;
   10130             :     }
   10131             : 
   10132          12 :     return error;
   10133             : }
   10134             : 
   10135             : 
   10136          48 : static ivas_error initMasaExtRenderer(
   10137             :     input_masa *inputMasa,
   10138             :     const AUDIO_CONFIG outConfig,
   10139             :     const RENDER_CONFIG_DATA *hRendCfg,
   10140             :     hrtf_handles *hrtfs )
   10141             : {
   10142             :     Word16 i;
   10143             :     ivas_error error;
   10144             :     MASA_EXT_REND_HANDLE hMasaExtRend;
   10145             : 
   10146          48 :     error = IVAS_ERR_OK;
   10147          48 :     move32();
   10148             : 
   10149          48 :     IF( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
   10150             :     {
   10151           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
   10152             :     }
   10153             : 
   10154          48 :     inputMasa->hMasaExtRend = hMasaExtRend;
   10155             : 
   10156             :     /* Default init */
   10157          48 :     hMasaExtRend->renderer_type = RENDERER_DISABLE;
   10158          48 :     move32();
   10159          48 :     hMasaExtRend->hDirACRend = NULL;
   10160          48 :     hMasaExtRend->hSpatParamRendCom = NULL;
   10161         432 :     for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
   10162             :     {
   10163         384 :         hMasaExtRend->hDiracDecBin[i] = NULL;
   10164             :     }
   10165          48 :     hMasaExtRend->hReverb = NULL;
   10166          48 :     hMasaExtRend->hHrtfParambin = &hrtfs->hHrtfParambin;
   10167          48 :     hMasaExtRend->hVBAPdata = NULL;
   10168          48 :     hMasaExtRend->hoa_dec_mtx = NULL;
   10169             : 
   10170          48 :     IF( NE_32( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ), IVAS_ERR_OK ) )
   10171             :     {
   10172           0 :         return error;
   10173             :     }
   10174             : 
   10175          48 :     IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
   10176             :     {
   10177           0 :         hMasaExtRend->nchan_output = add( inputMasa->base.ctx.pCustomLsOut->num_spk, inputMasa->base.ctx.pCustomLsOut->num_lfe );
   10178           0 :         move16();
   10179             :     }
   10180          48 :     ELSE IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ), IVAS_ERR_OK ) )
   10181             :     {
   10182           0 :         return error;
   10183             :     }
   10184             : 
   10185          48 :     SWITCH( outConfig )
   10186             :     {
   10187           4 :         case IVAS_AUDIO_CONFIG_MONO:
   10188           4 :             IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
   10189             :             {
   10190           2 :                 hMasaExtRend->renderer_type = RENDERER_DIRAC;
   10191           2 :                 move32();
   10192             :             }
   10193             :             ELSE
   10194             :             {
   10195             :                 /* 1TC MASA to mono does not need rendering. */
   10196           2 :                 hMasaExtRend->renderer_type = RENDERER_DISABLE;
   10197           2 :                 move32();
   10198             :             }
   10199           4 :             BREAK;
   10200             : 
   10201           4 :         case IVAS_AUDIO_CONFIG_STEREO:
   10202           4 :             hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
   10203           4 :             move32();
   10204           4 :             BREAK;
   10205             : 
   10206          32 :         case IVAS_AUDIO_CONFIG_5_1:
   10207             :         case IVAS_AUDIO_CONFIG_7_1:
   10208             :         case IVAS_AUDIO_CONFIG_5_1_2:
   10209             :         case IVAS_AUDIO_CONFIG_5_1_4:
   10210             :         case IVAS_AUDIO_CONFIG_7_1_4:
   10211             :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
   10212             :         case IVAS_AUDIO_CONFIG_FOA:
   10213             :         case IVAS_AUDIO_CONFIG_HOA2:
   10214             :         case IVAS_AUDIO_CONFIG_HOA3:
   10215          32 :             hMasaExtRend->renderer_type = RENDERER_DIRAC;
   10216          32 :             move32();
   10217          32 :             BREAK;
   10218             : 
   10219           8 :         case IVAS_AUDIO_CONFIG_BINAURAL:
   10220             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM:
   10221             :         case IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED:
   10222           8 :             hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
   10223           8 :             move32();
   10224           8 :             BREAK;
   10225             : 
   10226           0 :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
   10227             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
   10228           0 :             hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
   10229           0 :             move32();
   10230           0 :             BREAK;
   10231             : 
   10232           0 :         default:
   10233           0 :             return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
   10234             :     }
   10235             : 
   10236          48 :     IF( NE_16( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
   10237             :     {
   10238             :         Word16 subframe;
   10239          46 :         IF( NE_32( ( error = ivas_spat_hSpatParamRendCom_config_fx( &hMasaExtRend->hSpatParamRendCom, DIRAC_OPEN, 0, MASA_FORMAT, MC_MODE_NONE, *( inputMasa->base.ctx.pOutSampleRate ), 0, 1 ) ), IVAS_ERR_OK ) )
   10240             :         {
   10241           0 :             return error;
   10242             :         }
   10243             :         /* Simple population of the metadata index map as no adaptation is present */
   10244          46 :         set16_fx( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
   10245         230 :         FOR( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
   10246             :         {
   10247         184 :             hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
   10248         184 :             move16();
   10249             :         }
   10250          46 :         hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
   10251          46 :         move16();
   10252             :     }
   10253             : 
   10254          48 :     IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_DIRAC ) )
   10255             :     {
   10256          34 :         IF( NE_32( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ), IVAS_ERR_OK ) )
   10257             :         {
   10258           0 :             return error;
   10259             :         }
   10260             :     }
   10261             : 
   10262          48 :     test();
   10263          48 :     test();
   10264          48 :     IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_BINAURAL_PARAMETRIC ) || EQ_16( hMasaExtRend->renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) || EQ_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
   10265             :     {
   10266          12 :         IF( NE_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
   10267             :         {
   10268           8 :             IF( NE_32( ( error = ivas_dirac_dec_binaural_copy_hrtfs_fx( inputMasa->hMasaExtRend->hHrtfParambin ) ), IVAS_ERR_OK ) )
   10269             :             {
   10270           0 :                 return error;
   10271             :             }
   10272             :         }
   10273          12 :         if ( NE_32( ( error = ivas_masa_ext_rend_parambin_init( inputMasa, hRendCfg, hrtfs->hHrtfStatistics ) ), IVAS_ERR_OK ) )
   10274             :         {
   10275           0 :             return error;
   10276             :         }
   10277             :     }
   10278             : 
   10279             :     /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
   10280         144 :     FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
   10281             :     {
   10282          96 :         hMasaExtRend->cldfbAnaRend[i] = NULL;
   10283             :     }
   10284             : 
   10285         816 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
   10286             :     {
   10287         768 :         hMasaExtRend->cldfbSynRend[i] = NULL;
   10288             :     }
   10289             : 
   10290          48 :     IF( NE_32( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
   10291             :     {
   10292         116 :         FOR( i = 0; i < hMasaExtRend->nchan_input; i++ )
   10293             :         {
   10294          70 :             IF( NE_32( ( error = openCldfb_ivas_fx( &( hMasaExtRend->cldfbAnaRend[i] ), CLDFB_ANALYSIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS, DEC ) ), IVAS_ERR_OK ) )
   10295             :             {
   10296           0 :                 return error;
   10297             :             }
   10298             :         }
   10299             : 
   10300         364 :         FOR( i = 0; i < hMasaExtRend->nchan_output; i++ )
   10301             :         {
   10302         318 :             IF( NE_32( ( error = openCldfb_ivas_fx( &( hMasaExtRend->cldfbSynRend[i] ), CLDFB_SYNTHESIS, *inputMasa->base.ctx.pOutSampleRate, CLDFB_PROTOTYPE_5_00MS, DEC ) ), IVAS_ERR_OK ) )
   10303             :             {
   10304           0 :                 return error;
   10305             :             }
   10306             :         }
   10307             :     }
   10308             : 
   10309          48 :     inputMasa->hMasaExtRend = hMasaExtRend;
   10310             : 
   10311          48 :     return IVAS_ERR_OK;
   10312             : }
   10313             : 
   10314             : 
   10315         666 : static void freeMasaExtRenderer(
   10316             :     MASA_EXT_REND_HANDLE *hMasaExtRendOut )
   10317             : {
   10318             :     MASA_EXT_REND_HANDLE hMasaExtRend;
   10319             :     Word16 i;
   10320             : 
   10321         666 :     test();
   10322         666 :     IF( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
   10323             :     {
   10324         618 :         return;
   10325             :     }
   10326             : 
   10327          48 :     hMasaExtRend = *hMasaExtRendOut;
   10328             : 
   10329          48 :     IF( hMasaExtRend->hDirACRend != NULL )
   10330             :     {
   10331          34 :         ivas_dirac_rend_close_fx( &hMasaExtRend->hDirACRend );
   10332             :     }
   10333             : 
   10334          48 :     IF( hMasaExtRend->hSpatParamRendCom != NULL )
   10335             :     {
   10336          46 :         ivas_spat_hSpatParamRendCom_close_fx( &hMasaExtRend->hSpatParamRendCom );
   10337             :     }
   10338             : 
   10339         432 :     for ( i = 0; i < MAX_HEAD_ROT_POSES; i++ )
   10340             :     {
   10341         384 :         if ( hMasaExtRend->hDiracDecBin[i] != NULL )
   10342             :         {
   10343          12 :             ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin[i] );
   10344             :         }
   10345             :     }
   10346             : 
   10347          48 :     IF( hMasaExtRend->hReverb != NULL )
   10348             :     {
   10349           0 :         ivas_binaural_reverb_close_fx( &hMasaExtRend->hReverb );
   10350             :     }
   10351             : 
   10352          48 :     IF( hMasaExtRend->hHrtfParambin != NULL )
   10353             :     {
   10354          48 :         ivas_HRTF_parambin_binary_close_fx( hMasaExtRend->hHrtfParambin );
   10355             :     }
   10356             : 
   10357          48 :     IF( hMasaExtRend->hVBAPdata != NULL )
   10358             :     {
   10359          20 :         vbap_free_data_fx( &hMasaExtRend->hVBAPdata );
   10360             :     }
   10361             : 
   10362          48 :     IF( hMasaExtRend->hoa_dec_mtx != NULL )
   10363             :     {
   10364           2 :         free( hMasaExtRend->hoa_dec_mtx );
   10365             :     }
   10366             : 
   10367         144 :     FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
   10368             :     {
   10369          96 :         IF( hMasaExtRend->cldfbAnaRend[i] != NULL )
   10370             :         {
   10371          70 :             deleteCldfb_ivas_fx( &hMasaExtRend->cldfbAnaRend[i] );
   10372             :         }
   10373             :     }
   10374             : 
   10375         816 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
   10376             :     {
   10377         768 :         IF( hMasaExtRend->cldfbSynRend[i] != NULL )
   10378             :         {
   10379         318 :             deleteCldfb_ivas_fx( &hMasaExtRend->cldfbSynRend[i] );
   10380             :         }
   10381             :     }
   10382             : 
   10383          48 :     free( hMasaExtRend );
   10384          48 :     *hMasaExtRendOut = NULL;
   10385             : 
   10386          48 :     return;
   10387             : }
   10388             : 
   10389       25500 : static void intermidiate_ext_dirac_render(
   10390             :     MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure             */
   10391             :     Word16 to_fix )
   10392             : {
   10393             :     SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
   10394       25500 :     hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
   10395             :     DIRAC_DEC_STACK_MEM DirAC_mem;
   10396             :     Word16 ch;
   10397             :     DIRAC_REND_HANDLE hDirACRend;
   10398             :     Word16 subframe_idx;
   10399             :     Word16 slot_idx;
   10400             :     Word16 nchan_transport;
   10401             :     Word16 tmp;
   10402             : 
   10403       25500 :     hDirACRend = hMasaExtRend->hDirACRend;
   10404       25500 :     hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
   10405       25500 :     nchan_transport = hMasaExtRend->nchan_input;
   10406             :     DIRAC_OUTPUT_SYNTHESIS_STATE *h_dirac_output_synthesis_state;
   10407             : 
   10408       25500 :     h_dirac_output_synthesis_state = &( hDirACRend->h_output_synthesis_psd_state );
   10409             : 
   10410       25500 :     subframe_idx = hSpatParamRendCom->subframes_rendered;
   10411       25500 :     move16();
   10412             : 
   10413       25500 :     DirAC_mem = hDirACRend->stack_mem;
   10414             : 
   10415       25500 :     IF( to_fix )
   10416             :     {
   10417       12750 :         DirAC_mem.reference_power_smooth_q[0] = DirAC_mem.reference_power_q[0] = Q31;
   10418       12750 :         DirAC_mem.reference_power_smooth_q[1] = DirAC_mem.reference_power_q[1] = Q31;
   10419       12750 :         move16();
   10420       12750 :         move16();
   10421       12750 :         move16();
   10422       43486 :         FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
   10423             :         {
   10424       30736 :             Scale_sig32( hDirACRend->h_output_synthesis_psd_state.direct_responses_fx, i_mult( hSpatParamRendCom->num_freq_bands, hDirACRend->num_outputs_dir ), sub( Q30, hDirACRend->h_output_synthesis_psd_state.direct_responses_q ) ); /* Q30 */
   10425       30736 :             hDirACRend->h_output_synthesis_psd_state.direct_responses_q = Q30;
   10426       30736 :             move16();
   10427             :         }
   10428             : 
   10429       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx )
   10430             :         {
   10431       12750 :             Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_len );
   10432       12750 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth + shift) */
   10433       12750 :             hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth = add( hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth, shift );
   10434       12750 :             move16();
   10435             :         }
   10436       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx )
   10437             :         {
   10438       12750 :             Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_len );
   10439       12750 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth_prev + shift) */
   10440       12750 :             hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth_prev = add( hDirACRend->h_output_synthesis_psd_state.q_cy_cross_dir_smooth_prev, shift );
   10441       12750 :             move16();
   10442             :         }
   10443             : 
   10444       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx )
   10445             :         {
   10446       10500 :             Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx, imult1616( hDirACRend->num_outputs_dir, hSpatParamRendCom->num_freq_bands ) );
   10447       10500 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth + shift) */
   10448       10500 :             hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth = add( hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth, shift );
   10449       10500 :             move16();
   10450             :         }
   10451             : 
   10452       12750 :         Word16 num_channels_dir = hDirACRend->num_outputs_dir;
   10453       12750 :         move16();
   10454             : 
   10455       12750 :         IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
   10456             :         {
   10457        7500 :             num_channels_dir = hDirACRend->hOutSetup.nchan_out_woLFE;
   10458        7500 :             move16();
   10459             :         }
   10460             : 
   10461       12750 :         IF( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx )
   10462             :         {
   10463       12750 :             tmp = L_norm_arr( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, imult1616( num_channels_dir, hSpatParamRendCom->num_freq_bands ) );
   10464       12750 :             scale_sig32( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_len, tmp ); /* Q(h_dirac_output_synthesis_state->q_cy_auto_diff_smooth + tmp) */
   10465       12750 :             h_dirac_output_synthesis_state->q_cy_auto_diff_smooth = add( h_dirac_output_synthesis_state->q_cy_auto_diff_smooth, tmp );
   10466       12750 :             move16();
   10467             :         }
   10468             : 
   10469       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx )
   10470             :         {
   10471       12750 :             tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_len );
   10472       12750 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_auto_diff_smooth_prev + tmp) */
   10473       12750 :             hDirACRend->h_output_synthesis_psd_state.q_cy_auto_diff_smooth_prev = add( hDirACRend->h_output_synthesis_psd_state.q_cy_auto_diff_smooth_prev, tmp );
   10474       12750 :             move16();
   10475             :         }
   10476             : 
   10477       12750 :         scale_sig32( hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_fx, hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_len, sub( Q26, hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q ) ); /* Q26 */
   10478       12750 :         hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q = Q26;
   10479       12750 :         move16();
   10480       12750 :         scale_sig32( hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_fx, hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_len, sub( Q26, hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q ) ); /* Q26 */
   10481       12750 :         hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q = Q26;
   10482       12750 :         move16();
   10483       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx )
   10484             :         {
   10485       10500 :             Word16 shift = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx, imult1616( hSpatParamRendCom->num_freq_bands, hDirACRend->num_outputs_dir ) );
   10486       10500 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_len, shift ); /* Q(hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth_prev + shift) */
   10487       10500 :             hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth_prev = add( hDirACRend->h_output_synthesis_psd_state.q_cy_auto_dir_smooth_prev, shift );
   10488       10500 :             move16();
   10489             :         }
   10490             : 
   10491       12750 :         IF( EQ_16( hDirACRend->proto_signal_decorr_on, 1 ) )
   10492             :         {
   10493       12000 :             tmp = L_norm_arr( hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_fx, hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_len );
   10494       12000 :             scale_sig32( hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_fx, hDirACRend->h_freq_domain_decorr_ap_state->decorr_buffer_len, tmp ); /* Q(hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer + tmp) */
   10495       12000 :             hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer = add( hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer, tmp );
   10496       12000 :             move16();
   10497             :         }
   10498             : 
   10499       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len > 0 )
   10500             :         {
   10501             :             Word16 shift, norm1, norm2;
   10502             :             Word32 tmp1, tmp2;
   10503       12000 :             maximum_abs_32_fx( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_fx, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len, &tmp2 );
   10504       12000 :             maximum_abs_32_fx( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_fx, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len, &tmp1 );
   10505             : 
   10506       12000 :             IF( tmp1 == 0 )
   10507             :             {
   10508          32 :                 norm1 = 31;
   10509          32 :                 move16();
   10510             :             }
   10511             :             ELSE
   10512             :             {
   10513       11968 :                 norm1 = norm_l( tmp1 );
   10514             :             }
   10515             : 
   10516       12000 :             IF( tmp2 == 0 )
   10517             :             {
   10518          32 :                 norm2 = 31;
   10519          32 :                 move16();
   10520             :             }
   10521             :             ELSE
   10522             :             {
   10523       11968 :                 norm2 = norm_l( tmp2 );
   10524             :             }
   10525             : 
   10526       12000 :             shift = s_min( norm1, norm2 );
   10527             : 
   10528       12000 :             Word16 hr_exp = sub( 31, shift );
   10529             : 
   10530       12000 :             Scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_fx, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len, sub( sub( 31, hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q ), hr_exp ) ); /* Q(31 - hr_exp) */
   10531       12000 :             hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q = sub( 31, hr_exp );
   10532       12000 :             move16();
   10533             :         }
   10534             : 
   10535       43486 :         FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
   10536             :         {
   10537             :             /* CLDFB Analysis*/
   10538       77744 :             FOR( ch = 0; ch < nchan_transport; ch++ )
   10539             :             {
   10540       47008 :                 hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
   10541       47008 :                 move16();
   10542             :             }
   10543             :         }
   10544       12750 :         hDirACRend->proto_frame_dec_f_q = sub( 31, hDirACRend->proto_frame_dec_f_q );
   10545       12750 :         move16();
   10546             : 
   10547       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx )
   10548             :         {
   10549       10500 :             tmp = 0;
   10550       10500 :             move16();
   10551       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10552             :             {
   10553       81750 :                 tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx, s_min( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ) );
   10554             :             }
   10555       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10556             :             {
   10557       81750 :                 scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx, s_min( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q + tmp) */
   10558             :             }
   10559       10500 :             hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[0] = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[0], tmp );
   10560       10500 :             move16();
   10561       10500 :             tmp = 0;
   10562       10500 :             move16();
   10563       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10564             :             {
   10565       81750 :                 tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ) ) );
   10566             :             }
   10567       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10568             :             {
   10569       81750 :                 scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx + slot_idx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q + tmp) */
   10570             :             }
   10571       10500 :             hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[1] = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q[1], tmp );
   10572       10500 :             move16();
   10573       10500 :             tmp = 0;
   10574       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10575             :             {
   10576       81750 :                 tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, s_min( CLDFB_NO_CHANNELS_HALF, hSpatParamRendCom->num_freq_bands ) ) );
   10577             :             }
   10578       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10579             :             {
   10580       81750 :                 scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, s_min( CLDFB_NO_CHANNELS_HALF, hSpatParamRendCom->num_freq_bands ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q + tmp) */
   10581             :             }
   10582       10500 :             hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[0] = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[0] );
   10583       10500 :             move16();
   10584       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10585             :             {
   10586       81750 :                 tmp = s_min( tmp, L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ) ) );
   10587             :             }
   10588       92250 :             FOR( slot_idx = 0; slot_idx < hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_len; slot_idx = add( slot_idx, hSpatParamRendCom->num_freq_bands ) )
   10589             :             {
   10590       81750 :                 scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx + CLDFB_NO_CHANNELS_HALF, s_max( 0, sub( hSpatParamRendCom->num_freq_bands, CLDFB_NO_CHANNELS_HALF ) ), tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q + tmp) */
   10591             :             }
   10592       10500 :             hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[1] = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q[1] );
   10593       10500 :             move16();
   10594             :         }
   10595       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx != NULL )
   10596             :         {
   10597             : 
   10598       10500 :             tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_len );
   10599       10500 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_q + tmp) */
   10600       10500 :             hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_q, tmp );
   10601       10500 :             move16();
   10602             :         }
   10603             : 
   10604       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx != NULL )
   10605             :         {
   10606        9750 :             tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_len );
   10607        9750 :             scale_sig32( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx, hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_len, tmp ); /* Q(hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_q + tmp) */
   10608        9750 :             hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_q, tmp );
   10609        9750 :             move16();
   10610             :         }
   10611             :     }
   10612             :     ELSE
   10613             :     {
   10614       43350 :         FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[hSpatParamRendCom->subframes_rendered]; slot_idx++ )
   10615             :         {
   10616             :             /* CLDFB Analysis*/
   10617       77400 :             FOR( ch = 0; ch < nchan_transport; ch++ )
   10618             :             {
   10619       46800 :                 scale_sig32( hMasaExtRend->cldfbAnaRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbAnaRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state ) ); /* Q11 */
   10620       46800 :                 hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
   10621       46800 :                 move16();
   10622             :             }
   10623             :         }
   10624             : 
   10625      123000 :         FOR( ch = 0; ch < hDirACRend->hOutSetup.nchan_out_woLFE + hDirACRend->hOutSetup.num_lfe; ch++ )
   10626             :         {
   10627      110250 :             scale_sig32( hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbSynRend[0]->Q_cldfb_state ) ); /* Q11 */
   10628      110250 :             hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
   10629      110250 :             move16();
   10630             :         }
   10631             :     }
   10632             : 
   10633       25500 :     return;
   10634             : }
   10635             : 
   10636             : 
   10637         666 : static ivas_error printConfigInfo_rend(
   10638             :     IVAS_REND_HANDLE hIvasRend /* i  : IVAS renderer handle     */
   10639             : )
   10640             : {
   10641             :     ivas_error error;
   10642             :     Word8 config_str[50];
   10643             : 
   10644             :     /*-----------------------------------------------------------------*
   10645             :      * Print output audio configuration
   10646             :      *-----------------------------------------------------------------*/
   10647             : 
   10648         666 :     IF( NE_32( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ), IVAS_ERR_OK ) )
   10649             :     {
   10650           0 :         return error;
   10651             :     }
   10652             : 
   10653         666 :     fprintf( stdout, "Output configuration:   %s\n", config_str );
   10654             : 
   10655             :     /*-----------------------------------------------------------------*
   10656             :      * Print renderer configurations
   10657             :      *-----------------------------------------------------------------*/
   10658             : 
   10659         666 :     fprintf( stdout, "Output sampling rate:   %d Hz\n", hIvasRend->sampleRateOut );
   10660             : 
   10661         666 :     if ( hIvasRend->headRotData.headRotEnabled )
   10662             :     {
   10663          94 :         fprintf( stdout, "Head-tracking:          ON\n" );
   10664             :     }
   10665             : 
   10666         666 :     test();
   10667         666 :     test();
   10668         666 :     test();
   10669         666 :     test();
   10670         666 :     IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) ||
   10671             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) ||
   10672             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ||
   10673             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
   10674             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
   10675             :     {
   10676         188 :         fprintf( stdout, "Render framesize:       %dms\n", i_mult( hIvasRend->num_subframes, 5 ) );
   10677             :     }
   10678             : 
   10679         666 :     return IVAS_ERR_OK;
   10680             : }
   10681             : 
   10682             : 
   10683             : /*---------------------------------------------------------------------*
   10684             :  * IVAS_REND_PrintInputConfig()
   10685             :  *
   10686             :  *
   10687             :  *---------------------------------------------------------------------*/
   10688             : 
   10689         729 : void IVAS_REND_PrintInputConfig(
   10690             :     const IVAS_AUDIO_CONFIG inputConfig /* i  : input audio configuration    */
   10691             : )
   10692             : {
   10693             :     Word8 config_str[50];
   10694             : 
   10695         729 :     get_channel_config( inputConfig, &config_str[0] );
   10696         729 :     fprintf( stdout, "Input configuration:    %s\n", config_str );
   10697             : 
   10698         729 :     return;
   10699             : }
   10700             : 
   10701             : 
   10702             : /*---------------------------------------------------------------------*
   10703             :  * IVAS_REND_PrintConfig()
   10704             :  *
   10705             :  *
   10706             :  *---------------------------------------------------------------------*/
   10707             : 
   10708         666 : ivas_error IVAS_REND_PrintConfig(
   10709             :     IVAS_REND_HANDLE hIvasRend /* i  : IVAS renderer handle    */
   10710             : )
   10711             : {
   10712         666 :     if ( hIvasRend == NULL )
   10713             :     {
   10714           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
   10715             :     }
   10716             : 
   10717         666 :     return printConfigInfo_rend( hIvasRend );
   10718             : }
   10719             : 
   10720             : 
   10721             : /*---------------------------------------------------------------------*
   10722             :  * IVAS_REND_PrintDisclaimer()
   10723             :  *
   10724             :  * Print IVAS disclaimer to console
   10725             :  *---------------------------------------------------------------------*/
   10726             : 
   10727         666 : void IVAS_REND_PrintDisclaimer( void )
   10728             : {
   10729         666 :     print_disclaimer( stderr );
   10730             : 
   10731         666 :     return;
   10732             : }

Generated by: LCOV version 1.14