LCOV - code coverage report
Current view: top level - lib_rend - lib_rend.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 3012 3690 81.6 %
Date: 2025-05-03 01:55:50 Functions: 136 147 92.5 %

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

Generated by: LCOV version 1.14