LCOV - code coverage report
Current view: top level - lib_rend - lib_rend_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 574a190e3c6896c6c4ed10d7f23649709a0c4347 Lines: 2994 3676 81.4 %
Date: 2025-06-27 02:59:36 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         973 : static ivas_error allocateInputBaseBufferData_fx(
     232             :     Word32 **data, /* Qx */
     233             :     const Word16 data_size )
     234             : {
     235         973 :     *data = (Word32 *) malloc( data_size * sizeof( Word32 ) );
     236         973 :     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         973 :     return IVAS_ERR_OK;
     242             : }
     243        4662 : static void freeInputBaseBufferData_fx(
     244             :     Word32 **data /* Qx */ )
     245             : {
     246        4662 :     IF( *data != NULL )
     247             :     {
     248         973 :         free( *data );
     249         973 :         *data = NULL;
     250             :     }
     251             : 
     252        4662 :     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         666 : static void freeMcLfeDelayBuffer_fx(
     267             :     Word32 **lfeDelayBuffer /* Qx */ )
     268             : {
     269         666 :     IF( *lfeDelayBuffer != NULL )
     270             :     {
     271         372 :         free( *lfeDelayBuffer );
     272         372 :         *lfeDelayBuffer = NULL;
     273             :     }
     274             : 
     275         666 :     return;
     276             : }
     277             : 
     278             : 
     279        1752 : static IVAS_QUATERNION quaternionInit_fx(
     280             :     void )
     281             : {
     282             :     IVAS_QUATERNION q;
     283        1752 :     q.w_fx = ONE_IN_Q29;
     284        1752 :     move32();
     285        1752 :     q.x_fx = q.y_fx = q.z_fx = 0;
     286        1752 :     move32();
     287        1752 :     move32();
     288        1752 :     move32();
     289             : 
     290        1752 :     q.q_fact = Q29;
     291        1752 :     move16();
     292        1752 :     move16();
     293        1752 :     move16();
     294        1752 :     move16();
     295             : 
     296        1752 :     return q;
     297             : }
     298             : 
     299   221694105 : static Word32 *getSmplPtr_fx(
     300             :     IVAS_REND_AudioBuffer buffer,
     301             :     const UWord32 chnlIdx,
     302             :     const UWord32 smplIdx )
     303             : {
     304   221694105 :     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     1126140 : 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     1126140 :     Word32 numClipping = 0;
     365     1126140 :     move32();
     366             : 
     367             :     /* return early if given bad parameters */
     368     1126140 :     test();
     369     1126140 :     test();
     370     1126140 :     IF( hLimiter == NULL || output == NULL || output_frame <= 0 )
     371             :     {
     372           0 :         return 0;
     373             :     }
     374             : 
     375     1126140 :     channels = hLimiter->channel_ptrs_fx;
     376     1126140 :     num_channels = hLimiter->num_channels;
     377     1126140 :     move16();
     378             : 
     379     7755488 :     FOR( i = 0; i < num_channels; ++i )
     380             :     {
     381     6629348 :         channels[i] = output + imult1616( i, output_frame );
     382             :     }
     383             : 
     384     1126140 :     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  2809398780 :     FOR( i = 0; i < output_frame * num_channels; ++i )
     388             :     {
     389             : 
     390  2808272640 :         output[i] = L_min( L_max( L_shl( INT16_MIN, q_factor ), output[i] ), L_shl( INT16_MAX, q_factor ) );
     391  2808272640 :         move32();
     392             :     }
     393             : 
     394     1126140 :     return numClipping;
     395             : }
     396             : 
     397             : /*-------------------------------------------------------------------*
     398             :  * validateOutputAudioConfig()
     399             :  *
     400             :  *
     401             :  *-------------------------------------------------------------------*/
     402             : 
     403         666 : static ivas_error validateOutputAudioConfig(
     404             :     const AUDIO_CONFIG outConfig )
     405             : {
     406         666 :     SWITCH( outConfig )
     407             :     {
     408         666 :         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         666 :             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     8477919 : IVAS_REND_AudioConfigType getAudioConfigType(
     439             :     const AUDIO_CONFIG config )
     440             : {
     441             :     IVAS_REND_AudioConfigType type;
     442             : 
     443     8477919 :     SWITCH( config )
     444             :     {
     445     4284824 :         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     4284824 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED;
     454     4284824 :             move16();
     455     4284824 :             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      301622 :         case IVAS_AUDIO_CONFIG_OBA:
     463      301622 :             type = IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED;
     464      301622 :             move16();
     465      301622 :             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     8477919 :     return type;
     486             : }
     487             : 
     488             : /*-------------------------------------------------------------------*
     489             :  * validateOutputSampleRate()
     490             :  *
     491             :  *
     492             :  *-------------------------------------------------------------------*/
     493             : 
     494         666 : static ivas_error validateOutputSampleRate(
     495             :     const Word32 sampleRate,
     496             :     const AUDIO_CONFIG outConfig )
     497             : {
     498         666 :     IF( NE_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
     499             :     {
     500             :         /* If no binaural rendering, any sampling rate is supported */
     501         478 :         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     5841645 : ivas_error getAudioConfigNumChannels(
     523             :     const AUDIO_CONFIG config,
     524             :     Word16 *numChannels )
     525             : {
     526     5841645 :     SWITCH( config )
     527             :     {
     528     1484129 :         case IVAS_AUDIO_CONFIG_MONO:
     529             :         case IVAS_AUDIO_CONFIG_OBA:
     530             :         case IVAS_AUDIO_CONFIG_MASA1:
     531     1484129 :             *numChannels = 1;
     532     1484129 :             move16();
     533     1484129 :             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     5841645 :     move16();
     576     5841645 :     return IVAS_ERR_OK;
     577             : }
     578             : /*-------------------------------------------------------------------*
     579             :  * Local functions
     580             :  *-------------------------------------------------------------------*/
     581             : 
     582         713 : 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         713 :     test();
     591         713 :     test();
     592         713 :     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         713 :     IF( *phLimiter != NULL )
     599             :     {
     600          47 :         ivas_limiter_close_fx( phLimiter );
     601             :     }
     602             : 
     603         713 :     IF( NE_32( ( error = ivas_limiter_open_fx( phLimiter, numChannels, sampleRate ) ), IVAS_ERR_OK ) )
     604             :     {
     605           0 :         return error;
     606             :     }
     607             : 
     608         713 :     return IVAS_ERR_OK;
     609             : }
     610        1038 : 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        1038 :     ls.is_planar_setup = 1;
     618        1038 :     ls.num_spk = 1;
     619        1038 :     move16();
     620        1038 :     move16();
     621        1038 :     set32_fx( ls.ls_azimuth_fx, 0, MAX_OUTPUT_CHANNELS );
     622        1038 :     set32_fx( ls.ls_elevation_fx, 0, MAX_OUTPUT_CHANNELS );
     623        1038 :     ls.num_lfe = 0;
     624        1038 :     move16();
     625        1038 :     set16_fx( ls.lfe_idx, 0, MAX_OUTPUT_CHANNELS );
     626        1038 :     ls.separate_ch_found = 0;
     627        1038 :     move16();
     628        1038 :     set16_fx( ls.separate_ch_gains_fx, 0, MAX_OUTPUT_CHANNELS );
     629             : 
     630        1038 :     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         878 : 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         878 :     test();
     876         878 :     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         758 :         pEfapWrapper->speakerConfig = outConfig;
     884         758 :         move32();
     885             :     }
     886         878 :     pEfapWrapper->pCustomLsSetup = pCustomLsOut;
     887             : 
     888             :     /* If re-initializing, free existing EFAP handle. */
     889         878 :     IF( pEfapWrapper->hEfap != NULL )
     890             :     {
     891          47 :         efap_free_data_fx( &pEfapWrapper->hEfap );
     892             :     }
     893             : 
     894             :     /* Only initialize EFAP handle if output config is channel-based */
     895         878 :     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         683 :     IF( EQ_32( outConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
     902             :     {
     903         199 :         IF( NE_32( ( error = efap_init_data_fx( &pEfapWrapper->hEfap, pCustomLsOut->ls_azimuth_fx, pCustomLsOut->ls_elevation_fx, pCustomLsOut->num_spk, EFAP_MODE_EFAP ) ), IVAS_ERR_OK ) )
     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         683 :     return IVAS_ERR_OK;
     931             : }
     932             : 
     933      423262 : 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      423262 :     efap_determine_gains_fx( efapWrapper.hEfap, tmpPanGains, azi, ele, EFAP_MODE_EFAP );
     948             : 
     949             :     /* Now copy to buffer that includes LFE channels */
     950      423262 :     IF( EQ_32( efapWrapper.speakerConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
     951             :     {
     952       29835 :         numChannels = add( efapWrapper.pCustomLsSetup->num_spk, efapWrapper.pCustomLsSetup->num_lfe );
     953       29835 :         readPtr = tmpPanGains;
     954       29835 :         lfeCount = 0;
     955       29835 :         move16();
     956      387823 :         FOR( i = 0; i < numChannels; ++i )
     957             :         {
     958      357988 :             test();
     959      357988 :             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      357988 :                 IF( EQ_32( *readPtr, ONE_IN_Q30 ) )
     968             :                 {
     969           0 :                     panGains[i] = ONE_IN_Q31;
     970             :                 }
     971             :                 ELSE
     972             :                 {
     973      357988 :                     panGains[i] = L_shl( *readPtr, 1 );
     974             :                 }
     975      357988 :                 move32();
     976      357988 :                 ++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      423262 :     return IVAS_ERR_OK;
    1014             : }
    1015             : 
    1016         666 : 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         666 :     hIvasRend->headRotData.headRotEnabled = 1;
    1025         666 :     move16();
    1026             : 
    1027             :     /* Initialize 5ms crossfade */
    1028         666 :     crossfade_len = L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES;
    1029         666 :     move16();
    1030         666 :     tmp_fx = Q31_BY_SUB_FRAME_240;
    1031         666 :     move16();
    1032             : 
    1033      160506 :     FOR( i = 0; i < crossfade_len; i++ )
    1034             :     {
    1035      159840 :         hIvasRend->headRotData.crossfade_fx[i] = UL_Mpy_32_32( i, tmp_fx );
    1036      159840 :         move32();
    1037             :     }
    1038             : 
    1039             :     /* Initialize with unit quaternions */
    1040        2418 :     FOR( i = 0; i < hIvasRend->num_subframes; ++i )
    1041             :     {
    1042        1752 :         hIvasRend->headRotData.headPositions[i] = quaternionInit_fx();
    1043             :     }
    1044             : 
    1045             : 
    1046         666 :     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         666 :     IF( NE_32( ( error = ivas_orient_trk_Init_fx( hIvasRend->headRotData.hOrientationTracker ) ), IVAS_ERR_OK ) )
    1052             :     {
    1053           0 :         return error;
    1054             :     }
    1055             : 
    1056         666 :     return IVAS_ERR_OK;
    1057             : }
    1058             : 
    1059             : 
    1060         666 : static void closeHeadRotation(
    1061             :     IVAS_REND_HANDLE hIvasRend )
    1062             : {
    1063         666 :     test();
    1064         666 :     IF( ( hIvasRend != NULL ) && ( hIvasRend->headRotData.hOrientationTracker != NULL ) )
    1065             :     {
    1066         666 :         free( hIvasRend->headRotData.hOrientationTracker );
    1067             :     }
    1068             : 
    1069         666 :     return;
    1070             : }
    1071             : 
    1072             : 
    1073         426 : static void initRotMatrix_fx(
    1074             :     rotation_matrix_fx rot_mat )
    1075             : {
    1076             :     Word16 i;
    1077             : 
    1078             :     /* Initialize rotation matrices */
    1079        1704 :     FOR( i = 0; i < 3; i++ )
    1080             :     {
    1081        1278 :         set_zero_fx( rot_mat[i], 3 );
    1082        1278 :         rot_mat[i][i] = ONE_IN_Q30;
    1083        1278 :         move32();
    1084             :     }
    1085             : 
    1086         426 :     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       10297 : 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       10297 :     inputBase->inConfig = inConfig;
    1129       10297 :     move32();
    1130       10297 :     inputBase->id = id;
    1131       10297 :     move16();
    1132       10297 :     inputBase->gain_fx = ONE_IN_Q30;
    1133       10297 :     move32();
    1134       10297 :     inputBase->ctx = rendCtx;
    1135       10297 :     inputBase->numNewSamplesPerChannel = 0;
    1136       10297 :     move32();
    1137             : 
    1138       10297 :     inputBase->inputBuffer.config.numSamplesPerChannel = 0;
    1139       10297 :     inputBase->inputBuffer.config.numChannels = 0;
    1140       10297 :     move16();
    1141       10297 :     move16();
    1142       10297 :     inputBase->inputBuffer.data_fx = dataBuf;
    1143       10297 :     IF( inputBase->inputBuffer.data_fx != NULL )
    1144             :     {
    1145         973 :         set32_fx( inputBase->inputBuffer.data_fx, 0, dataBufSize );
    1146             :     }
    1147             : 
    1148       10297 :     return;
    1149             : }
    1150             : 
    1151      300852 : static IVAS_ISM_METADATA defaultObjectPosition(
    1152             :     void )
    1153             : {
    1154             :     IVAS_ISM_METADATA pos;
    1155             : 
    1156      300852 :     pos.azimuth_fx = 0;
    1157      300852 :     move32();
    1158      300852 :     pos.elevation_fx = 0;
    1159      300852 :     move32();
    1160      300852 :     pos.radius_fx = ONE_IN_Q9;
    1161      300852 :     move16();
    1162      300852 :     pos.spread_fx = 0;
    1163      300852 :     move32();
    1164      300852 :     pos.gainFactor_fx = ONE_IN_Q31;
    1165      300852 :     move32();
    1166      300852 :     pos.yaw_fx = 0;
    1167      300852 :     move32();
    1168      300852 :     pos.pitch_fx = 0;
    1169      300852 :     move32();
    1170      300852 :     return pos;
    1171             : }
    1172             : 
    1173             : 
    1174      947155 : static Word8 checkObjectPositionChanged_fx(
    1175             :     IVAS_ISM_METADATA *currentPos,
    1176             :     IVAS_ISM_METADATA *previousPos )
    1177             : {
    1178      947155 :     test();
    1179     1555417 :     return !( LT_32( L_abs( L_sub( currentPos->azimuth_fx, previousPos->azimuth_fx ) ), EPSILLON_FX ) &&
    1180      608262 :               LT_32( L_abs( L_sub( currentPos->elevation_fx, previousPos->elevation_fx ) ), EPSILLON_FX ) );
    1181             : }
    1182             : 
    1183        4662 : 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        4662 :     ctx.pOutConfig = &hIvasRend->outputConfig;
    1192        4662 :     ctx.pOutSampleRate = &hIvasRend->sampleRateOut;
    1193        4662 :     ctx.pCustomLsOut = &hIvasRend->customLsOut;
    1194        4662 :     ctx.pEfapOutWrapper = &hIvasRend->efapOutWrapper;
    1195        4662 :     ctx.pHeadRotData = &hIvasRend->headRotData;
    1196        4662 :     ctx.pCombinedOrientationData = &hIvasRend->hCombinedOrientationData;
    1197             : 
    1198        4662 :     return ctx;
    1199             : }
    1200             : 
    1201             : 
    1202         798 : static TDREND_WRAPPER defaultTdRendWrapper(
    1203             :     void )
    1204             : {
    1205             :     TDREND_WRAPPER w;
    1206             : 
    1207         798 :     w.binaural_latency_ns = 0;
    1208         798 :     move32();
    1209         798 :     w.hBinRendererTd = NULL;
    1210         798 :     w.hHrtfTD = NULL;
    1211             : 
    1212         798 :     return w;
    1213             : }
    1214             : 
    1215             : 
    1216         973 : 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         973 :     test();
    1222         973 :     test();
    1223         973 :     IF( ( EQ_32( inConfig, IVAS_AUDIO_CONFIG_MONO ) || EQ_32( inConfig, IVAS_AUDIO_CONFIG_STEREO ) ) && EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) )
    1224             :     {
    1225           0 :         return false;
    1226             :     }
    1227             : 
    1228             :     /* If not returned so far, config pair is supported */
    1229         973 :     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         426 : 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         426 :     inputIsm = (input_ism *) input;
    1269         426 :     rendCtx = inputIsm->base.ctx;
    1270         426 :     outConfig = *rendCtx.pOutConfig;
    1271             : 
    1272         426 :     IF( !isIoConfigPairSupported( inConfig, outConfig ) )
    1273             :     {
    1274           0 :         return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    1275             :     }
    1276             : 
    1277         426 :     IF( NE_32( ( error = allocateInputBaseBufferData_fx( &inputIsm->bufferData_fx, MAX_BUFFER_LENGTH ) ), IVAS_ERR_OK ) )
    1278             :     {
    1279           0 :         return error;
    1280             :     }
    1281         426 :     initRendInputBase_fx( &inputIsm->base, inConfig, id, rendCtx, inputIsm->bufferData_fx, MAX_BUFFER_LENGTH );
    1282             : 
    1283         426 :     inputIsm->firstFrameRendered = FALSE;
    1284         426 :     move16();
    1285             : 
    1286         426 :     inputIsm->currentPos = defaultObjectPosition();
    1287         426 :     inputIsm->previousPos = defaultObjectPosition();
    1288         426 :     inputIsm->crendWrapper = NULL;
    1289         426 :     inputIsm->hReverb = NULL;
    1290         426 :     inputIsm->tdRendWrapper = defaultTdRendWrapper();
    1291             : 
    1292         426 :     initRotMatrix_fx( inputIsm->rot_mat_prev );
    1293             : 
    1294         426 :     set_zero_fx( inputIsm->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    1295             : 
    1296         426 :     inputIsm->hOMasa = NULL;
    1297             : 
    1298         426 :     error = IVAS_ERR_OK;
    1299         426 :     move32();
    1300             : 
    1301         426 :     test();
    1302         426 :     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         386 :     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         385 :         IF( EQ_32( getAudioConfigType( inConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    1322             :         {
    1323           0 :             ivas_format = MC_FORMAT;
    1324             :         }
    1325             :         ELSE
    1326             :         {
    1327         385 :             ivas_format = ISM_FORMAT;
    1328             :         }
    1329             : 
    1330         385 :         move16();
    1331         385 :         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         385 :         Word16 nchan_rend = num_src;
    1337         385 :         move16();
    1338             : 
    1339         385 :         test();
    1340         385 :         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         770 :         FOR( Word16 nS = 0; nS < nchan_rend; nS++ )
    1345             :         {
    1346         385 :             TDREND_SRC_t *Src_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[SrcInd[nS]];
    1347         385 :             IF( Src_p != NULL )
    1348             :             {
    1349         385 :                 IF( Src_p->SrcSpatial_p != NULL )
    1350             :                 {
    1351         385 :                     Src_p->SrcSpatial_p->q_Pos_p = Q31;
    1352         385 :                     move16();
    1353             :                 }
    1354         385 :                 TDREND_SRC_SPATIAL_t *SrcSpatial_p = inputIsm->tdRendWrapper.hBinRendererTd->Sources[nS]->SrcSpatial_p;
    1355         385 :                 SrcSpatial_p->q_Pos_p = Q31;
    1356         385 :                 move16();
    1357             :             }
    1358             :         }
    1359             : 
    1360         385 :         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         426 :     return IVAS_ERR_OK;
    1370             : }
    1371             : 
    1372        2664 : static void clearInputIsm(
    1373             :     input_ism *inputIsm )
    1374             : {
    1375             :     rendering_context rendCtx;
    1376             : 
    1377        2664 :     rendCtx = inputIsm->base.ctx;
    1378             : 
    1379        2664 :     freeInputBaseBufferData_fx( &inputIsm->base.inputBuffer.data_fx );
    1380             : 
    1381        2664 :     initRendInputBase_fx( &inputIsm->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    1382             : 
    1383             :     /* Free input's internal handles */
    1384        2664 :     ivas_rend_closeCrend( &inputIsm->crendWrapper );
    1385             : 
    1386        2664 :     ivas_reverb_close( &inputIsm->hReverb );
    1387             : 
    1388        2664 :     IF( inputIsm->tdRendWrapper.hBinRendererTd != NULL )
    1389             :     {
    1390         385 :         ivas_td_binaural_close_fx( &inputIsm->tdRendWrapper.hBinRendererTd );
    1391         385 :         inputIsm->tdRendWrapper.hHrtfTD = NULL;
    1392             :     }
    1393             : 
    1394             : 
    1395        2664 :     ivas_omasa_ana_close( &( inputIsm->hOMasa ) );
    1396             : 
    1397        2664 :     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     2507531 : 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     2507531 :     pInputBase = (const input_base *) rendInput;
    1599             : 
    1600     2507531 :     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     2291556 :         IF( NE_32( ( error = getAudioConfigNumChannels( pInputBase->inConfig, numInChannels ) ), IVAS_ERR_OK ) )
    1609             :         {
    1610           0 :             return error;
    1611             :         }
    1612             :     }
    1613             : 
    1614     2507531 :     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         666 : static void clearInputMc(
    2488             :     input_mc *inputMc )
    2489             : {
    2490             :     rendering_context rendCtx;
    2491             : 
    2492         666 :     rendCtx = inputMc->base.ctx;
    2493         666 :     freeMcLfeDelayBuffer_fx( &inputMc->lfeDelayBuffer_fx );
    2494         666 :     freeInputBaseBufferData_fx( &inputMc->bufferData_fx );
    2495         666 :     initRendInputBase_fx( &inputMc->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    2496             : 
    2497             :     /* Free input's internal handles */
    2498         666 :     IF( inputMc->efapInWrapper.hEfap != NULL )
    2499             :     {
    2500         129 :         efap_free_data_fx( &inputMc->efapInWrapper.hEfap );
    2501             :     }
    2502             : 
    2503         666 :     ivas_rend_closeCrend( &inputMc->crendWrapper );
    2504             : 
    2505         666 :     ivas_reverb_close( &inputMc->hReverb );
    2506             : 
    2507         666 :     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         666 :     ivas_mcmasa_ana_close( &( inputMc->hMcMasa ) );
    2515             : 
    2516         666 :     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         666 : static void clearInputSba(
    2742             :     input_sba *inputSba )
    2743             : {
    2744             :     rendering_context rendCtx;
    2745             : 
    2746         666 :     rendCtx = inputSba->base.ctx;
    2747             : 
    2748         666 :     freeInputBaseBufferData_fx( &inputSba->bufferData_fx );
    2749             : 
    2750         666 :     initRendInputBase_fx( &inputSba->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    2751             : 
    2752             :     /* Free input's internal handles */
    2753         666 :     ivas_rend_closeCrend( &inputSba->crendWrapper );
    2754             : 
    2755         666 :     ivas_dirac_ana_close_fx( &( inputSba->hDirAC ) );
    2756             : 
    2757         666 :     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         666 : static void clearInputMasa(
    2827             :     input_masa *inputMasa )
    2828             : {
    2829             :     rendering_context rendCtx;
    2830             : 
    2831         666 :     rendCtx = inputMasa->base.ctx;
    2832             : 
    2833         666 :     freeInputBaseBufferData_fx( &inputMasa->bufferData_fx );
    2834             : 
    2835         666 :     masaPrerendClose_fx( &inputMasa->hMasaPrerend );
    2836             : 
    2837         666 :     freeMasaExtRenderer( &inputMasa->hMasaExtRend );
    2838             : 
    2839         666 :     initRendInputBase_fx( &inputMasa->base, IVAS_AUDIO_CONFIG_INVALID, 0, rendCtx, NULL, 0 );
    2840             : 
    2841         666 :     return;
    2842             : }
    2843             : 
    2844             : 
    2845             : /*-------------------------------------------------------------------------
    2846             :  * IVAS_REND_Open()
    2847             :  *
    2848             :  *
    2849             :  *------------------------------------------------------------------------*/
    2850             : 
    2851         666 : 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         666 :     IF( phIvasRend == NULL )
    2866             :     {
    2867           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    2868             :     }
    2869             : 
    2870         666 :     IF( NE_32( ( error = validateOutputAudioConfig( outConfig ) ), IVAS_ERR_OK ) )
    2871             :     {
    2872           0 :         return error;
    2873             :     }
    2874             : 
    2875         666 :     IF( NE_32( ( error = validateOutputSampleRate( outputSampleRate, outConfig ) ), IVAS_ERR_OK ) )
    2876             :     {
    2877           0 :         return error;
    2878             :     }
    2879             : 
    2880         666 :     *phIvasRend = (IVAS_REND_HANDLE) malloc( sizeof( struct IVAS_REND ) );
    2881         666 :     IF( *phIvasRend == NULL )
    2882             :     {
    2883           0 :         return IVAS_ERR_FAILED_ALLOC;
    2884             :     }
    2885             : 
    2886         666 :     hIvasRend = *phIvasRend;
    2887         666 :     hIvasRend->sampleRateOut = outputSampleRate;
    2888         666 :     hIvasRend->outputConfig = outConfig;
    2889         666 :     hIvasRend->customLsOut = defaultCustomLs();
    2890         666 :     hIvasRend->hLimiter = NULL;
    2891         666 :     hIvasRend->efapOutWrapper.hEfap = NULL;
    2892         666 :     hIvasRend->efapOutWrapper.pCustomLsSetup = NULL;
    2893         666 :     hIvasRend->num_subframes = num_subframes;
    2894             : 
    2895             :     /* Initialize limiter */
    2896         666 :     IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
    2897             :     {
    2898           0 :         return error;
    2899             :     }
    2900             : 
    2901         666 :     IF( NE_32( ( error = initLimiter( &hIvasRend->hLimiter, numOutChannels, outputSampleRate ) ), IVAS_ERR_OK ) )
    2902             :     {
    2903           0 :         return error;
    2904             :     }
    2905             : 
    2906             :     /* Initialize headrotation data */
    2907         666 :     IF( NE_32( ( error = initHeadRotation_fx( hIvasRend ) ), IVAS_ERR_OK ) )
    2908             :     {
    2909           0 :         return error;
    2910             :     }
    2911             : 
    2912             :     /* Initialize external orientation data */
    2913         666 :     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         666 :     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         666 :     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        3330 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    2931             :     {
    2932        2664 :         initRendInputBase_fx( &hIvasRend->inputsIsm[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    2933        2664 :         hIvasRend->inputsIsm[i].crendWrapper = NULL;
    2934        2664 :         hIvasRend->inputsIsm[i].hReverb = NULL;
    2935        2664 :         hIvasRend->inputsIsm[i].tdRendWrapper.hBinRendererTd = NULL;
    2936        2664 :         hIvasRend->inputsIsm[i].nonDiegeticPan = nonDiegeticPan;
    2937        2664 :         move16();
    2938        2664 :         hIvasRend->inputsIsm[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
    2939        2664 :         move32();
    2940        2664 :         hIvasRend->inputsIsm[i].hOMasa = NULL;
    2941        2664 :         hIvasRend->inputsIsm[i].bufferData_fx = NULL;
    2942             :     }
    2943             : 
    2944        1332 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    2945             :     {
    2946         666 :         initRendInputBase_fx( &hIvasRend->inputsMc[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    2947             : 
    2948         666 :         hIvasRend->inputsMc[i].efapInWrapper.hEfap = NULL;
    2949         666 :         hIvasRend->inputsMc[i].crendWrapper = NULL;
    2950         666 :         hIvasRend->inputsMc[i].hReverb = NULL;
    2951         666 :         hIvasRend->inputsMc[i].tdRendWrapper.hBinRendererTd = NULL;
    2952         666 :         hIvasRend->inputsMc[i].bufferData_fx = NULL;
    2953         666 :         hIvasRend->inputsMc[i].lfeDelayBuffer_fx = NULL;
    2954         666 :         hIvasRend->inputsMc[i].nonDiegeticPan = nonDiegeticPan;
    2955         666 :         move16();
    2956         666 :         hIvasRend->inputsMc[i].nonDiegeticPanGain_fx = nonDiegeticPanGain;
    2957         666 :         move32();
    2958         666 :         hIvasRend->inputsMc[i].hMcMasa = NULL;
    2959             :     }
    2960             : 
    2961        1332 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    2962             :     {
    2963         666 :         initRendInputBase_fx( &hIvasRend->inputsSba[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    2964             : 
    2965         666 :         hIvasRend->inputsSba[i].crendWrapper = NULL;
    2966         666 :         hIvasRend->inputsSba[i].bufferData_fx = NULL;
    2967         666 :         hIvasRend->inputsSba[i].hDirAC = NULL;
    2968             :     }
    2969             : 
    2970        1332 :     FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
    2971             :     {
    2972         666 :         initRendInputBase_fx( &hIvasRend->inputsMasa[i].base, IVAS_AUDIO_CONFIG_INVALID, 0, getRendCtx( hIvasRend ), NULL, 0 );
    2973             : 
    2974         666 :         hIvasRend->inputsMasa[i].metadataHasBeenFed = false;
    2975         666 :         hIvasRend->inputsMasa[i].bufferData_fx = NULL;
    2976         666 :         hIvasRend->inputsMasa[i].hMasaPrerend = NULL;
    2977         666 :         hIvasRend->inputsMasa[i].hMasaExtRend = NULL;
    2978         666 :         move16();
    2979             :     }
    2980             : 
    2981             : 
    2982         666 :     return IVAS_ERR_OK;
    2983             : }
    2984         152 : 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         152 :     customLs.num_spk = rendCustomLsLayout.num_spk;
    2992         152 :     move16();
    2993         152 :     Copy32( rendCustomLsLayout.azimuth_fx, customLs.ls_azimuth_fx, rendCustomLsLayout.num_spk );
    2994         152 :     Copy32( rendCustomLsLayout.elevation_fx, customLs.ls_elevation_fx, rendCustomLsLayout.num_spk );
    2995         152 :     customLs.is_planar_setup = 1;
    2996         152 :     move16();
    2997         776 :     FOR( i = 0; i < rendCustomLsLayout.num_spk; ++i )
    2998             :     {
    2999         776 :         IF( fabsf( rendCustomLsLayout.elevation[i] ) > EPSILON )
    3000             :         {
    3001         152 :             customLs.is_planar_setup = 0;
    3002         152 :             move16();
    3003         152 :             BREAK;
    3004             :         }
    3005             :     }
    3006             : 
    3007         152 :     customLs.num_lfe = rendCustomLsLayout.num_lfe;
    3008         152 :     move16();
    3009         152 :     Copy( rendCustomLsLayout.lfe_idx, customLs.lfe_idx, rendCustomLsLayout.num_lfe );
    3010             : 
    3011         152 :     return customLs;
    3012             : }
    3013             : 
    3014             : 
    3015         152 : 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         152 :     test();
    3022         152 :     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         152 :     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         152 :     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         152 :     return IVAS_ERR_OK;
    3043             : }
    3044             : 
    3045             : 
    3046             : /*-------------------------------------------------------------------*
    3047             :  * IVAS_REND_ConfigureCustomOutputLoudspeakerLayout()
    3048             :  *
    3049             :  *
    3050             :  *-------------------------------------------------------------------*/
    3051             : 
    3052          47 : 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          47 :     IF( hIvasRend == NULL )
    3063             :     {
    3064           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3065             :     }
    3066             : 
    3067          47 :     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          47 :     IF( NE_32( ( error = validateCustomLsLayout_fx( layout ) ), IVAS_ERR_OK ) )
    3074             :     {
    3075           0 :         return error;
    3076             :     }
    3077             : 
    3078          47 :     hIvasRend->customLsOut = makeCustomLsSetup( layout );
    3079             : 
    3080             :     /* Re-initialize limiter - number of output channels may have changed */
    3081          47 :     IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
    3082             :     {
    3083           0 :         return error;
    3084             :     }
    3085             : 
    3086          47 :     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          47 :     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          94 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    3101             :     {
    3102          47 :         inputMc = &hIvasRend->inputsMc[i];
    3103          47 :         IF( EQ_32( inputMc->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3104             :         {
    3105             :             /* Input inactive, skip. */
    3106          47 :             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          94 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    3119             :     {
    3120          47 :         inputSba = &hIvasRend->inputsSba[i];
    3121             : 
    3122          47 :         IF( EQ_32( inputSba->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3123             :         {
    3124             :             /* Input inactive, skip. */
    3125          47 :             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          47 :     return IVAS_ERR_OK;
    3134             : }
    3135             : 
    3136             : /*-------------------------------------------------------------------*
    3137             :  * IVAS_REND_NumOutChannels()
    3138             :  *
    3139             :  *
    3140             :  *-------------------------------------------------------------------*/
    3141             : 
    3142     1127519 : 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     1127519 :     test();
    3150     1127519 :     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     1127519 :     SWITCH( hIvasRend->outputConfig )
    3157             :     {
    3158       36003 :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
    3159       36003 :             *numOutChannels = add( hIvasRend->customLsOut.num_spk, hIvasRend->customLsOut.num_lfe );
    3160       36003 :             move16();
    3161       36003 :             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     1127519 :     return IVAS_ERR_OK;
    3171             : }
    3172             : 
    3173             : 
    3174         973 : 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         973 :     return (IVAS_REND_InputId) UL_or( UL_lshl( ( (UWord32) getAudioConfigType( config ) ), 8 ), L_add( inputIndex, 1 ) );
    3182             : }
    3183             : 
    3184             : 
    3185     3133018 : 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     3133018 :     inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
    3196     3133018 :     configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
    3197             : 
    3198             :     /* Validate values derived from input ID */
    3199     3133018 :     IF( inputIndex < 0 )
    3200             :     {
    3201           0 :         return IVAS_ERR_INVALID_INPUT_ID;
    3202             :     }
    3203     3133018 :     SWITCH( configType )
    3204             :     {
    3205     2495576 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    3206     2495576 :             IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
    3207             :             {
    3208           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3209             :             }
    3210     2495576 :             pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
    3211     2495576 :             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     3133018 :     test();
    3239     3133018 :     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     3133018 :     *ppInput = pInputBase;
    3246             : 
    3247     3133018 :     return IVAS_ERR_OK;
    3248             : }
    3249             : 
    3250             : 
    3251      630413 : 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      630413 :     inputIndex = L_sub( L_and( inputId, 0xFF ), 1 );
    3262      630413 :     configType = L_shr( L_and( inputId, 0xFF00 ), 8 );
    3263             : 
    3264             :     /* Validate values derived from input ID */
    3265      630413 :     IF( inputIndex < 0 )
    3266             :     {
    3267           0 :         return IVAS_ERR_INVALID_INPUT_ID;
    3268             :     }
    3269      630413 :     SWITCH( configType )
    3270             :     {
    3271         426 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    3272         426 :             IF( GT_32( inputIndex, RENDERER_MAX_ISM_INPUTS ) )
    3273             :             {
    3274           0 :                 return IVAS_ERR_INVALID_INPUT_ID;
    3275             :             }
    3276         426 :             pInputBase = &hIvasRend->inputsIsm[inputIndex].base;
    3277         426 :             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      630413 :     test();
    3305      630413 :     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      630413 :     *ppInput = pInputBase;
    3312             : 
    3313      630413 :     return IVAS_ERR_OK;
    3314             : }
    3315             : 
    3316         973 : 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         973 :     canAddInput = false;
    3335         973 :     move16();
    3336             : 
    3337             :     /* Find first unused input in array */
    3338        1353 :     FOR( ( i = 0, pByte = inputs ); i < maxInputs; ( ++i, pByte += inputStructSize ) )
    3339             :     {
    3340        1353 :         pInputBase = (const input_base *) pByte;
    3341             : 
    3342        1353 :         IF( EQ_32( pInputBase->inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    3343             :         {
    3344         973 :             *inputIndex = i;
    3345         973 :             move32();
    3346         973 :             canAddInput = true;
    3347         973 :             move16();
    3348         973 :             BREAK;
    3349             :         }
    3350             :     }
    3351             : 
    3352         973 :     IF( !canAddInput )
    3353             :     {
    3354           0 :         return IVAS_ERR_TOO_MANY_INPUTS;
    3355             :     }
    3356             : 
    3357         973 :     return IVAS_ERR_OK;
    3358             : }
    3359             : 
    3360             : 
    3361             : /*-------------------------------------------------------------------*
    3362             :  * IVAS_REND_AddInput()
    3363             :  *
    3364             :  *
    3365             :  *-------------------------------------------------------------------*/
    3366         973 : 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         973 :     test();
    3381         973 :     IF( hIvasRend == NULL || inputId == NULL )
    3382             :     {
    3383           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3384             :     }
    3385             : 
    3386             : 
    3387         973 :     SWITCH( getAudioConfigType( inConfig ) )
    3388             :     {
    3389         426 :         case IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED:
    3390         426 :             maxNumInputsOfType = RENDERER_MAX_ISM_INPUTS;
    3391         426 :             inputsArray = hIvasRend->inputsIsm;
    3392         426 :             inputStructSize = sizeof( *hIvasRend->inputsIsm );
    3393         426 :             activateInput = setRendInputActiveIsm;
    3394         426 :             move32();
    3395         426 :             move32();
    3396         426 :             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         973 :     IF( NE_32( ( error = findFreeInputSlot_fx( inputsArray, inputStructSize, maxNumInputsOfType, &inputIndex ) ), IVAS_ERR_OK ) )
    3427             :     {
    3428           0 :         return error;
    3429             :     }
    3430             : 
    3431         973 :     *inputId = makeInputId( inConfig, inputIndex );
    3432         973 :     move16();
    3433             : 
    3434         973 :     IF( NE_32( ( error = activateInput( (UWord8 *) inputsArray + inputStructSize * inputIndex, inConfig, *inputId, hIvasRend->hRendererConfig ) ), IVAS_ERR_OK ) )
    3435             :     {
    3436           0 :         return error;
    3437             :     }
    3438             : 
    3439         973 :     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         973 : 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         973 :     IF( hIvasRend == NULL )
    3526             :     {
    3527           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3528             :     }
    3529             : 
    3530         973 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    3531             :     {
    3532           0 :         return error;
    3533             :     }
    3534             : 
    3535         973 :     inputBase->gain_fx = gain;
    3536         973 :     move32();
    3537             : 
    3538         973 :     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      630413 : 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      630413 :     test();
    3705      630413 :     IF( hIvasRend == NULL || numChannels == NULL )
    3706             :     {
    3707           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3708             :     }
    3709             : 
    3710      630413 :     IF( NE_32( ( error = getConstInputById( hIvasRend, inputId, (const void **) &pInput ) ), IVAS_ERR_OK ) )
    3711             :     {
    3712           0 :         return error;
    3713             :     }
    3714             : 
    3715      630413 :     IF( NE_32( ( error = getRendInputNumChannels( pInput, numChannels ) ), IVAS_ERR_OK ) )
    3716             :     {
    3717           0 :         return error;
    3718             :     }
    3719             : 
    3720      630413 :     return IVAS_ERR_OK;
    3721             : }
    3722             : 
    3723             : /*-------------------------------------------------------------------*
    3724             :  * IVAS_REND_GetNumAllObjects()
    3725             :  *
    3726             :  *
    3727             :  *-------------------------------------------------------------------*/
    3728         426 : 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         426 :     test();
    3734         426 :     IF( hIvasRend == NULL || numChannels == NULL )
    3735             :     {
    3736           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3737             :     }
    3738             : 
    3739         426 :     test();
    3740         426 :     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         426 :     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     1877090 : 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     1877090 :     test();
    3889     1877090 :     IF( hIvasRend == NULL || inputAudio.data_fx == NULL )
    3890             :     {
    3891           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3892             :     }
    3893             : 
    3894     1877090 :     test();
    3895     1877090 :     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     1877090 :     test();
    3901     1877090 :     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     1877090 :     test();
    3907     1877090 :     move32(); // move added for typecasting
    3908     1877090 :     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     1877090 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    3915             :     {
    3916           0 :         return error;
    3917             :     }
    3918             : 
    3919     1877090 :     IF( NE_32( ( error = getRendInputNumChannels( inputBase, &numInputChannels ) ), IVAS_ERR_OK ) )
    3920             :     {
    3921           0 :         return error;
    3922             :     }
    3923     1877090 :     test();
    3924     1877090 :     test();
    3925     1877090 :     IF( ( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) || EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA2 ) ) && EQ_32( inputBase->inConfig, IVAS_AUDIO_CONFIG_OBA ) )
    3926             :     {
    3927         150 :         numInputChannels = (Word16) hIvasRend->inputsIsm[0].total_num_objects;
    3928         150 :         move16();
    3929             :     }
    3930             : 
    3931     1877090 :     IF( NE_16( numInputChannels, inputAudio.config.numChannels ) )
    3932             :     {
    3933           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    3934             :     }
    3935             : 
    3936     1877090 :     inputBase->inputBuffer.config = inputAudio.config;
    3937             : 
    3938     1877090 :     MVR2R_WORD32( inputAudio.data_fx, inputBase->inputBuffer.data_fx, inputAudio.config.numSamplesPerChannel * inputAudio.config.numChannels );
    3939             : 
    3940     1877090 :     inputBase->numNewSamplesPerChannel = inputAudio.config.numSamplesPerChannel;
    3941     1877090 :     move32();
    3942             : 
    3943     1877090 :     return IVAS_ERR_OK;
    3944             : }
    3945             : 
    3946             : 
    3947             : /*-------------------------------------------------------------------*
    3948             :  * IVAS_REND_FeedInputObjectMetadata()
    3949             :  *
    3950             :  *
    3951             :  *-------------------------------------------------------------------*/
    3952             : 
    3953     1247500 : 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     1247500 :     IF( hIvasRend == NULL )
    3965             :     {
    3966           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    3967             :     }
    3968             : 
    3969     1247500 :     IF( NE_32( ( error = getInputById( hIvasRend, inputId, (void **) &inputBase ) ), IVAS_ERR_OK ) )
    3970             :     {
    3971           0 :         return error;
    3972             :     }
    3973             : 
    3974     1247500 :     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     1247500 :     inputIsm = (input_ism *) inputBase;
    3981     1247500 :     inputIsm->previousPos = inputIsm->currentPos;
    3982     1247500 :     inputIsm->currentPos = objectPosition;
    3983             : 
    3984     1247500 :     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         666 : 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         666 :     rendererConfigEnabled = EQ_32( getAudioConfigType( outAudioConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL );
    4070             : 
    4071         666 :     IF( rendererConfigEnabled )
    4072             :     {
    4073         188 :         hIvasRend->rendererConfigEnabled = 1;
    4074         188 :         move16();
    4075             :     }
    4076             :     ELSE
    4077             :     {
    4078         478 :         hIvasRend->rendererConfigEnabled = 0;
    4079         478 :         move16();
    4080             :     }
    4081             : 
    4082         666 :     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         478 :         hIvasRend->hRendererConfig = NULL;
    4096             :     }
    4097             : 
    4098         666 :     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      946116 : 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      946116 :     IF( hIvasRend == NULL )
    4310             :     {
    4311           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4312             :     }
    4313             : 
    4314      946116 :     hIvasRend->headRotData.headRotEnabled = 0;
    4315      946116 :     move32();
    4316             : 
    4317             :     /* reconfigure binaural rendering to allocate the necessary renderers and free unused ones */
    4318      946116 :     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      946116 :     return IVAS_ERR_OK;
    4334             : }
    4335             : 
    4336             : /*-------------------------------------------------------------------*
    4337             :  * IVAS_REND_SetOrientationTrackingMode()
    4338             :  *
    4339             :  *
    4340             :  *-------------------------------------------------------------------*/
    4341             : 
    4342         666 : 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         666 :     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     1126140 : ivas_error IVAS_REND_CombineHeadAndExternalOrientation(
    4469             :     IVAS_REND_HANDLE hIvasRend /* i/o: Renderer handle      */
    4470             : )
    4471             : {
    4472     1126140 :     IF( hIvasRend == NULL )
    4473             :     {
    4474           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    4475             :     }
    4476     1126140 :     ivas_error error_type = combine_external_and_head_orientations_rend( &hIvasRend->headRotData, hIvasRend->hExternalOrientationData, hIvasRend->hCombinedOrientationData );
    4477     1126140 :     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     5282295 : 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     5282295 :     lastInSmpl = getSmplPtr_fx( inAudio, inChannelIdx, inAudio.config.numSamplesPerChannel );
    4520             : 
    4521    51204875 :     FOR( outChnlIdx = 0; outChnlIdx < outAudio.config.numChannels; ++outChnlIdx )
    4522             :     {
    4523    45922580 :         currentGain = gainsCurrent[outChnlIdx];
    4524    45922580 :         move32();
    4525    45922580 :         if ( gainsPrev == NULL )
    4526             :         {
    4527    42525392 :             previousGain = 0;
    4528    42525392 :             move32();
    4529             :         }
    4530             :         else
    4531             :         {
    4532     3397188 :             previousGain = gainsPrev[outChnlIdx];
    4533     3397188 :             move32();
    4534             :         }
    4535             : 
    4536             :         /* Process current output channel only if applying non-zero gains */
    4537    45922580 :         test();
    4538    45922580 :         test();
    4539    45922580 :         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    27135745 :             inSmpl = getSmplPtr_fx( inAudio, inChannelIdx, 0 );
    4543             : 
    4544             :             /* Set output pointer to first output channel sample */
    4545    27135745 :             outSmpl = getSmplPtr_fx( outAudio, outChnlIdx, 0 );
    4546             : 
    4547    27135745 :             test();
    4548    27135745 :             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 10024117680 :                     *outSmpl = L_add( Mpy_32_32( currentGain, ( *inSmpl ) ), *outSmpl );
    4554 10024117680 :                     move32();
    4555 10024117680 :                     ++outSmpl;
    4556 10024117680 :                     ++inSmpl;
    4557             :                 }
    4558 10024117680 :                 WHILE( inSmpl != lastInSmpl );
    4559             :             }
    4560             :             ELSE
    4561             :             {
    4562     1996136 :                 i = 0;
    4563     1996136 :                 Word32 tmp = Q31_BY_SUB_FRAME_240;
    4564     1996136 :                 Word32 tmp1 = 239; /* L_SUBFRAME_48k - 1 */
    4565     1996136 :                 move32();
    4566     1996136 :                 move32();
    4567     1996136 :                 move32();
    4568     1996136 :                 SWITCH( outAudio.config.numSamplesPerChannel )
    4569             :                 {
    4570     1051037 :                     case NUM_SAMPLES_960:
    4571     1051037 :                         tmp = Q31_BY_NUM_SAMPLES_960;
    4572     1051037 :                         tmp1 = 959; /* NUM_SAMPLES_960 - 1 */
    4573     1051037 :                         move32();
    4574     1051037 :                         move32();
    4575     1051037 :                         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_640:
    4583           0 :                         tmp = Q31_BY_NUM_SAMPLES_640;
    4584           0 :                         tmp1 = 639; /* NUM_SAMPLES_640 - 1 */
    4585           0 :                         move32();
    4586           0 :                         move32();
    4587           0 :                         BREAK;
    4588           0 :                     case NUM_SAMPLES_320:
    4589           0 :                         tmp = Q31_BY_NUM_SAMPLES_320;
    4590           0 :                         tmp1 = 319; /* NUM_SAMPLES_320 - 1 */
    4591           0 :                         move32();
    4592           0 :                         move32();
    4593           0 :                         BREAK;
    4594           0 :                     case NUM_SAMPLES_160:
    4595           0 :                         tmp = Q31_BY_NUM_SAMPLES_160;
    4596           0 :                         tmp1 = 159; /* NUM_SAMPLES_160 - 1 */
    4597           0 :                         move32();
    4598           0 :                         move32();
    4599           0 :                         BREAK;
    4600      945099 :                     case L_SUBFRAME_48k:
    4601      945099 :                         tmp = Q31_BY_SUB_FRAME_240;
    4602      945099 :                         tmp1 = 239; /* L_SUBFRAME_48k - 1 */
    4603      945099 :                         move32();
    4604      945099 :                         move32();
    4605      945099 :                         BREAK;
    4606           0 :                     case L_SUBFRAME_32k:
    4607           0 :                         tmp = Q31_BY_SUB_FRAME_180;
    4608           0 :                         tmp1 = 179; /* L_SUBFRAME_32k - 1 */
    4609           0 :                         move32();
    4610           0 :                         move32();
    4611           0 :                         BREAK;
    4612           0 :                     case L_SUBFRAME_16k:
    4613           0 :                         tmp = Q31_BY_SUB_FRAME_80;
    4614           0 :                         tmp1 = 79; /* L_SUBFRAME_16k - 1 */
    4615           0 :                         move32();
    4616           0 :                         move32();
    4617           0 :                         BREAK;
    4618           0 :                     case L_SUBFRAME_8k:
    4619           0 :                         tmp = Q31_BY_SUB_FRAME_40;
    4620           0 :                         tmp1 = 39; /* L_SUBFRAME_8k - 1 */
    4621           0 :                         move32();
    4622           0 :                         move32();
    4623           0 :                         BREAK;
    4624           0 :                     default:
    4625           0 :                         BREAK;
    4626             :                 }
    4627             :                 /* Otherwise use weighted average between previous and current gain */
    4628  1233823144 :                 DO
    4629             :                 {
    4630  1235819280 :                     IF( EQ_32( i, tmp1 ) )
    4631             :                     {
    4632     1996136 :                         fadeIn = ONE_IN_Q31;
    4633     1996136 :                         move32();
    4634             :                     }
    4635             :                     ELSE
    4636             :                     {
    4637  1233823144 :                         fadeIn = UL_Mpy_32_32( i, tmp );
    4638             :                     }
    4639  1235819280 :                     fadeOut = L_sub( ONE_IN_Q31, fadeIn );
    4640             : 
    4641  1235819280 :                     *outSmpl = L_add( Mpy_32_32( L_add( Mpy_32_32( fadeIn, currentGain ), Mpy_32_32( fadeOut, previousGain ) ), ( *inSmpl ) ), *outSmpl );
    4642  1235819280 :                     move32();
    4643  1235819280 :                     ++outSmpl;
    4644  1235819280 :                     ++inSmpl;
    4645  1235819280 :                     ++i;
    4646             :                 }
    4647  1235819280 :                 WHILE( inSmpl != lastInSmpl );
    4648             :             }
    4649             :         }
    4650             :     }
    4651             : 
    4652     5282295 :     return;
    4653             : }
    4654             : /* Take one channel from input buffer and copy it to each channel
    4655             :    in output buffer, with different gain applied per output channel */
    4656     4334795 : static void renderBufferChannel_fx(
    4657             :     const IVAS_REND_AudioBuffer inAudio,
    4658             :     const Word32 inChannelIdx,
    4659             :     const Word32 *const outputGains, /* Q31 */
    4660             :     IVAS_REND_AudioBuffer outAudio )
    4661             : {
    4662     4334795 :     renderBufferChannelLerp_fx( inAudio, inChannelIdx, outputGains, NULL, outAudio );
    4663             : 
    4664     4334795 :     return;
    4665             : }
    4666             : 
    4667       70522 : static ivas_error chooseCrossfade_fx(
    4668             :     const IVAS_REND_HeadRotData *headRotData,
    4669             :     const Word32 **pCrossfade /* Q31 */ )
    4670             : {
    4671       70522 :     *pCrossfade = headRotData->crossfade_fx;
    4672             : 
    4673       70522 :     return IVAS_ERR_OK;
    4674             : }
    4675             : 
    4676             : 
    4677       25504 : static ivas_error rotateFrameMc_fx(
    4678             :     IVAS_REND_AudioBuffer inAudio,                               /* i  : Input Audio buffer               */
    4679             :     AUDIO_CONFIG inConfig,                                       /* i  : Input Audio config               */
    4680             :     const LSSETUP_CUSTOM_STRUCT *pInCustomLs,                    /* i  : Input Custom LS setup            */
    4681             :     const IVAS_REND_HeadRotData *headRotData,                    /* i  : Head rotation data               */
    4682             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i  : Combined head and external orientations */
    4683             :     rotation_gains_Word32 gains_prev,                            /* i/o: Previous frame rotation gains    */
    4684             :     const EFAP_HANDLE hEFAPdata,                                 /* i  : EFAP structure                   */
    4685             :     IVAS_REND_AudioBuffer outAudio                               /* o  : Output Audio buffer              */
    4686             : )
    4687             : {
    4688             :     Word16 i;
    4689             :     Word16 j;
    4690             :     const Word32 *crossfade; /* Q31 */
    4691             :     Word16 num_subframes;
    4692             :     Word16 subframe_idx, subframe_len;
    4693             :     Word32 azimuth_fx, elevation_fx; /* Q22 */
    4694             :     Word16 is_planar_setup, lfe_idx;
    4695             :     Word16 nchan;
    4696             :     Word16 ch_in, ch_out;
    4697             :     Word16 ch_in_woLFE, ch_out_woLFE;
    4698       25504 :     Word32 *readPtr, *writePtr = NULL;
    4699             :     const Word32 *ls_azimuth, *ls_elevation;
    4700             :     rotation_matrix_fx Rmat_fx;
    4701             :     rotation_gains_Word32 gains;
    4702             :     Word32 tmp_gains[MAX_INPUT_CHANNELS]; /* Q30 */
    4703             :     ivas_error error;
    4704       25504 :     push_wmops( "rotateFrameMc_fx" );
    4705       25504 :     IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
    4706             :     {
    4707           0 :         return error;
    4708             :     }
    4709       25504 :     IF( ( hCombinedOrientationData != NULL ) )
    4710             :     {
    4711       25504 :         num_subframes = ( *hCombinedOrientationData )->num_subframes;
    4712             :     }
    4713             :     ELSE
    4714             :     {
    4715           0 :         num_subframes = MAX_PARAM_SPATIAL_SUBFRAMES;
    4716             :     }
    4717       25504 :     move16();
    4718             : 
    4719       25504 :     IF( NE_32( inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    4720             :     {
    4721       12500 :         IF( NE_32( ( error = getAudioConfigNumChannels( inConfig, &nchan ) ), IVAS_ERR_OK ) )
    4722             :         {
    4723           0 :             return error;
    4724             :         }
    4725             :     }
    4726             :     ELSE
    4727             :     {
    4728       13004 :         nchan = add( pInCustomLs->num_spk, pInCustomLs->num_lfe );
    4729             :     }
    4730             : 
    4731       25504 :     IF( NE_32( ( error = getMcConfigValues_fx( inConfig, pInCustomLs, &ls_azimuth, &ls_elevation, &lfe_idx, &is_planar_setup ) ), IVAS_ERR_OK ) )
    4732             :     {
    4733           0 :         return error;
    4734             :     }
    4735             : 
    4736             :     /* initialize gains to passthrough */
    4737      319068 :     FOR( ch_in = 0; ch_in < nchan; ch_in++ )
    4738             :     {
    4739      293564 :         set32_fx( gains[ch_in], 0, nchan );
    4740      293564 :         gains[ch_in][ch_in] = ONE_IN_Q30;
    4741      293564 :         move32();
    4742             :     }
    4743             : 
    4744             :     /* subframe loop */
    4745             :     Word16 tmp_e;
    4746       25504 :     Word16 tmp = BASOP_Util_Divide3216_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &tmp_e );
    4747       25504 :     tmp = shr( tmp, negate( add( 1, tmp_e ) ) );
    4748       25504 :     subframe_len = tmp;
    4749       25504 :     move16();
    4750             : 
    4751       66314 :     FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
    4752             :     {
    4753      163240 :         FOR( i = 0; i < 3; i++ )
    4754             :         {
    4755      122430 :             IF( hCombinedOrientationData != NULL )
    4756             :             {
    4757      489720 :                 FOR( j = 0; j < 3; j++ )
    4758             :                 {
    4759      367290 :                     Rmat_fx[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
    4760      367290 :                     move32();
    4761             :                 }
    4762             :             }
    4763             :             ELSE
    4764             :             {
    4765             :                 /* Set to identity */
    4766           0 :                 set32_fx( Rmat_fx[i], 0, 3 );
    4767           0 :                 Rmat_fx[i][i] = ONE_IN_Q30;
    4768           0 :                 move32();
    4769             :             }
    4770             :         }
    4771             : 
    4772      510570 :         FOR( ch_in = 0; ch_in < nchan; ch_in++ )
    4773             :         {
    4774             :             /* skip LFE */
    4775      469760 :             IF( EQ_16( ch_in, lfe_idx ) )
    4776             :             {
    4777       20000 :                 CONTINUE;
    4778             :             }
    4779             : 
    4780             :             /* input channel index without LFE */
    4781      449760 :             test();
    4782      449760 :             IF( ( lfe_idx > 0 ) && ( GE_16( ch_in, lfe_idx ) ) )
    4783             :             {
    4784       85600 :                 ch_in_woLFE = sub( ch_in, 1 );
    4785             :             }
    4786             :             ELSE
    4787             :             {
    4788      364160 :                 ch_in_woLFE = ch_in;
    4789      364160 :                 move16();
    4790             :             }
    4791             : 
    4792             : 
    4793             :             /* gains for current subframe rotation */
    4794      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 );
    4795             : 
    4796      449760 :             test();
    4797      449760 :             test();
    4798      449760 :             IF( hEFAPdata != NULL && ( NE_32( ls_azimuth[ch_in_woLFE], azimuth_fx ) || NE_32( ls_elevation[ch_in_woLFE], elevation_fx ) ) )
    4799             :             {
    4800      144730 :                 efap_determine_gains_fx( hEFAPdata, tmp_gains, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
    4801             : 
    4802     1444790 :                 FOR( ch_out = 0; ch_out < nchan; ch_out++ )
    4803             :                 {
    4804             :                     /* skip LFE */
    4805     1300060 :                     IF( EQ_16( ch_out, lfe_idx ) )
    4806             :                     {
    4807      144730 :                         CONTINUE;
    4808             :                     }
    4809             : 
    4810             :                     /* output channel index without LFE */
    4811     1155330 :                     test();
    4812     1155330 :                     IF( ( lfe_idx > 0 ) && ( GE_16( ch_out, lfe_idx ) ) )
    4813             :                     {
    4814      721140 :                         ch_out_woLFE = sub( ch_out, 1 );
    4815             :                     }
    4816             :                     ELSE
    4817             :                     {
    4818      434190 :                         ch_out_woLFE = ch_out;
    4819      434190 :                         move16();
    4820             :                     }
    4821             : 
    4822     1155330 :                     gains[ch_in][ch_out] = tmp_gains[ch_out_woLFE]; // Q30
    4823     1155330 :                     move32();
    4824             :                 }
    4825             :             }
    4826             :         }
    4827             : 
    4828             :         /* apply panning gains by mtx multiplication */
    4829      510570 :         FOR( ch_out = 0; ch_out < nchan; ch_out++ )
    4830             :         {
    4831     6541120 :             FOR( ch_in = 0; ch_in < nchan; ch_in++ )
    4832             :             {
    4833     6071360 :                 writePtr = getSmplPtr_fx( outAudio, ch_out, imult1616( subframe_idx, subframe_len ) ); /* Qx */
    4834     6071360 :                 readPtr = getSmplPtr_fx( inAudio, ch_in, imult1616( subframe_idx, subframe_len ) );    /* Qx */
    4835             :                 /* crossfade with previous rotation gains */
    4836  1463197760 :                 FOR( i = 0; i < subframe_len; i++ )
    4837             :                 {
    4838  1457126400 :                     *writePtr =
    4839  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] ) ),
    4840  1457126400 :                                                  Mpy_32_32( ( *readPtr ), Mpy_32_32( crossfade[i], gains[ch_in][ch_out] ) ) ) ); /* Qx - 1 */
    4841  1457126400 :                     move32();
    4842  1457126400 :                     readPtr++;
    4843  1457126400 :                     writePtr++;
    4844             :                 }
    4845             :             }
    4846             :         }
    4847             : 
    4848             :         /* move gains to gains_prev */
    4849      510570 :         FOR( i = 0; i < nchan; i++ )
    4850             :         {
    4851      469760 :             MVR2R_WORD32( gains[i], gains_prev[i], nchan );
    4852             :         }
    4853             :     }
    4854             : 
    4855       25504 :     pop_wmops();
    4856       25504 :     return IVAS_ERR_OK;
    4857             : }
    4858             : 
    4859             : 
    4860       45018 : static ivas_error rotateFrameSba_fx(
    4861             :     IVAS_REND_AudioBuffer inAudio,                               /* i  : Input Audio buffer                      */
    4862             :     const AUDIO_CONFIG inConfig,                                 /* i  : Input Audio config                      */
    4863             :     const IVAS_REND_HeadRotData *headRotData,                    /* i  : Head rotation data                      */
    4864             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* i  : Combined head and external orientations */
    4865             :     Word16 gains_prev[MAX_INPUT_CHANNELS][MAX_INPUT_CHANNELS],   /* i/o: Previous frame rotation gains       Q14 */
    4866             :     IVAS_REND_AudioBuffer outAudio                               /* o  : Output Audio buffer                     */
    4867             : )
    4868             : {
    4869             :     Word16 i, l, n, m;
    4870             :     Word16 m1, m2;
    4871             :     Word16 shd_rot_max_order;
    4872             :     const Word32 *crossfade; /* Q31 */
    4873             :     Word16 num_subframes;
    4874             :     Word16 subframe_idx, subframe_len;
    4875             :     Word32 *writePtr;
    4876             :     Word32 tmpRot[2 * HEADROT_ORDER + 1];
    4877             :     Word16 gains[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]; /* Q14 */
    4878             :     Word32 temp;
    4879             :     Word32 Rmat[3][3]; /* Q30 */
    4880             :     ivas_error error;
    4881             :     Word16 idx, exp;
    4882             :     Word32 cf, oneminuscf; /* Q31 */
    4883             :     Word32 val;
    4884             : 
    4885       45018 :     push_wmops( "rotateFrameSba" );
    4886             : 
    4887       45018 :     IF( NE_32( ( error = chooseCrossfade_fx( headRotData, &crossfade ) ), IVAS_ERR_OK ) )
    4888             :     {
    4889           0 :         return error;
    4890             :     }
    4891       45018 :     num_subframes = ( hCombinedOrientationData != NULL ) ? ( *hCombinedOrientationData )->num_subframes : MAX_PARAM_SPATIAL_SUBFRAMES;
    4892       45018 :     move16();
    4893             : 
    4894       45018 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( inConfig, &shd_rot_max_order ) ), IVAS_ERR_OK ) )
    4895             :     {
    4896           0 :         return error;
    4897             :     }
    4898             : 
    4899             :     // subframe_len = inAudio.config.numSamplesPerChannel / num_subframes;
    4900       45018 :     subframe_len = BASOP_Util_Divide1616_Scale( inAudio.config.numSamplesPerChannel, num_subframes, &exp );
    4901       45018 :     subframe_len = shr( subframe_len, sub( 15, exp ) );
    4902      117063 :     FOR( subframe_idx = 0; subframe_idx < num_subframes; subframe_idx++ )
    4903             :     {
    4904             :         /* initialize rotation matrices with zeros */
    4905     1224765 :         FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
    4906             :         {
    4907     1152720 :             set16_fx( gains[i], 0, HEADROT_SHMAT_DIM );
    4908             :         }
    4909             : 
    4910      288180 :         FOR( i = 0; i < 3; i++ )
    4911             :         {
    4912      216135 :             IF( hCombinedOrientationData != NULL )
    4913             :             {
    4914      864540 :                 FOR( l = 0; l < 3; l++ )
    4915             :                 {
    4916      648405 :                     Rmat[i][l] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][l]; /* Q30 */
    4917      648405 :                     move32();
    4918             :                 }
    4919             :             }
    4920             :             ELSE
    4921             :             {
    4922             :                 /* Set to identity */
    4923           0 :                 set32_fx( Rmat[i], 0, 3 );
    4924           0 :                 Rmat[i][i] = ONE_IN_Q30;
    4925           0 :                 move32();
    4926             :             }
    4927             :         }
    4928             :         /* calculate ambisonics rotation matrices for the previous and current frames */
    4929       72045 :         SHrotmatgen_fx( gains, Rmat, shd_rot_max_order );
    4930             : 
    4931             : #ifdef DEBUGGING
    4932             :         dbgwrite_txt( (const float *) ( gains[0] ), HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_code_gains.txt", NULL );
    4933             :         dbgwrite_txt( (const float *) ( Rmat[0] ), 3 * 3, "Fixed_code_Rmat.txt", NULL );
    4934             : #endif
    4935    17362845 :         FOR( i = 0; i < subframe_len; i++ )
    4936             :         {
    4937    17290800 :             idx = add( imult1616( subframe_idx, subframe_len ), i );
    4938             :             // cf = crossfade[i];
    4939    17290800 :             cf = crossfade[i];
    4940    17290800 :             move32();
    4941    17290800 :             oneminuscf = L_sub( ONE_IN_Q31, cf );
    4942             :             /*    As the rotation matrix becomes block diagonal in a SH basis, we can*/
    4943             :             /*      apply each angular-momentum block individually to save complexity. */
    4944             : 
    4945             :             /*    loop over l blocks */
    4946    17290800 :             m1 = 1;
    4947    17290800 :             m2 = 4;
    4948    17290800 :             move16();
    4949    17290800 :             move16();
    4950    51872400 :             FOR( l = 1; l <= shd_rot_max_order; l++ )
    4951             :             {
    4952             :                 /* compute mtx-vector product for this l  */
    4953   184435200 :                 FOR( n = m1; n < m2; n++ )
    4954             :                 {
    4955   149853600 :                     tmpRot[n - m1] = 0;
    4956   149853600 :                     move32();
    4957   876067200 :                     FOR( m = m1; m < m2; m++ )
    4958             :                     {
    4959   726213600 :                         val = inAudio.data_fx[m * inAudio.config.numSamplesPerChannel + idx];
    4960             :                         /* crossfade with previous rotation gains */
    4961   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 );
    4962   726213600 :                         tmpRot[n - m1] = L_add( L_shl( temp, 1 ), tmpRot[n - m1] );
    4963   726213600 :                         move32();
    4964   726213600 :                         move32();
    4965             :                     }
    4966             :                 }
    4967             :                 /* write back the result */
    4968   184435200 :                 FOR( n = m1; n < m2; n++ )
    4969             :                 {
    4970   149853600 :                     writePtr = getSmplPtr_fx( outAudio, n, idx );
    4971   149853600 :                     ( *writePtr ) = tmpRot[n - m1];
    4972   149853600 :                     move32();
    4973             :                 }
    4974    34581600 :                 m1 = m2;
    4975    34581600 :                 move16();
    4976    34581600 :                 m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
    4977             :             }
    4978             :         }
    4979             : 
    4980             :         /* move SHrotmat to SHrotmat_prev */
    4981     1224765 :         FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
    4982             :         {
    4983     1152720 :             Copy( gains[i], gains_prev[i], HEADROT_SHMAT_DIM );
    4984             :         }
    4985             :     }
    4986       45018 :     pop_wmops();
    4987             : 
    4988       45018 :     return IVAS_ERR_OK;
    4989             : }
    4990             : 
    4991      150000 : static ivas_error renderIsmToBinaural(
    4992             :     input_ism *ismInput,
    4993             :     IVAS_REND_AudioBuffer outAudio )
    4994             : {
    4995             :     Word32 tmpTDRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    4996             :     ivas_error error;
    4997             :     Word16 ism_md_subframe_update_ext;
    4998             :     Word16 i;
    4999      150000 :     Word16 exp = *outAudio.pq_fact;
    5000      150000 :     move16();
    5001      150000 :     push_wmops( "renderIsmToBinaural" );
    5002             :     /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
    5003      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 */ ) );
    5004      150000 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpTDRendBuffer );
    5005             : 
    5006     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5007             :     {
    5008     2400000 :         Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    5009             :     }
    5010             : 
    5011      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,
    5012             :                                                            *ismInput->base.ctx.pOutSampleRate, outAudio.config.numSamplesPerChannel, tmpTDRendBuffer, &exp ) ),
    5013             :                IVAS_ERR_OK ) )
    5014             :     {
    5015           0 :         return error;
    5016             :     }
    5017             : 
    5018     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5019             :     {
    5020     2400000 :         Scale_sig32( tmpTDRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    5021             :     }
    5022             : 
    5023      150000 :     IF( ismInput->hReverb != NULL )
    5024             :     {
    5025           0 :         FOR( i = 0; i < outAudio.config.numChannels; i++ )
    5026             :         {
    5027           0 :             FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
    5028             :             {
    5029           0 :                 tmpTDRendBuffer[i][j] = L_shl( tmpTDRendBuffer[i][j], Q2 ); /* Q(exp + 2) */
    5030           0 :                 move32();
    5031             :             }
    5032             :         }
    5033             :     }
    5034      150000 :     accumulate2dArrayToBuffer_fx( tmpTDRendBuffer, &outAudio );
    5035             : 
    5036      150000 :     pop_wmops();
    5037             : 
    5038      150000 :     return IVAS_ERR_OK;
    5039             : }
    5040             : 
    5041      302544 : static Word16 getNumSubframesInBuffer(
    5042             :     const IVAS_REND_AudioBuffer *buffer,
    5043             :     const Word32 sampleRate )
    5044             : {
    5045      302544 :     Word16 scale, temp = extract_l( Mpy_32_32( sampleRate, 10737418 /* 1 / FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES in Q31 */ ) );
    5046      302544 :     temp = BASOP_Util_Divide1616_Scale( buffer->config.numSamplesPerChannel, temp, &scale );
    5047      302544 :     temp = shr( temp, sub( 15, scale ) ); /* Q0 */
    5048      302544 :     return temp;
    5049             : }
    5050             : 
    5051             : 
    5052      150000 : static ivas_error renderIsmToBinauralRoom(
    5053             :     input_ism *ismInput,
    5054             :     IVAS_REND_AudioBuffer outAudio,
    5055             :     Word16 *exp )
    5056             : {
    5057             :     Word16 position_changed;
    5058             :     Word16 i, j;
    5059             :     Word32 azi_rot, ele_rot; /* Q22 */
    5060             :     Word16 subframe_idx;
    5061             :     Word16 tmp;
    5062             :     rotation_matrix_fx Rmat;
    5063             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    5064             :     ivas_error error;
    5065             :     pan_vector_fx currentPanGains;
    5066             :     IVAS_REND_AudioBuffer tmpMcBuffer;
    5067             :     IVAS_ISM_METADATA rotatedPosPrev;
    5068             :     IVAS_ISM_METADATA rotatedPos;
    5069             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    5070             :     Word8 combinedOrientationEnabled;
    5071             :     Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
    5072             : 
    5073     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    5074             :     {
    5075     2400000 :         p_tmpRendBuffer[i] = tmpRendBuffer[i];
    5076             :     }
    5077             : 
    5078      150000 :     push_wmops( "renderIsmToBinauralRoom" );
    5079             : 
    5080      150000 :     rotatedPosPrev = defaultObjectPosition();
    5081      150000 :     rotatedPos = defaultObjectPosition();
    5082             : 
    5083      150000 :     hCombinedOrientationData = ismInput->base.ctx.pCombinedOrientationData;
    5084      150000 :     combinedOrientationEnabled = 0;
    5085      150000 :     move16();
    5086      150000 :     IF( hCombinedOrientationData != NULL )
    5087             :     {
    5088      270000 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    5089             :         {
    5090      195000 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    5091             :             {
    5092       75000 :                 combinedOrientationEnabled = 1;
    5093       75000 :                 move16();
    5094       75000 :                 BREAK;
    5095             :             }
    5096             :         }
    5097             :     }
    5098             : 
    5099      150000 :     IF( combinedOrientationEnabled )
    5100             :     {
    5101      150000 :         FOR( subframe_idx = 0; subframe_idx < 1; subframe_idx++ )
    5102             :         {
    5103      300000 :             FOR( i = 0; i < 3; i++ )
    5104             :             {
    5105      225000 :                 test();
    5106      225000 :                 IF( hCombinedOrientationData != NULL && ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] )
    5107             :                 {
    5108      900000 :                     FOR( j = 0; j < 3; j++ )
    5109             :                     {
    5110      675000 :                         Rmat[i][j] = ( *hCombinedOrientationData )->Rmat_fx[subframe_idx][i][j];
    5111      675000 :                         move32();
    5112             :                     }
    5113             :                 }
    5114             :                 ELSE
    5115             :                 {
    5116             :                     /* Set to identity */
    5117           0 :                     set_zero_fx( Rmat[i], 3 );
    5118           0 :                     Rmat[i][i] = ONE_IN_Q30;
    5119           0 :                     move32();
    5120             :                 }
    5121             :             }
    5122             :         }
    5123             :     }
    5124             : 
    5125             :     /* get previous position */
    5126      150000 :     IF( combinedOrientationEnabled )
    5127             :     {
    5128       75000 :         rotateAziEle_fx_frac_az_el( ismInput->previousPos.azimuth_fx, ismInput->previousPos.elevation_fx, &azi_rot, &ele_rot, ismInput->rot_mat_prev, 0 );
    5129       75000 :         rotatedPosPrev.azimuth_fx = azi_rot;
    5130       75000 :         move32();
    5131       75000 :         rotatedPosPrev.elevation_fx = ele_rot;
    5132       75000 :         move32();
    5133             :     }
    5134             :     ELSE
    5135             :     {
    5136       75000 :         rotatedPosPrev.azimuth_fx = ismInput->previousPos.azimuth_fx;
    5137       75000 :         move32();
    5138       75000 :         rotatedPosPrev.elevation_fx = ismInput->previousPos.elevation_fx;
    5139       75000 :         move32();
    5140             :     }
    5141             : 
    5142             :     /* get current position */
    5143      150000 :     IF( combinedOrientationEnabled )
    5144             :     {
    5145       75000 :         rotateAziEle_fx_frac_az_el( ismInput->currentPos.azimuth_fx, ismInput->currentPos.elevation_fx, &azi_rot, &ele_rot, Rmat, 0 );
    5146       75000 :         rotatedPos.azimuth_fx = azi_rot;
    5147       75000 :         move32();
    5148       75000 :         rotatedPos.elevation_fx = ele_rot;
    5149       75000 :         move32();
    5150             :     }
    5151             :     ELSE
    5152             :     {
    5153       75000 :         rotatedPos.azimuth_fx = ismInput->currentPos.azimuth_fx;
    5154       75000 :         move32();
    5155       75000 :         rotatedPos.elevation_fx = ismInput->currentPos.elevation_fx;
    5156       75000 :         move32();
    5157             :     }
    5158             : 
    5159      150000 :     test();
    5160      150000 :     position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &rotatedPos, &rotatedPosPrev );
    5161      150000 :     move16();
    5162             : 
    5163             :     /* set previous gains if this is the first frame */
    5164      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 ) )
    5165             :     {
    5166           0 :         return error;
    5167             :     }
    5168             : 
    5169             :     /* compute gains only if position changed */
    5170      150000 :     IF( position_changed )
    5171             :     {
    5172       64693 :         IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
    5173             :                                               rotatedPos.azimuth_fx,
    5174             :                                               rotatedPos.elevation_fx,
    5175             :                                               currentPanGains ) ),
    5176             :                    IVAS_ERR_OK ) )
    5177             :         {
    5178           0 :             return error;
    5179             :         }
    5180             :     }
    5181             : 
    5182             :     /* intermediate rendering to 7_1_4 */
    5183      150000 :     tmpMcBuffer = ismInput->base.inputBuffer;
    5184             : 
    5185      150000 :     IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
    5186             :     {
    5187           0 :         return error;
    5188             :     }
    5189             : 
    5190      150000 :     tmpMcBuffer.config.numChannels = tmp;
    5191      150000 :     move16();
    5192      150000 :     tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
    5193      150000 :     set_zero_fx( tmpMcBuffer.data_fx, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
    5194             : 
    5195      150000 :     IF( position_changed )
    5196             :     {
    5197       64693 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
    5198             :                                     currentPanGains,
    5199       64693 :                                     ismInput->prev_pan_gains_fx,
    5200             :                                     tmpMcBuffer );
    5201             :     }
    5202             :     ELSE
    5203             :     {
    5204       85307 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
    5205       85307 :                                     ismInput->prev_pan_gains_fx,
    5206             :                                     NULL,
    5207             :                                     tmpMcBuffer );
    5208             :     }
    5209             : 
    5210      150000 :     copyBufferTo2dArray_fx( tmpMcBuffer, tmpRendBuffer );
    5211             : 
    5212             :     /* save gains for next frame */
    5213      600000 :     FOR( i = 0; i < 3; i++ )
    5214             :     {
    5215      450000 :         Copy32( Rmat[i], ismInput->rot_mat_prev[i], 3 );
    5216             :     }
    5217             : 
    5218      150000 :     IF( position_changed )
    5219             :     {
    5220       64693 :         Copy32( currentPanGains, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    5221             :     }
    5222             :     // Crend_process porting
    5223             :     CREND_HANDLE hCrend;
    5224      150000 :     hCrend = ismInput->crendWrapper->hCrend;
    5225      150000 :     IF( hCrend->reflections != NULL )
    5226             :     {
    5227           0 :         test();
    5228           0 :         IF( EQ_32( hCrend->reflections->use_er, 1 ) && EQ_32( hCrend->reflections->is_ready, 1 ) )
    5229             :         {
    5230           0 :             FOR( i = 0; i < 150; i++ )
    5231             :             {
    5232           0 :                 hCrend->reflections->shoebox_data.gains.data_fx[i] = L_shl( hCrend->reflections->shoebox_data.gains.data_fx[i], Q9 );
    5233           0 :                 move32();
    5234             :             }
    5235             :         }
    5236             :     }
    5237             : 
    5238      150000 :     move16();
    5239             : 
    5240             :     /* render 7_1_4 with BRIRs */
    5241      150000 :     IF( NE_32( ( error = ivas_rend_crendProcess( ismInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR,
    5242             :                                                  NULL, NULL, NULL, NULL, p_tmpRendBuffer, *ismInput->base.ctx.pOutSampleRate,
    5243             :                                                  getNumSubframesInBuffer( &outAudio, *ismInput->base.ctx.pOutSampleRate ) ) ),
    5244             :                IVAS_ERR_OK ) )
    5245             : 
    5246             :     {
    5247           0 :         return error;
    5248             :     }
    5249      150000 :     IF( hCrend->hReverb != NULL )
    5250             :     {
    5251           0 :         *exp = sub( *exp, 2 );
    5252           0 :         move16();
    5253             :     }
    5254      150000 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
    5255             : 
    5256      150000 :     free( tmpMcBuffer.data_fx );
    5257             : 
    5258      150000 :     pop_wmops();
    5259             : 
    5260      150000 :     return IVAS_ERR_OK;
    5261             : }
    5262      150000 : static ivas_error renderIsmToBinauralReverb(
    5263             :     input_ism *ismInput,
    5264             :     IVAS_REND_AudioBuffer outAudio )
    5265             : {
    5266             :     Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    5267             :     ivas_error error;
    5268             :     Word16 ism_md_subframe_update_ext, i;
    5269      150000 :     Word16 exp = *outAudio.pq_fact;
    5270      150000 :     move16();
    5271             : 
    5272      150000 :     push_wmops( "renderIsmToBinauralRoom" );
    5273             : 
    5274             :     /* Metadata Delay to sync with audio delay converted from ms to 5ms (1000/50/4) subframe index */
    5275      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 */ ) );
    5276      150000 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
    5277             : 
    5278     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5279             :     {
    5280     2400000 :         Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    5281             :     }
    5282             : 
    5283      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 ) )
    5284             :     {
    5285           0 :         return error;
    5286             :     }
    5287             : 
    5288     2550000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5289             :     {
    5290     2400000 :         Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( 11, exp ) ) ); /* Q(exp) */
    5291             :     }
    5292             : 
    5293      150000 :     IF( ismInput->hReverb != NULL )
    5294             :     {
    5295      450000 :         FOR( i = 0; i < outAudio.config.numChannels; i++ )
    5296             :         {
    5297   115500000 :             FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel; j++ )
    5298             :             {
    5299   115200000 :                 tmpRendBuffer_fx[i][j] = L_shl( tmpRendBuffer_fx[i][j], 2 ); /* Q(exp + 2) */
    5300   115200000 :                 move16();
    5301             :             }
    5302             :         }
    5303             :     }
    5304      150000 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    5305      150000 :     pop_wmops();
    5306             : 
    5307      150000 :     return IVAS_ERR_OK;
    5308             : }
    5309             : 
    5310      569500 : static ivas_error renderIsmToMc(
    5311             :     input_ism *ismInput,
    5312             :     const IVAS_REND_AudioBuffer outAudio )
    5313             : {
    5314             :     Word8 position_changed;
    5315             :     pan_vector_fx currentPanGains_fx; /* Q31 */
    5316             :     ivas_error error;
    5317             : 
    5318      569500 :     push_wmops( "renderIsmToMc" );
    5319             : 
    5320      569500 :     ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5321      569500 :     move32();
    5322      569500 :     ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5323      569500 :     move32();
    5324      569500 :     ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5325      569500 :     move32();
    5326      569500 :     ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5327      569500 :     move32();
    5328             : 
    5329      569500 :     test();
    5330      569500 :     position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
    5331      569500 :     move16();
    5332      569500 :     IF( EQ_32( *ismInput->base.ctx.pOutConfig, IVAS_AUDIO_CONFIG_STEREO ) )
    5333             :     {
    5334       83500 :         IF( ismInput->nonDiegeticPan )
    5335             :         {
    5336        7500 :             currentPanGains_fx[0] = L_add( L_shr( ismInput->nonDiegeticPanGain_fx, 1 ), ONE_IN_Q30 ); /* Q31 */
    5337        7500 :             currentPanGains_fx[1] = L_sub( ONE_IN_Q31, currentPanGains_fx[0] );                       /* Q31 */
    5338        7500 :             ismInput->prev_pan_gains_fx[0] = currentPanGains_fx[0];                                   /* Q31 */
    5339        7500 :             ismInput->prev_pan_gains_fx[1] = currentPanGains_fx[1];                                   /* Q31 */
    5340        7500 :             move32();
    5341        7500 :             move32();
    5342        7500 :             move32();
    5343        7500 :             move32();
    5344             :         }
    5345             :         ELSE
    5346             :         {
    5347       76000 :             set32_fx( currentPanGains_fx, 0, MAX_OUTPUT_CHANNELS );
    5348             : 
    5349             :             Word16 gains_fx[2];
    5350             :             Word16 azimuth_tmp, elevation_tmp;
    5351             : 
    5352       76000 :             azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
    5353       76000 :             elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
    5354             : 
    5355       76000 :             ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
    5356       76000 :             currentPanGains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
    5357       76000 :             currentPanGains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
    5358       76000 :             move32();
    5359       76000 :             move32();
    5360             : 
    5361       76000 :             azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
    5362       76000 :             elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
    5363             : 
    5364       76000 :             set32_fx( ismInput->prev_pan_gains_fx, 0, MAX_OUTPUT_CHANNELS );
    5365       76000 :             ivas_ism_get_stereo_gains_fx( azimuth_tmp, elevation_tmp, &gains_fx[0], &gains_fx[1] );
    5366       76000 :             ismInput->prev_pan_gains_fx[0] = L_deposit_h( gains_fx[0] ); /* Q31 */
    5367       76000 :             ismInput->prev_pan_gains_fx[1] = L_deposit_h( gains_fx[1] ); /* Q31 */
    5368       76000 :             move32();
    5369       76000 :             move32();
    5370             :         }
    5371             :     }
    5372             :     ELSE
    5373             :     {
    5374             :         /* compute gains only if position changed */
    5375      486000 :         IF( position_changed )
    5376             :         {
    5377             :             // TODO tmu review when #215 is resolved
    5378      207304 :             IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
    5379             :                                                   ismInput->currentPos.azimuth_fx,
    5380             :                                                   ismInput->currentPos.elevation_fx,
    5381             :                                                   currentPanGains_fx ) ),
    5382             :                        IVAS_ERR_OK ) )
    5383             :             {
    5384           0 :                 return error;
    5385             :             }
    5386             :         }
    5387             : 
    5388             :         /* set previous gains if this is the first frame */
    5389      486000 :         IF( !ismInput->firstFrameRendered )
    5390             :         {
    5391             :             // TODO tmu review when #215 is resolved
    5392         188 :             IF( NE_32( ( error = getEfapGains_fx( *ismInput->base.ctx.pEfapOutWrapper,
    5393             :                                                   ismInput->previousPos.azimuth_fx,
    5394             :                                                   ismInput->previousPos.elevation_fx,
    5395             :                                                   ismInput->prev_pan_gains_fx ) ),
    5396             :                        IVAS_ERR_OK ) )
    5397             :             {
    5398           0 :                 return error;
    5399             :             }
    5400             :             /* fix2float to be removed */
    5401             :         }
    5402             :     }
    5403             : 
    5404             :     /* Assume num channels in audio buffer to be 1.
    5405             :      * This should have been validated in IVAS_REND_FeedInputAudio() */
    5406      569500 :     IF( position_changed )
    5407             :     {
    5408      244300 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
    5409             :                                     currentPanGains_fx,
    5410      244300 :                                     ismInput->prev_pan_gains_fx,
    5411             :                                     outAudio );
    5412             :     }
    5413             :     ELSE
    5414             :     {
    5415      325200 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
    5416      325200 :                                     ismInput->prev_pan_gains_fx,
    5417             :                                     NULL,
    5418             :                                     outAudio );
    5419             :     }
    5420             : 
    5421      569500 :     IF( position_changed )
    5422             :     {
    5423      244300 :         Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    5424             :     }
    5425             : 
    5426      569500 :     pop_wmops();
    5427             : 
    5428             : 
    5429      569500 :     return IVAS_ERR_OK;
    5430             : }
    5431      228000 : static ivas_error renderIsmToSba(
    5432             :     input_ism *ismInput,
    5433             :     const AUDIO_CONFIG outConfig,
    5434             :     const IVAS_REND_AudioBuffer outAudio )
    5435             : {
    5436             :     Word16 i;
    5437             :     Word8 position_changed;
    5438             :     Word16 ambiOrderOut;
    5439             :     Word16 numOutChannels;
    5440             :     pan_vector_fx currentPanGains_fx;
    5441             :     ivas_error error;
    5442      228000 :     error = IVAS_ERR_OK;
    5443      228000 :     move32();
    5444             : 
    5445      228000 :     ismInput->currentPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->currentPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5446      228000 :     ismInput->currentPos.elevation_fx = L_shl( L_shr( L_add( ismInput->currentPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5447      228000 :     ismInput->previousPos.azimuth_fx = L_shl( L_shr( L_add( ismInput->previousPos.azimuth_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5448      228000 :     ismInput->previousPos.elevation_fx = L_shl( L_shr( L_add( ismInput->previousPos.elevation_fx, ONE_IN_Q21 ), Q22 ), Q22 );
    5449      228000 :     move32();
    5450      228000 :     move32();
    5451      228000 :     move32();
    5452      228000 :     move32();
    5453             : 
    5454      228000 :     push_wmops( "renderIsmToSba" );
    5455             : 
    5456      228000 :     IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &numOutChannels ) ), IVAS_ERR_OK ) )
    5457             :     {
    5458           0 :         return error;
    5459             :     }
    5460             : 
    5461      228000 :     IF( NE_32( ( error = getAmbisonicsOrder_fx( outConfig, &ambiOrderOut ) ), IVAS_ERR_OK ) )
    5462             :     {
    5463           0 :         return error;
    5464             :     }
    5465             : 
    5466      228000 :     test();
    5467      228000 :     position_changed = !ismInput->firstFrameRendered || checkObjectPositionChanged_fx( &ismInput->currentPos, &ismInput->previousPos );
    5468      228000 :     move16();
    5469             : 
    5470             :     /* set previous gains if this is the first frame */
    5471             :     Word16 azimuth_tmp, elevation_tmp;
    5472      228000 :     IF( !ismInput->firstFrameRendered )
    5473             :     {
    5474             :         // TODO tmu review when #215 is resolved
    5475          84 :         azimuth_tmp = extract_l( L_shr( ismInput->previousPos.azimuth_fx, Q22 ) );
    5476          84 :         elevation_tmp = extract_l( L_shr( ismInput->previousPos.elevation_fx, Q22 ) );
    5477          84 :         ivas_dirac_dec_get_response_fx( azimuth_tmp,
    5478             :                                         elevation_tmp,
    5479          84 :                                         ismInput->prev_pan_gains_fx,
    5480             :                                         ambiOrderOut,
    5481             :                                         Q29 );
    5482        1428 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    5483             :         {
    5484        1344 :             ismInput->prev_pan_gains_fx[i] = L_shl_sat( ismInput->prev_pan_gains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
    5485        1344 :             move32();
    5486             :         }
    5487             :     }
    5488             : 
    5489             :     /* compute gains only if position changed */
    5490      228000 :     IF( position_changed )
    5491             :     {
    5492             :         // TODO tmu review when #215 is resolved
    5493       88848 :         azimuth_tmp = extract_l( L_shr( ismInput->currentPos.azimuth_fx, Q22 ) );
    5494       88848 :         elevation_tmp = extract_l( L_shr( ismInput->currentPos.elevation_fx, Q22 ) );
    5495       88848 :         ivas_dirac_dec_get_response_fx( azimuth_tmp,
    5496             :                                         elevation_tmp,
    5497             :                                         currentPanGains_fx,
    5498             :                                         ambiOrderOut,
    5499             :                                         Q29 );
    5500     1510416 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    5501             :         {
    5502     1421568 :             currentPanGains_fx[i] = L_shl_sat( currentPanGains_fx[i], Q2 ); /* Q29 + Q2 = Q31 */
    5503     1421568 :             move32();
    5504             :         }
    5505             :     }
    5506             : 
    5507             :     /* Assume num channels in audio buffer to be 1.
    5508             :      * This should have been validated in IVAS_REND_FeedInputAudio() */
    5509      228000 :     IF( position_changed )
    5510             :     {
    5511       88848 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
    5512             :                                     currentPanGains_fx,
    5513       88848 :                                     ismInput->prev_pan_gains_fx,
    5514             :                                     outAudio );
    5515             :     }
    5516             :     ELSE
    5517             :     {
    5518      139152 :         renderBufferChannelLerp_fx( ismInput->base.inputBuffer, 0,
    5519      139152 :                                     ismInput->prev_pan_gains_fx,
    5520             :                                     NULL,
    5521             :                                     outAudio );
    5522             :     }
    5523             : 
    5524      228000 :     IF( position_changed )
    5525             :     {
    5526       88848 :         Copy32( currentPanGains_fx, ismInput->prev_pan_gains_fx, MAX_OUTPUT_CHANNELS );
    5527             :     }
    5528      228000 :     pop_wmops();
    5529             : 
    5530      228000 :     return error;
    5531             : }
    5532             : 
    5533         150 : static void renderIsmToMasa(
    5534             :     input_ism *ismInput,
    5535             :     IVAS_REND_AudioBuffer outAudio,
    5536             :     Word16 *exp )
    5537             : {
    5538             :     Word32 tmpRendBuffer_fx[MAX_NUM_OBJECTS][L_FRAME48k];
    5539             :     Word16 i, guard_bits, q_min, q_diff;
    5540             : 
    5541         150 :     push_wmops( "renderIsmToMasa" );
    5542             : 
    5543         150 :     copyBufferTo2dArray_fx( ismInput->base.inputBuffer, tmpRendBuffer_fx );
    5544             : 
    5545         150 :     q_min = MAX_16;
    5546         150 :     move16();
    5547             : 
    5548         750 :     FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
    5549             :     {
    5550         600 :         q_min = s_min( q_min, L_norm_arr( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel ) );
    5551             :     }
    5552             : 
    5553         150 :     guard_bits = find_guarded_bits_fx( ismInput->base.inputBuffer.config.numSamplesPerChannel );
    5554         150 :     q_min = sub( add( q_min, *outAudio.pq_fact ), guard_bits );
    5555         150 :     q_diff = sub( q_min, *outAudio.pq_fact );
    5556             : 
    5557         750 :     FOR( i = 0; i < ismInput->base.inputBuffer.config.numChannels; i++ )
    5558             :     {
    5559         600 :         scale_sig32( tmpRendBuffer_fx[i], ismInput->base.inputBuffer.config.numSamplesPerChannel, q_diff ); // *outAudio.pq_fact -> q_min
    5560             :     }
    5561             : 
    5562         150 :     ivas_omasa_ana_fx( ismInput->hOMasa, tmpRendBuffer_fx, &q_min, ismInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels, ismInput->base.inputBuffer.config.numChannels );
    5563             : 
    5564         150 :     *exp = q_min;
    5565         150 :     move16();
    5566             : 
    5567         150 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    5568             : 
    5569         150 :     pop_wmops();
    5570             : 
    5571         150 :     return;
    5572             : }
    5573             : 
    5574     1247650 : static ivas_error renderInputIsm(
    5575             :     input_ism *ismInput,
    5576             :     const AUDIO_CONFIG outConfig,
    5577             :     const IVAS_REND_AudioBuffer outAudio )
    5578             : {
    5579             :     ivas_error error;
    5580             :     IVAS_REND_AudioBuffer inAudio;
    5581     1247650 :     Word16 exp = *outAudio.pq_fact;
    5582     1247650 :     move16();
    5583             : 
    5584     1247650 :     error = IVAS_ERR_OK;
    5585     1247650 :     move32();
    5586     1247650 :     inAudio = ismInput->base.inputBuffer;
    5587             : 
    5588     1247650 :     IF( NE_32( ismInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
    5589             :     {
    5590           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" );
    5591             :     }
    5592     1247650 :     ismInput->base.numNewSamplesPerChannel = 0;
    5593     1247650 :     move32();
    5594             : 
    5595             :     /* Apply input gain to new audio */
    5596     1247650 :     v_multc_fixed( inAudio.data_fx, ismInput->base.gain_fx, inAudio.data_fx, imult1616( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
    5597     1247650 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 );
    5598     1247650 :     move16();
    5599     1247650 :     exp = *outAudio.pq_fact;
    5600     1247650 :     move16();
    5601             : 
    5602             :     /* set combined orientation subframe info to start info */
    5603     1247650 :     ivas_combined_orientation_set_to_start_index( *ismInput->base.ctx.pCombinedOrientationData );
    5604             : 
    5605             : 
    5606     1247650 :     SWITCH( getAudioConfigType( outConfig ) )
    5607             :     {
    5608      569500 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    5609      569500 :             error = renderIsmToMc( ismInput, outAudio );
    5610      569500 :             BREAK;
    5611      228000 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    5612      228000 :             error = renderIsmToSba( ismInput, outConfig, outAudio );
    5613      228000 :             BREAK;
    5614      450000 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    5615             :             SWITCH( outConfig )
    5616             :             {
    5617      150000 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    5618      150000 :                     error = renderIsmToBinaural( ismInput, outAudio );
    5619      150000 :                     BREAK;
    5620      150000 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    5621      150000 :                     error = renderIsmToBinauralRoom( ismInput, outAudio, &exp );
    5622      150000 :                     BREAK;
    5623      150000 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    5624      150000 :                     error = renderIsmToBinauralReverb( ismInput, outAudio );
    5625      150000 :                     BREAK;
    5626           0 :                 default:
    5627           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    5628             :             }
    5629      450000 :             BREAK;
    5630         150 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    5631         150 :             renderIsmToMasa( ismInput, outAudio, &exp );
    5632         150 :             BREAK;
    5633           0 :         default:
    5634           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    5635             :     }
    5636             : 
    5637             :     /* Check error here to keep switch statement more compact */
    5638     1247650 :     IF( NE_32( error, IVAS_ERR_OK ) )
    5639             :     {
    5640           0 :         return error;
    5641             :     }
    5642             : 
    5643     1247650 :     ismInput->firstFrameRendered = TRUE;
    5644     1247650 :     move16();
    5645             : 
    5646     1247650 :     *outAudio.pq_fact = exp;
    5647     1247650 :     move16();
    5648             : 
    5649     1247650 :     return error;
    5650             : }
    5651             : 
    5652     1126140 : static ivas_error renderActiveInputsIsm(
    5653             :     IVAS_REND_HANDLE hIvasRend,
    5654             :     IVAS_REND_AudioBuffer outAudio )
    5655             : {
    5656             :     Word16 i;
    5657             :     input_ism *pCurrentInput;
    5658             :     ivas_error error;
    5659     1126140 :     Word16 input_q = Q8;
    5660     1126140 :     move16();
    5661     5630700 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsIsm ); i < RENDERER_MAX_ISM_INPUTS; ( ++i, ++pCurrentInput ) )
    5662             :     {
    5663     4504560 :         IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    5664             :         {
    5665             :             /* Skip inactive inputs */
    5666     3256910 :             CONTINUE;
    5667             :         }
    5668             : 
    5669     1247650 :         *outAudio.pq_fact = Q8;
    5670     1247650 :         move16();
    5671     1247650 :         IF( NE_32( ( error = renderInputIsm( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    5672             :         {
    5673           0 :             return error;
    5674             :         }
    5675  2925119650 :         FOR( Word16 j = 0; j < outAudio.config.numSamplesPerChannel * outAudio.config.numChannels; ++j )
    5676             :         {
    5677  2923872000 :             outAudio.data_fx[j] = L_shl( outAudio.data_fx[j], sub( sub( input_q, 1 ), ( *outAudio.pq_fact ) ) ); /* Q(input_q - 1) */
    5678  2923872000 :             move32();
    5679             :         }
    5680     1247650 :         *outAudio.pq_fact = sub( input_q, 1 );
    5681     1247650 :         move16();
    5682             :     }
    5683     1126140 :     return IVAS_ERR_OK;
    5684             : }
    5685       87012 : static ivas_error renderLfeToBinaural_fx(
    5686             :     const input_mc *mcInput,
    5687             :     IVAS_REND_AudioBuffer outAudio,
    5688             :     Word16 in_q,
    5689             :     Word16 out_q )
    5690             : {
    5691             :     Word16 lfe_idx;
    5692             :     Word32 gain_fx;
    5693             :     Word16 ear_idx, i, r_shift;
    5694             :     Word32 tmpLfeBuffer[MAX_BUFFER_LENGTH_PER_CHANNEL];
    5695             :     Word16 frame_size, num_cpy_smpl_cur_frame, num_cpy_smpl_prev_frame;
    5696             :     const Word32 *lfeInput;
    5697             :     Word32 *writePtr;
    5698             : 
    5699       87012 :     assert( ( outAudio.config.numChannels == 2 ) && "Must be binaural output" );
    5700             : 
    5701       87012 :     push_wmops( "renderLfeToBinaural" );
    5702       87012 :     gain_fx = GAIN_LFE_WORD32; /* 1.88364911f in Q30 */
    5703       87012 :     move32();
    5704             : 
    5705       87012 :     IF( NE_32( mcInput->base.inConfig, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    5706             :     {
    5707       48000 :         lfe_idx = LFE_CHANNEL;
    5708       48000 :         move16();
    5709             :     }
    5710       39012 :     ELSE IF( mcInput->customLsInput.num_lfe > 0 )
    5711             :     {
    5712           0 :         lfe_idx = mcInput->customLsInput.lfe_idx[0];
    5713           0 :         move16();
    5714             :     }
    5715             :     ELSE
    5716             :     {
    5717             :         /* no LFE to render */
    5718             : #ifdef FIX_1740_MISING_POP_WMOPS
    5719       39012 :         pop_wmops();
    5720             : #endif
    5721       39012 :         return IVAS_ERR_OK;
    5722             :     }
    5723             : 
    5724             :     /* --- Prepare LFE signal to be added to binaural output --- */
    5725       48000 :     lfeInput = getSmplPtr_fx( mcInput->base.inputBuffer, lfe_idx, 0 );
    5726       48000 :     frame_size = mcInput->base.inputBuffer.config.numSamplesPerChannel;
    5727       48000 :     move16();
    5728       48000 :     num_cpy_smpl_prev_frame = mcInput->binauralDelaySmp;
    5729       48000 :     move16();
    5730       48000 :     num_cpy_smpl_cur_frame = sub( frame_size, num_cpy_smpl_prev_frame );
    5731             : 
    5732             :     /* Assuming LFE should be delayed by less that the duration of one frame */
    5733       48000 :     assert( mcInput->binauralDelaySmp < frame_size );
    5734             : 
    5735             :     /* Get delayed LFE signal from previous frame, apply gain and save in tmp buffer */
    5736       48000 :     v_multc_fixed( mcInput->lfeDelayBuffer_fx, gain_fx, tmpLfeBuffer, num_cpy_smpl_prev_frame ); /* Qx - 1 */
    5737             : 
    5738             :     /* Continue filling tmp buffer, now with LFE signal from current frame */
    5739       48000 :     v_multc_fixed( lfeInput, gain_fx, tmpLfeBuffer + num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); /* Qx - 1 */
    5740             : 
    5741             :     /* Save remaining LFE samples of current frame for next frame */
    5742       48000 :     MVR2R_WORD32( lfeInput + num_cpy_smpl_cur_frame, mcInput->lfeDelayBuffer_fx, num_cpy_smpl_prev_frame );
    5743       48000 :     r_shift = sub( sub( in_q, 1 ), out_q );
    5744             : 
    5745       48000 :     IF( r_shift != 0 )
    5746             :     {
    5747    14533750 :         FOR( i = 0; i < add( num_cpy_smpl_prev_frame, num_cpy_smpl_cur_frame ); i++ )
    5748             :         {
    5749    14496000 :             tmpLfeBuffer[i] = L_shr( tmpLfeBuffer[i], r_shift ); /* Q(out_q) */
    5750    14496000 :             move32();
    5751             :         }
    5752             :     }
    5753             :     /* Copy LFE to left and right ears */
    5754      144000 :     FOR( ear_idx = 0; ear_idx < BINAURAL_CHANNELS; ++ear_idx )
    5755             :     {
    5756       96000 :         writePtr = getSmplPtr_fx( outAudio, ear_idx, 0 );
    5757       96000 :         move32();
    5758       96000 :         v_add_fixed_no_hdrm( writePtr, tmpLfeBuffer, writePtr, frame_size ); /* Q(out_q) */
    5759             :     }
    5760             : 
    5761       48000 :     pop_wmops();
    5762             : 
    5763       48000 :     return IVAS_ERR_OK;
    5764             : }
    5765       29004 : static ivas_error renderMcToBinaural(
    5766             :     input_mc *mcInput,
    5767             :     const AUDIO_CONFIG outConfig,
    5768             :     IVAS_REND_AudioBuffer outAudio )
    5769             : {
    5770             :     Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    5771             :     AUDIO_CONFIG inConfig;
    5772             :     ivas_error error;
    5773             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    5774             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    5775             :     Word8 combinedOrientationEnabled;
    5776             :     Word16 subframe_idx;
    5777             :     Word32 *p_tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS];
    5778             :     Word16 i;
    5779       29004 :     Word16 exp = *outAudio.pq_fact;
    5780       29004 :     move16();
    5781      493068 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    5782             :     {
    5783      464064 :         p_tmpRendBuffer_fx[i] = tmpRendBuffer_fx[i];
    5784             :     }
    5785       29004 :     push_wmops( "renderMcToBinaural" );
    5786       29004 :     inConfig = mcInput->base.inConfig;
    5787       29004 :     move32();
    5788       29004 :     hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
    5789       29004 :     combinedOrientationEnabled = 0;
    5790       29004 :     move16();
    5791       29004 :     IF( hCombinedOrientationData != NULL )
    5792             :     {
    5793       52209 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    5794             :         {
    5795       37707 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    5796             :             {
    5797       14502 :                 combinedOrientationEnabled = 1;
    5798       14502 :                 move16();
    5799       14502 :                 BREAK;
    5800             :             }
    5801             :         }
    5802             :     }
    5803             : 
    5804       29004 :     test();
    5805       29004 :     test();
    5806       29004 :     test();
    5807       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 ) ) ) )
    5808             :     {
    5809       18754 :         copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
    5810             : 
    5811      318818 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5812             :         {
    5813      300064 :             Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    5814             :         }
    5815       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,
    5816             :                                                                0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer_fx, &exp ) ),
    5817             :                    IVAS_ERR_OK ) )
    5818             :         {
    5819           0 :             return error;
    5820             :         }
    5821             : 
    5822      318818 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5823             :         {
    5824      300064 :             Scale_sig32( tmpRendBuffer_fx[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    5825             :         }
    5826             :     }
    5827             :     ELSE
    5828             :     {
    5829             :         /* apply rotation */
    5830       10250 :         IF( combinedOrientationEnabled )
    5831             :         {
    5832        2250 :             tmpRotBuffer = mcInput->base.inputBuffer;
    5833        2250 :             tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    5834        2250 :             set32_fx( tmpRotBuffer.data_fx, 0, imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) );
    5835             : 
    5836        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 ) )
    5837             :             {
    5838           0 :                 return error;
    5839             :             }
    5840             : 
    5841        2250 :             exp = sub( *outAudio.pq_fact, 1 );
    5842             : 
    5843        2250 :             copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer_fx );
    5844             : 
    5845        2250 :             free( tmpRotBuffer.data_fx );
    5846             :         }
    5847             :         ELSE
    5848             :         {
    5849        8000 :             copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
    5850             :         }
    5851             :         // Porting Crend_process function
    5852             :         CREND_HANDLE hCrend;
    5853       10250 :         hCrend = mcInput->crendWrapper->hCrend;
    5854             : 
    5855             :         /* call CREND */
    5856       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,
    5857             :                                                      getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
    5858             :                    IVAS_ERR_OK ) )
    5859             :         {
    5860           0 :             return error;
    5861             :         }
    5862       10250 :         IF( hCrend->hReverb != NULL )
    5863             :         {
    5864           0 :             exp = sub( exp, 2 );
    5865             :         }
    5866             :     }
    5867             : 
    5868       29004 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    5869             : 
    5870       29004 :     IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
    5871             : 
    5872             :     {
    5873           0 :         return error;
    5874             :     }
    5875       29004 :     *outAudio.pq_fact = exp;
    5876       29004 :     move16();
    5877       29004 :     pop_wmops();
    5878       29004 :     return IVAS_ERR_OK;
    5879             : }
    5880       32000 : static ivas_error renderMcToBinauralRoom(
    5881             :     input_mc *mcInput,
    5882             :     const AUDIO_CONFIG outConfig,
    5883             :     IVAS_REND_AudioBuffer outAudio )
    5884             : {
    5885             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    5886             :     AUDIO_CONFIG inConfig;
    5887             :     ivas_error error;
    5888             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    5889             :     Word32 *p_tmpRendBuffer[MAX_OUTPUT_CHANNELS];
    5890             :     Word16 i;
    5891             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    5892             :     Word8 combinedOrientationEnabled;
    5893             :     Word16 subframe_idx;
    5894       32000 :     Word16 exp = *outAudio.pq_fact;
    5895       32000 :     move16();
    5896      544000 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    5897             :     {
    5898      512000 :         p_tmpRendBuffer[i] = tmpRendBuffer[i];
    5899             :     }
    5900             : 
    5901       32000 :     push_wmops( "renderMcToBinauralRoom" );
    5902       32000 :     inConfig = mcInput->base.inConfig;
    5903       32000 :     move32();
    5904       32000 :     hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
    5905       32000 :     combinedOrientationEnabled = 0;
    5906       32000 :     move16();
    5907       32000 :     IF( hCombinedOrientationData != NULL )
    5908             :     {
    5909       57600 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    5910             :         {
    5911       41600 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    5912             :             {
    5913       16000 :                 combinedOrientationEnabled = 1;
    5914       16000 :                 move16();
    5915       16000 :                 BREAK;
    5916             :             }
    5917             :         }
    5918             :     }
    5919             : 
    5920       32000 :     test();
    5921       32000 :     test();
    5922       32000 :     test();
    5923       32000 :     test();
    5924       32000 :     test();
    5925       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 ) ) ) ) )
    5926             :     {
    5927        5750 :         copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
    5928             : 
    5929       97750 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5930             :         {
    5931       92000 :             Scale_sig32( tmpRendBuffer[i], L_FRAME48k, sub( Q11, exp ) ); /* Q11 */
    5932             :         }
    5933             : 
    5934        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,
    5935             :                                                                0, *mcInput->base.ctx.pOutSampleRate, mcInput->base.inputBuffer.config.numSamplesPerChannel, tmpRendBuffer, &exp ) ),
    5936             :                    IVAS_ERR_OK ) )
    5937             :         {
    5938           0 :             return error;
    5939             :         }
    5940             : 
    5941       97750 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; ++i )
    5942             :         {
    5943       92000 :             Scale_sig32( tmpRendBuffer[i], L_FRAME48k, negate( sub( Q11, exp ) ) ); /* Q(exp) */
    5944             :         }
    5945             :     }
    5946             :     ELSE
    5947             :     {
    5948             :         /* apply rotation */
    5949       26250 :         IF( combinedOrientationEnabled )
    5950             :         {
    5951       10250 :             tmpRotBuffer = mcInput->base.inputBuffer;
    5952       10250 :             tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    5953       10250 :             set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
    5954             : 
    5955       10250 :             IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData,
    5956             :                                                    mcInput->rot_gains_prev_fx,
    5957             :                                                    mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
    5958             :                        IVAS_ERR_OK ) )
    5959             :             {
    5960           0 :                 return error;
    5961             :             }
    5962             : 
    5963       10250 :             exp = sub( *outAudio.pq_fact, 1 );
    5964             : 
    5965       10250 :             copyBufferTo2dArray_fx( tmpRotBuffer, tmpRendBuffer );
    5966       10250 :             free( tmpRotBuffer.data_fx );
    5967             :         }
    5968             :         ELSE
    5969             :         {
    5970       16000 :             copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer );
    5971             :         }
    5972             :         // Porting Crend_process function
    5973             :         CREND_HANDLE hCrend;
    5974       26250 :         hCrend = mcInput->crendWrapper->hCrend;
    5975             : 
    5976             :         /* call CREND */
    5977       26250 :         IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, mcInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, p_tmpRendBuffer, *mcInput->base.ctx.pOutSampleRate,
    5978             :                                                      getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
    5979             :                    IVAS_ERR_OK ) )
    5980             :         {
    5981           0 :             return error;
    5982             :         }
    5983       26250 :         IF( hCrend->hReverb != NULL )
    5984             :         {
    5985       10250 :             exp = sub( exp, Q2 );
    5986             :         }
    5987             :     }
    5988             : 
    5989       32000 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
    5990             : 
    5991       32000 :     IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
    5992             :     {
    5993           0 :         return error;
    5994             :     }
    5995       32000 :     *outAudio.pq_fact = exp;
    5996       32000 :     move16();
    5997       32000 :     pop_wmops();
    5998       32000 :     return IVAS_ERR_OK;
    5999             : }
    6000       26008 : static ivas_error renderMcCustomLsToBinauralRoom(
    6001             :     input_mc *mcInput,
    6002             :     const AUDIO_CONFIG outConfig,
    6003             :     IVAS_REND_AudioBuffer outAudio )
    6004             : {
    6005             :     Word16 i;
    6006             :     Word16 tmp;
    6007             :     Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6008             :     ivas_error error;
    6009             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    6010             :     IVAS_REND_AudioBuffer tmpMcBuffer;
    6011             :     IVAS_REND_AudioBuffer *tmpBufPtr;
    6012             :     Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
    6013             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    6014             :     Word8 combinedOrientationEnabled;
    6015             :     Word16 subframe_idx;
    6016       26008 :     Word16 exp = *outAudio.pq_fact;
    6017       26008 :     move16();
    6018       26008 :     push_wmops( "renderMcCustomLsToBinauralRoom" );
    6019       26008 :     tmpRotBuffer = outAudio; /* avoid compilation warning */
    6020             : 
    6021      442136 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6022             :     {
    6023      416128 :         p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
    6024             :     }
    6025             : 
    6026       26008 :     hCombinedOrientationData = mcInput->base.ctx.pCombinedOrientationData;
    6027       26008 :     combinedOrientationEnabled = 0;
    6028       26008 :     move16();
    6029       26008 :     IF( hCombinedOrientationData != NULL )
    6030             :     {
    6031       46818 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    6032             :         {
    6033       33814 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    6034             :             {
    6035       13004 :                 combinedOrientationEnabled = 1;
    6036       13004 :                 move16();
    6037       13004 :                 BREAK;
    6038             :             }
    6039             :         }
    6040             :     }
    6041             : 
    6042             :     /* apply rotation */
    6043       26008 :     IF( combinedOrientationEnabled )
    6044             :     {
    6045       13004 :         tmpRotBuffer = mcInput->base.inputBuffer;
    6046       13004 :         tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    6047       13004 :         set32_fx( tmpRotBuffer.data_fx, 0, tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels );
    6048             : 
    6049       13004 :         IF( NE_32( ( error = rotateFrameMc_fx( mcInput->base.inputBuffer, mcInput->base.inConfig, &mcInput->customLsInput, mcInput->base.ctx.pHeadRotData, mcInput->base.ctx.pCombinedOrientationData,
    6050             :                                                mcInput->rot_gains_prev_fx,
    6051             :                                                mcInput->efapInWrapper.hEfap, tmpRotBuffer ) ),
    6052             :                    IVAS_ERR_OK ) )
    6053             :         {
    6054           0 :             return error;
    6055             :         }
    6056       13004 :         exp = sub( *outAudio.pq_fact, Q1 );
    6057             :     }
    6058             : 
    6059             :     /* intermediate conversion to 7_1_4 */
    6060       26008 :     tmpMcBuffer = mcInput->base.inputBuffer;
    6061             : 
    6062       26008 :     IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
    6063             :     {
    6064           0 :         return error;
    6065             :     }
    6066             : 
    6067       26008 :     tmpMcBuffer.config.numChannels = tmp;
    6068       26008 :     move16();
    6069       26008 :     tmpMcBuffer.data_fx = malloc( imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) * sizeof( Word32 ) );
    6070       26008 :     set32_fx( tmpMcBuffer.data_fx, 0, imult1616( tmpMcBuffer.config.numSamplesPerChannel, tmpMcBuffer.config.numChannels ) );
    6071             : 
    6072       26008 :     IF( combinedOrientationEnabled )
    6073             :     {
    6074       13004 :         tmpBufPtr = &tmpRotBuffer;
    6075             :     }
    6076             :     ELSE
    6077             :     {
    6078       13004 :         tmpBufPtr = &mcInput->base.inputBuffer;
    6079             :     }
    6080      406136 :     FOR( i = 0; i < mcInput->base.inputBuffer.config.numChannels; i++ )
    6081             :     {
    6082      380128 :         renderBufferChannel_fx( *tmpBufPtr, i, mcInput->panGains_fx[i], tmpMcBuffer );
    6083             :     }
    6084       26008 :     copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
    6085             : 
    6086             :     CREND_HANDLE hCrend;
    6087       26008 :     hCrend = mcInput->crendWrapper->hCrend;
    6088             :     /* call CREND */
    6089       26008 :     IF( NE_32( ( error = ivas_rend_crendProcess( mcInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig, NULL, NULL, NULL, NULL,
    6090             :                                                  p_tmpCrendBuffer, *mcInput->base.ctx.pOutSampleRate, getNumSubframesInBuffer( &outAudio, *mcInput->base.ctx.pOutSampleRate ) ) ),
    6091             :                IVAS_ERR_OK ) )
    6092             :     {
    6093           0 :         return error;
    6094             :     }
    6095       26008 :     IF( hCrend->hReverb != NULL )
    6096             :     {
    6097       13004 :         exp = sub( exp, 2 );
    6098             :     }
    6099             : 
    6100       26008 :     accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
    6101             : 
    6102       26008 :     IF( NE_32( ( error = renderLfeToBinaural_fx( mcInput, outAudio, *outAudio.pq_fact, exp ) ), IVAS_ERR_OK ) )
    6103             :     {
    6104           0 :         return error;
    6105             :     }
    6106       26008 :     *outAudio.pq_fact = exp;
    6107       26008 :     move16();
    6108       26008 :     IF( combinedOrientationEnabled )
    6109             :     {
    6110       13004 :         free( tmpRotBuffer.data_fx );
    6111             :     }
    6112       26008 :     free( tmpMcBuffer.data_fx );
    6113             : 
    6114       26008 :     pop_wmops();
    6115       26008 :     return IVAS_ERR_OK;
    6116             : }
    6117      196617 : static void renderMcToMc(
    6118             :     const input_mc *mcInput,
    6119             :     IVAS_REND_AudioBuffer outAudio )
    6120             : {
    6121             :     Word16 i;
    6122             :     IVAS_REND_AudioBuffer inAudio;
    6123             : 
    6124      196617 :     push_wmops( "renderMcToMc" );
    6125      196617 :     inAudio = mcInput->base.inputBuffer;
    6126             : 
    6127     1507289 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    6128             :     {
    6129     1310672 :         renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
    6130             :     }
    6131             : 
    6132      196617 :     pop_wmops();
    6133      196617 :     return;
    6134             : }
    6135       75756 : static void renderMcToSba(
    6136             :     const input_mc *mcInput,
    6137             :     IVAS_REND_AudioBuffer outAudio )
    6138             : {
    6139             :     Word16 i;
    6140             :     IVAS_REND_AudioBuffer inAudio;
    6141             : 
    6142       75756 :     push_wmops( "renderMcToSba" );
    6143       75756 :     inAudio = mcInput->base.inputBuffer;
    6144             : 
    6145      591852 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    6146             :     {
    6147      516096 :         renderBufferChannel_fx( inAudio, i, mcInput->panGains_fx[i], outAudio );
    6148             :     }
    6149       75756 :     pop_wmops();
    6150       75756 :     return;
    6151             : }
    6152             : 
    6153         150 : static void renderMcToMasa(
    6154             :     input_mc *mcInput,
    6155             :     IVAS_REND_AudioBuffer outAudio )
    6156             : {
    6157         150 :     push_wmops( "renderMcToMasa" );
    6158             :     Word32 tmpRendBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6159         150 :     copyBufferTo2dArray_fx( mcInput->base.inputBuffer, tmpRendBuffer_fx );
    6160         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 );
    6161         150 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer_fx, &outAudio );
    6162             : 
    6163         150 :     pop_wmops();
    6164         150 :     return;
    6165             : }
    6166             : 
    6167      359535 : static ivas_error renderInputMc(
    6168             :     input_mc *mcInput,
    6169             :     const AUDIO_CONFIG outConfig,
    6170             :     IVAS_REND_AudioBuffer outAudio )
    6171             : {
    6172             :     ivas_error error;
    6173             :     IVAS_REND_AudioBuffer inAudio;
    6174      359535 :     error = IVAS_ERR_OK;
    6175      359535 :     move32();
    6176             : 
    6177      359535 :     inAudio = mcInput->base.inputBuffer;
    6178             : 
    6179      359535 :     IF( NE_32( mcInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
    6180             :     {
    6181           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" );
    6182             :     }
    6183      359535 :     mcInput->base.numNewSamplesPerChannel = 0;
    6184      359535 :     move32();
    6185      359535 :     v_multc_fixed( inAudio.data_fx, mcInput->base.gain_fx, inAudio.data_fx, inAudio.config.numSamplesPerChannel * inAudio.config.numChannels );
    6186      359535 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, Q1 ); // reducing the Q by 1 compensating for the v_mult_fixed done
    6187      359535 :     move16();
    6188             :     /* set combined orientation subframe info to start info */
    6189      359535 :     ivas_combined_orientation_set_to_start_index( *( mcInput->base.ctx.pCombinedOrientationData ) );
    6190             : 
    6191      359535 :     SWITCH( getAudioConfigType( outConfig ) )
    6192             :     {
    6193      196617 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    6194      196617 :             renderMcToMc( mcInput, outAudio );
    6195      196617 :             BREAK;
    6196       75756 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    6197       75756 :             renderMcToSba( mcInput, outAudio );
    6198       75756 :             BREAK;
    6199       87012 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    6200             :             SWITCH( outConfig )
    6201             :             {
    6202       29004 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    6203       29004 :                     error = renderMcToBinaural( mcInput, outConfig, outAudio );
    6204       29004 :                     BREAK;
    6205       58008 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    6206             :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    6207       58008 :                     IF( mcInput->base.inConfig == IVAS_AUDIO_CONFIG_LS_CUSTOM )
    6208             :                     {
    6209       26008 :                         error = renderMcCustomLsToBinauralRoom( mcInput, outConfig, outAudio );
    6210             :                     }
    6211             :                     ELSE
    6212             :                     {
    6213       32000 :                         error = renderMcToBinauralRoom( mcInput, outConfig, outAudio );
    6214             :                     }
    6215       58008 :                     BREAK;
    6216           0 :                 default:
    6217           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    6218             :             }
    6219       87012 :             BREAK;
    6220         150 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    6221         150 :             renderMcToMasa( mcInput, outAudio );
    6222         150 :             BREAK;
    6223           0 :         default:
    6224           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    6225             :     }
    6226      359535 :     return error;
    6227             : }
    6228     1126140 : static ivas_error renderActiveInputsMc(
    6229             :     IVAS_REND_HANDLE hIvasRend,
    6230             :     IVAS_REND_AudioBuffer outAudio )
    6231             : {
    6232             :     Word16 i;
    6233             :     input_mc *pCurrentInput;
    6234             :     ivas_error error;
    6235     2252280 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMc ); i < RENDERER_MAX_MC_INPUTS; ( ++i, ++pCurrentInput ) )
    6236             :     {
    6237     1126140 :         IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    6238             :         {
    6239             :             /* Skip inactive inputs */
    6240      766605 :             CONTINUE;
    6241             :         }
    6242             : 
    6243      359535 :         *outAudio.pq_fact = Q8;
    6244      359535 :         move16();
    6245      359535 :         IF( NE_32( ( error = renderInputMc( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    6246             :         {
    6247           0 :             return error;
    6248             :         }
    6249             :     }
    6250             : 
    6251     1126140 :     return IVAS_ERR_OK;
    6252             : }
    6253      115801 : static void renderSbaToMc(
    6254             :     const input_sba *sbaInput,
    6255             :     IVAS_REND_AudioBuffer outAudio )
    6256             : {
    6257             :     Word16 i;
    6258             :     IVAS_REND_AudioBuffer inAudio;
    6259             : 
    6260      115801 :     push_wmops( "renderSbaToMc" );
    6261      115801 :     inAudio = sbaInput->base.inputBuffer;
    6262             : 
    6263     1225294 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    6264             :     {
    6265     1109493 :         renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
    6266             :     }
    6267             : 
    6268      115801 :     pop_wmops();
    6269      115801 :     return;
    6270             : }
    6271             : 
    6272             : 
    6273       45768 : static void renderSbaToSba(
    6274             :     const input_sba *sbaInput,
    6275             :     IVAS_REND_AudioBuffer outAudio )
    6276             : {
    6277             :     Word16 i;
    6278             :     IVAS_REND_AudioBuffer inAudio;
    6279             : 
    6280       45768 :     push_wmops( "renderSbaToSba" );
    6281       45768 :     inAudio = sbaInput->base.inputBuffer;
    6282             : 
    6283      483942 :     FOR( i = 0; i < inAudio.config.numChannels; ++i )
    6284             :     {
    6285      438174 :         renderBufferChannel_fx( inAudio, i, sbaInput->hoaDecMtx_fx[i], outAudio );
    6286             :     }
    6287             : 
    6288       45768 :     pop_wmops();
    6289       45768 :     return;
    6290             : }
    6291       30012 : static ivas_error renderSbaToBinaural(
    6292             :     input_sba *sbaInput,
    6293             :     const AUDIO_CONFIG outConfig,
    6294             :     IVAS_REND_AudioBuffer outAudio )
    6295             : {
    6296             :     ivas_error error;
    6297             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    6298             :     Word16 i;
    6299             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    6300             :     Word8 combinedOrientationEnabled;
    6301             :     Word16 subframe_idx;
    6302             :     Word32 output_buffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6303             :     Word32 *output_fx[MAX_OUTPUT_CHANNELS];
    6304             : 
    6305       30012 :     push_wmops( "renderSbaToBinaural" );
    6306             :     {
    6307             : 
    6308      510204 :         FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6309             :         {
    6310      480192 :             output_fx[i] = output_buffer_fx[i];
    6311             :         }
    6312             : 
    6313       30012 :         hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
    6314       30012 :         combinedOrientationEnabled = 0;
    6315       30012 :         move16();
    6316       30012 :         IF( hCombinedOrientationData != NULL )
    6317             :         {
    6318       54027 :             FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    6319             :             {
    6320       39021 :                 IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    6321             :                 {
    6322       15006 :                     combinedOrientationEnabled = 1;
    6323       15006 :                     move16();
    6324       15006 :                     BREAK;
    6325             :                 }
    6326             :             }
    6327             :         }
    6328             :         /* apply rotation */
    6329       30012 :         IF( combinedOrientationEnabled )
    6330             :         {
    6331       15006 :             tmpRotBuffer = sbaInput->base.inputBuffer;
    6332             : 
    6333       15006 :             tmpRotBuffer.data_fx = malloc( tmpRotBuffer.config.numSamplesPerChannel * tmpRotBuffer.config.numChannels * sizeof( Word32 ) );
    6334             :             /* copy input for in-place rotation */
    6335             : 
    6336       15006 :             Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
    6337             : 
    6338       15006 :             IF( NE_16( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
    6339             :                                                     sbaInput->base.ctx.pCombinedOrientationData, sbaInput->rot_gains_prev_fx, tmpRotBuffer ) ),
    6340             :                        IVAS_ERR_OK ) )
    6341             :             {
    6342           0 :                 return error;
    6343             :             }
    6344             : 
    6345       15006 :             copyBufferTo2dArray_fx( tmpRotBuffer, output_buffer_fx );
    6346       15006 :             free( tmpRotBuffer.data_fx );
    6347             :         }
    6348             :         ELSE
    6349             :         {
    6350       15006 :             copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, output_buffer_fx );
    6351             :         }
    6352             :         // Porting Crend_process function
    6353             :         CREND_HANDLE hCrend;
    6354       30012 :         hCrend = sbaInput->crendWrapper->hCrend;
    6355             : 
    6356             :         /* call CREND */
    6357       30012 :         IF( NE_32( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, sbaInput->base.inConfig, outConfig, NULL, NULL, NULL, NULL, output_fx, *sbaInput->base.ctx.pOutSampleRate,
    6358             :                                                      getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ),
    6359             :                    IVAS_ERR_OK ) )
    6360             :         {
    6361           0 :             return error;
    6362             :         }
    6363       30012 :         IF( hCrend->hReverb != NULL )
    6364             :         {
    6365           0 :             *outAudio.pq_fact = sub( *outAudio.pq_fact, Q2 );
    6366           0 :             move16();
    6367             :         }
    6368       30012 :         accumulate2dArrayToBuffer_fx( output_buffer_fx, &outAudio );
    6369             :     }
    6370             : 
    6371       30012 :     pop_wmops();
    6372       30012 :     return IVAS_ERR_OK;
    6373             : }
    6374       60024 : static ivas_error renderSbaToBinauralRoom(
    6375             :     input_sba *sbaInput,
    6376             :     const AUDIO_CONFIG outConfig,
    6377             :     IVAS_REND_AudioBuffer outAudio )
    6378             : {
    6379             :     Word16 i;
    6380             :     Word16 tmp;
    6381             :     Word32 tmpCrendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6382             :     ivas_error error;
    6383             :     IVAS_REND_AudioBuffer tmpRotBuffer;
    6384             :     IVAS_REND_AudioBuffer tmpMcBuffer;
    6385             :     IVAS_REND_AudioBuffer *tmpBufPtr;
    6386             :     Word32 *p_tmpCrendBuffer[MAX_OUTPUT_CHANNELS];
    6387             :     const COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData;
    6388             :     Word8 combinedOrientationEnabled;
    6389             :     Word16 subframe_idx;
    6390             : 
    6391       60024 :     tmpRotBuffer = outAudio; /* avoid compilation warning */
    6392       60024 :     push_wmops( "renderSbaToBinauralRoom" );
    6393             :     Word16 nchan_out;
    6394             :     CREND_HANDLE hCrend;
    6395             : 
    6396       60024 :     hCrend = sbaInput->crendWrapper->hCrend;
    6397             : 
    6398       60024 :     IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &nchan_out ) ), IVAS_ERR_OK ) )
    6399             :     {
    6400           0 :         return error;
    6401             :     }
    6402             : 
    6403     1020408 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    6404             :     {
    6405      960384 :         p_tmpCrendBuffer[i] = tmpCrendBuffer[i];
    6406             :     }
    6407             : 
    6408       60024 :     hCombinedOrientationData = sbaInput->base.ctx.pCombinedOrientationData;
    6409       60024 :     combinedOrientationEnabled = 0;
    6410       60024 :     move16();
    6411       60024 :     IF( hCombinedOrientationData != NULL )
    6412             :     {
    6413      108054 :         FOR( subframe_idx = 0; subframe_idx < ( *hCombinedOrientationData )->num_subframes; subframe_idx++ )
    6414             :         {
    6415       78042 :             IF( ( *hCombinedOrientationData )->enableCombinedOrientation[subframe_idx] != 0 )
    6416             :             {
    6417       30012 :                 combinedOrientationEnabled = 1;
    6418       30012 :                 move16();
    6419       30012 :                 BREAK;
    6420             :             }
    6421             :         }
    6422             :     }
    6423             : 
    6424             :     /* apply rotation */
    6425       60024 :     IF( combinedOrientationEnabled )
    6426             :     {
    6427       30012 :         tmpRotBuffer = sbaInput->base.inputBuffer;
    6428       30012 :         tmpRotBuffer.data_fx = malloc( imult1616( tmpRotBuffer.config.numSamplesPerChannel, tmpRotBuffer.config.numChannels ) * sizeof( Word32 ) );
    6429             : 
    6430             :         /* copy input for in-place rotation */
    6431       30012 :         Copy32( sbaInput->base.inputBuffer.data_fx, tmpRotBuffer.data_fx, i_mult( tmpRotBuffer.config.numChannels, tmpRotBuffer.config.numSamplesPerChannel ) );
    6432             : 
    6433       30012 :         IF( NE_32( ( error = rotateFrameSba_fx( sbaInput->base.inputBuffer, sbaInput->base.inConfig, sbaInput->base.ctx.pHeadRotData,
    6434             :                                                 sbaInput->base.ctx.pCombinedOrientationData,
    6435             :                                                 sbaInput->rot_gains_prev_fx,
    6436             :                                                 tmpRotBuffer ) ),
    6437             :                    IVAS_ERR_OK ) )
    6438             :         {
    6439           0 :             return error;
    6440             :         }
    6441             :     }
    6442             : 
    6443             :     /* intermediate rendering to 7_1_4 */
    6444       60024 :     tmpMcBuffer = sbaInput->base.inputBuffer;
    6445             : 
    6446       60024 :     IF( NE_32( ( error = getAudioConfigNumChannels( IVAS_AUDIO_CONFIG_7_1_4, &tmp ) ), IVAS_ERR_OK ) )
    6447             :     {
    6448           0 :         return error;
    6449             :     }
    6450             : 
    6451       60024 :     tmpMcBuffer.config.numChannels = tmp;
    6452       60024 :     move16();
    6453       60024 :     tmpMcBuffer.data_fx = malloc( tmpMcBuffer.config.numSamplesPerChannel * tmpMcBuffer.config.numChannels * sizeof( Word32 ) );
    6454       60024 :     set32_fx( tmpMcBuffer.data_fx, 0, i_mult( tmpMcBuffer.config.numChannels, tmpMcBuffer.config.numSamplesPerChannel ) );
    6455             : 
    6456       60024 :     IF( combinedOrientationEnabled )
    6457             :     {
    6458       30012 :         tmpBufPtr = &tmpRotBuffer;
    6459             :     }
    6460             :     ELSE
    6461             :     {
    6462       30012 :         tmpBufPtr = &sbaInput->base.inputBuffer;
    6463             :     }
    6464      640256 :     FOR( i = 0; i < sbaInput->base.inputBuffer.config.numChannels; i++ )
    6465             :     {
    6466      580232 :         renderBufferChannel_fx( *tmpBufPtr, i, sbaInput->hoaDecMtx_fx[i], tmpMcBuffer );
    6467             :     }
    6468       60024 :     copyBufferTo2dArray_fx( tmpMcBuffer, tmpCrendBuffer );
    6469             :     // Porting Crend_process function
    6470             : 
    6471             :     /* call CREND */
    6472       60024 :     IF( NE_32( ( error = ivas_rend_crendProcess( sbaInput->crendWrapper, IVAS_AUDIO_CONFIG_7_1_4, outConfig,
    6473             :                                                  NULL, NULL, NULL, NULL, p_tmpCrendBuffer, *sbaInput->base.ctx.pOutSampleRate,
    6474             :                                                  getNumSubframesInBuffer( &outAudio, *sbaInput->base.ctx.pOutSampleRate ) ) ),
    6475             :                IVAS_ERR_OK ) )
    6476             :     {
    6477           0 :         return error;
    6478             :     }
    6479       60024 :     IF( hCrend->hReverb != NULL )
    6480             :     {
    6481       30012 :         *outAudio.pq_fact = sub( *outAudio.pq_fact, 2 );
    6482       30012 :         move16();
    6483             :     }
    6484             : 
    6485       60024 :     accumulate2dArrayToBuffer_fx( tmpCrendBuffer, &outAudio );
    6486             : 
    6487       60024 :     IF( combinedOrientationEnabled )
    6488             :     {
    6489       30012 :         free( tmpRotBuffer.data_fx );
    6490             :     }
    6491       60024 :     free( tmpMcBuffer.data_fx );
    6492             : 
    6493       60024 :     pop_wmops();
    6494       60024 :     return IVAS_ERR_OK;
    6495             : }
    6496         150 : static void renderSbaToMasa(
    6497             :     input_sba *sbaInput,
    6498             :     IVAS_REND_AudioBuffer outAudio )
    6499             : {
    6500             :     Word32 tmpRendBuffer[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6501             : 
    6502         150 :     push_wmops( "renderMcToMasa" );
    6503         150 :     copyBufferTo2dArray_fx( sbaInput->base.inputBuffer, tmpRendBuffer );
    6504         150 :     ivas_dirac_ana_fx( sbaInput->hDirAC, tmpRendBuffer, sbaInput->base.inputBuffer.config.numSamplesPerChannel, outAudio.config.numChannels );
    6505         150 :     accumulate2dArrayToBuffer_fx( tmpRendBuffer, &outAudio );
    6506             : 
    6507         150 :     pop_wmops();
    6508         150 :     return;
    6509             : }
    6510      251755 : static ivas_error renderInputSba(
    6511             :     input_sba *sbaInput,
    6512             :     const AUDIO_CONFIG outConfig,
    6513             :     IVAS_REND_AudioBuffer outAudio )
    6514             : {
    6515             :     ivas_error error;
    6516             :     IVAS_REND_AudioBuffer inAudio;
    6517      251755 :     error = IVAS_ERR_OK;
    6518      251755 :     move32();
    6519      251755 :     inAudio = sbaInput->base.inputBuffer;
    6520             : 
    6521      251755 :     IF( NE_32( sbaInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
    6522             :     {
    6523           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" );
    6524             :     }
    6525      251755 :     sbaInput->base.numNewSamplesPerChannel = 0;
    6526      251755 :     move32();
    6527      251755 :     *outAudio.pq_fact = outAudio.q_factor;
    6528      251755 :     move16();
    6529             :     /* Apply input gain to new audio */
    6530      251755 :     v_multc_fixed( inAudio.data_fx, sbaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
    6531      251755 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
    6532      251755 :     move16();
    6533             : 
    6534             :     /* set combined orientation subframe info to start info */
    6535      251755 :     ivas_combined_orientation_set_to_start_index( *( sbaInput->base.ctx.pCombinedOrientationData ) );
    6536             : 
    6537      251755 :     SWITCH( getAudioConfigType( outConfig ) )
    6538             :     {
    6539      115801 :         case IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED:
    6540      115801 :             renderSbaToMc( sbaInput, outAudio );
    6541      115801 :             BREAK;
    6542       45768 :         case IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS:
    6543       45768 :             renderSbaToSba( sbaInput, outAudio );
    6544       45768 :             BREAK;
    6545       90036 :         case IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL:
    6546             :             SWITCH( outConfig )
    6547             :             {
    6548       30012 :                 case IVAS_AUDIO_CONFIG_BINAURAL:
    6549       30012 :                     error = renderSbaToBinaural( sbaInput, outConfig, outAudio );
    6550       30012 :                     BREAK;
    6551       60024 :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    6552             :                 case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    6553       60024 :                     error = renderSbaToBinauralRoom( sbaInput, outConfig, outAudio );
    6554       60024 :                     BREAK;
    6555           0 :                 default:
    6556           0 :                     return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    6557             :             }
    6558       90036 :             BREAK;
    6559         150 :         case IVAS_REND_AUDIO_CONFIG_TYPE_MASA:
    6560         150 :             renderSbaToMasa( sbaInput, outAudio );
    6561         150 :             BREAK;
    6562           0 :         default:
    6563           0 :             return IVAS_ERR_INVALID_OUTPUT_FORMAT;
    6564             :     }
    6565             : 
    6566      251755 :     return error;
    6567             : }
    6568     1126140 : static ivas_error renderActiveInputsSba(
    6569             :     IVAS_REND_HANDLE hIvasRend,
    6570             :     IVAS_REND_AudioBuffer outAudio )
    6571             : {
    6572             :     Word16 i;
    6573             :     input_sba *pCurrentInput;
    6574             :     ivas_error error;
    6575             : 
    6576     2252280 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsSba ); i < RENDERER_MAX_SBA_INPUTS; ( ++i, ++pCurrentInput ) )
    6577             :     {
    6578     1126140 :         IF( EQ_32( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    6579             :         {
    6580             :             /* Skip inactive inputs */
    6581      874385 :             CONTINUE;
    6582             :         }
    6583      251755 :         *outAudio.pq_fact = Q8;
    6584      251755 :         move16();
    6585      251755 :         IF( NE_32( ( error = renderInputSba( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    6586             :         {
    6587           0 :             return error;
    6588             :         }
    6589             :     }
    6590     1126140 :     return IVAS_ERR_OK;
    6591             : }
    6592             : 
    6593             : 
    6594       17250 : static void copyMasaMetadataToDiracRenderer_fx(
    6595             :     MASA_METADATA_FRAME *meta,
    6596             :     SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom,
    6597             :     const Word16 maxBin )
    6598             : {
    6599             :     Word16 band, sf, bin;
    6600             :     Word16 meta_write_index;
    6601             : 
    6602       17250 :     hSpatParamRendCom->numParametricDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
    6603       17250 :     hSpatParamRendCom->numSimultaneousDirections = add( meta->descriptive_meta.numberOfDirections, 1 );
    6604       17250 :     move16();
    6605       17250 :     move16();
    6606             : 
    6607       86250 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    6608             :     {
    6609       69000 :         meta_write_index = add( hSpatParamRendCom->dirac_bs_md_write_idx, sf ) % hSpatParamRendCom->dirac_md_buffer_length;
    6610             : 
    6611     1725000 :         FOR( band = 0; band < MASA_MAXIMUM_CODING_SUBBANDS; band++ )
    6612             :         {
    6613     5796000 :             FOR( bin = MASA_band_grouping_24[band]; bin < MASA_band_grouping_24[band + 1] && bin < maxBin; bin++ )
    6614             :             {
    6615     4140000 :                 hSpatParamRendCom->azimuth[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    6616     4140000 :                 move16();
    6617     4140000 :                 hSpatParamRendCom->elevation[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[0].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    6618     4140000 :                 move16();
    6619     4140000 :                 hSpatParamRendCom->energy_ratio1_fx[meta_write_index][bin] = meta->directional_meta[0].energy_ratio_fx[sf][band];
    6620     4140000 :                 move32();
    6621     4140000 :                 hSpatParamRendCom->diffuseness_vector_fx[meta_write_index][bin] = L_sub( ONE_IN_Q30, meta->directional_meta[0].energy_ratio_fx[sf][band] );
    6622     4140000 :                 move32();
    6623     4140000 :                 hSpatParamRendCom->spreadCoherence_fx[meta_write_index][bin] = meta->directional_meta[0].spread_coherence_fx[sf][band];
    6624     4140000 :                 move16();
    6625     4140000 :                 hSpatParamRendCom->surroundingCoherence_fx[meta_write_index][bin] = meta->common_meta.surround_coherence_fx[sf][band];
    6626     4140000 :                 move16();
    6627             : 
    6628     4140000 :                 IF( EQ_16( hSpatParamRendCom->numSimultaneousDirections, 2 ) )
    6629             :                 {
    6630     2160000 :                     hSpatParamRendCom->azimuth2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].azimuth_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    6631     2160000 :                     move16();
    6632     2160000 :                     hSpatParamRendCom->elevation2[meta_write_index][bin] = extract_l( L_shr( meta->directional_meta[1].elevation_fx[sf][band], Q22 ) ); /* Q22 - Q22 = Q0 */
    6633     2160000 :                     move16();
    6634     2160000 :                     hSpatParamRendCom->energy_ratio2_fx[meta_write_index][bin] = meta->directional_meta[1].energy_ratio_fx[sf][band];
    6635     2160000 :                     move32();
    6636     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] );
    6637     2160000 :                     move32();
    6638     2160000 :                     hSpatParamRendCom->spreadCoherence2_fx[meta_write_index][bin] = meta->directional_meta[1].spread_coherence_fx[sf][band];
    6639     2160000 :                     move16();
    6640             :                 }
    6641             :             }
    6642             :         }
    6643             :     }
    6644             : 
    6645       17250 :     hSpatParamRendCom->dirac_bs_md_write_idx = add( hSpatParamRendCom->dirac_bs_md_write_idx, MAX_PARAM_SPATIAL_SUBFRAMES ) % hSpatParamRendCom->dirac_md_buffer_length;
    6646       17250 :     move16();
    6647             : 
    6648       17250 :     return;
    6649             : }
    6650             : 
    6651             : 
    6652         150 : static void renderMasaToMasa(
    6653             :     input_masa *masaInput,
    6654             :     IVAS_REND_AudioBuffer outAudio )
    6655             : {
    6656             :     Word16 sf, band, dir, numDirs;
    6657             :     Word32 ratioSum_fx; /* Q30 */
    6658             :     MASA_DECODER_EXT_OUT_META_HANDLE outMeta;
    6659             :     MASA_METADATA_FRAME *inMeta;
    6660             :     Word32 tmpBuffer_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6661             :     Word16 ts, i, j, l_ts;
    6662             :     Word32 Chan_RealBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
    6663             :     Word32 Chan_ImagBuffer_fx[MASA_MAX_TRANSPORT_CHANNELS][CLDFB_NO_CHANNELS_MAX];
    6664             :     Word16 band_m_idx, block_m_idx;
    6665             :     Word16 mrange[2];
    6666             :     Word16 brange[2];
    6667             :     Word16 numAnalysisChannels;
    6668         150 :     copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_fx );
    6669         150 :     Word16 q_cldfb = *outAudio.pq_fact;
    6670         150 :     Word16 q_cldfb_out = *outAudio.pq_fact;
    6671         150 :     Word16 scale_factor = 31;
    6672             :     Word16 scale_fac_arr[MASA_MAX_TRANSPORT_CHANNELS];
    6673         150 :     move16();
    6674         150 :     move16();
    6675         150 :     move16();
    6676             :     /* Calculate energy */
    6677             :     // l_ts = masaInput->base.inputBuffer.config.numSamplesPerChannel / CLDFB_NO_COL_MAX;
    6678         150 :     l_ts = shr( masaInput->base.inputBuffer.config.numSamplesPerChannel, 4 );
    6679         150 :     numAnalysisChannels = masaInput->hMasaPrerend->num_Cldfb_instances;
    6680         150 :     move16();
    6681             :     /* do processing over all CLDFB time slots */
    6682         750 :     FOR( block_m_idx = 0; block_m_idx < MAX_PARAM_SPATIAL_SUBFRAMES; block_m_idx++ )
    6683             :     {
    6684         600 :         mrange[0] = DirAC_block_grouping[block_m_idx];
    6685         600 :         mrange[1] = DirAC_block_grouping[block_m_idx + 1];
    6686         600 :         move16();
    6687         600 :         move16();
    6688             : 
    6689         600 :         set_zero_fx( masaInput->hMasaPrerend->energy_fx[block_m_idx], MASA_FREQUENCY_BANDS );
    6690         600 :         set16_fx( masaInput->hMasaPrerend->energy_e[block_m_idx], 0, MASA_FREQUENCY_BANDS );
    6691             : 
    6692        3000 :         FOR( ts = mrange[0]; ts < mrange[1]; ts++ )
    6693             :         {
    6694        7200 :             FOR( i = 0; i < numAnalysisChannels; i++ )
    6695             :             {
    6696        4800 :                 scale_factor = 31;
    6697        4800 :                 move16();
    6698        4800 :                 masaInput->hMasaPrerend->cldfbAnaEnc[i]->Q_cldfb_state = q_cldfb;
    6699        4800 :                 q_cldfb_out = q_cldfb;
    6700        4800 :                 move16();
    6701        4800 :                 move16();
    6702        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 );
    6703        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 ) ) );
    6704        4800 :                 scale_factor = sub( scale_factor, 1 );
    6705        4800 :                 scale_sig32( Chan_RealBuffer_fx[i], CLDFB_NO_CHANNELS_MAX, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
    6706        4800 :                 scale_sig32( Chan_ImagBuffer_fx[i], CLDFB_NO_CHANNELS_MAX, scale_factor ); /* Q(q_cldfb_out + scale_factor) */
    6707        4800 :                 scale_fac_arr[i] = scale_factor;
    6708        4800 :                 move16();
    6709             :             }
    6710             : 
    6711        2400 :             scale_factor = MAX_16;
    6712        2400 :             move16();
    6713        7200 :             FOR( i = 0; i < numAnalysisChannels; i++ )
    6714             :             {
    6715        4800 :                 scale_factor = s_min( scale_factor, scale_fac_arr[i] );
    6716             :             }
    6717             : 
    6718        7200 :             FOR( i = 0; i < numAnalysisChannels; i++ )
    6719             :             {
    6720        4800 :                 IF( NE_16( scale_factor, scale_fac_arr[i] ) )
    6721             :                 {
    6722       48861 :                     FOR( j = 0; j < CLDFB_NO_CHANNELS_MAX; j++ )
    6723             :                     {
    6724       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) */
    6725       48060 :                         move32();
    6726       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) */
    6727       48060 :                         move32();
    6728             :                     }
    6729             :                 }
    6730             :             }
    6731             : 
    6732        2400 :             Word16 q_add = sub( 31, add( scale_factor, q_cldfb_out ) );
    6733             :             /* Compute channel energy for metadata processing */
    6734       60000 :             FOR( band_m_idx = 0; band_m_idx < MASA_FREQUENCY_BANDS; band_m_idx++ )
    6735             :             {
    6736       57600 :                 brange[0] = MASA_band_grouping_24[band_m_idx];
    6737       57600 :                 move16();
    6738       57600 :                 brange[1] = MASA_band_grouping_24[band_m_idx + 1];
    6739       57600 :                 move16();
    6740      201600 :                 FOR( j = brange[0]; j < brange[1]; j++ )
    6741             :                 {
    6742      432000 :                     FOR( i = 0; i < numAnalysisChannels; i++ )
    6743             :                     {
    6744      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 */
    6745      288000 :                         masaInput->hMasaPrerend->energy_fx[block_m_idx][band_m_idx] = BASOP_Util_Add_Mant32Exp( masaInput->hMasaPrerend->energy_fx[block_m_idx][band_m_idx], masaInput->hMasaPrerend->energy_e[block_m_idx][band_m_idx], temp, shl( q_add, 1 ), &masaInput->hMasaPrerend->energy_e[block_m_idx][band_m_idx] );
    6746      288000 :                         move32();
    6747             :                     }
    6748             :                 }
    6749             :             }
    6750             :         }
    6751             :     }
    6752             : 
    6753             :     /* Copy audio channels if mismatch in number of transports */
    6754         150 :     test();
    6755         150 :     test();
    6756         150 :     IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 1 ) && EQ_16( outAudio.config.numChannels, 2 ) )
    6757             :     {
    6758           0 :         Copy32( tmpBuffer_fx[0], tmpBuffer_fx[1], masaInput->base.inputBuffer.config.numSamplesPerChannel );
    6759             :     }
    6760         150 :     ELSE IF( EQ_16( masaInput->base.inputBuffer.config.numChannels, 2 ) && EQ_16( outAudio.config.numChannels, 1 ) )
    6761             :     {
    6762             :         //  v_add( tmpBuffer[0], tmpBuffer[1], tmpBuffer[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
    6763           0 :         v_add_fixed_no_hdrm( tmpBuffer_fx[0], tmpBuffer_fx[1], tmpBuffer_fx[0], masaInput->base.inputBuffer.config.numSamplesPerChannel );
    6764             :     }
    6765             : 
    6766             :     /* Copy metadata */
    6767         150 :     outMeta = masaInput->hMasaPrerend->hMasaOut;
    6768         150 :     inMeta = &masaInput->masaMetadata;
    6769         150 :     numDirs = add( inMeta->descriptive_meta.numberOfDirections, 1 );
    6770             : 
    6771         750 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    6772             :     {
    6773       15000 :         FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    6774             :         {
    6775             :             /* Remainder is always set to zero and energy removal is compensated in following steps
    6776             :              * to other ratios. */
    6777             :             //     inMeta->common_meta.remainder_to_total_ratio[sf][band] = 0.0f;
    6778       14400 :             inMeta->common_meta.remainder_to_total_ratio_fx[sf][band] = 0;
    6779       14400 :             move32();
    6780       14400 :             ratioSum_fx = 0;
    6781       14400 :             move32();
    6782       43200 :             FOR( dir = 0; dir < numDirs; dir++ )
    6783             :             {
    6784       28800 :                 ratioSum_fx = L_add( ratioSum_fx, inMeta->directional_meta[dir].energy_ratio_fx[sf][band] );
    6785             :             }
    6786       14400 :             ratioSum_fx = L_add( ratioSum_fx, inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] );
    6787             : 
    6788       14400 :             IF( ratioSum_fx == 0 )
    6789             :             {
    6790           0 :                 FOR( dir = 0; dir < numDirs; dir++ )
    6791             :                 {
    6792           0 :                     inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = 0;
    6793           0 :                     move32();
    6794             :                 }
    6795           0 :                 inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = ONE_IN_Q30;
    6796           0 :                 move32();
    6797             :             }
    6798       14400 :             ELSE IF( NE_32( ratioSum_fx, ONE_IN_Q30 ) )
    6799             :             {
    6800       14400 :                 Word16 tmp_e = 0;
    6801       14400 :                 move16();
    6802       14400 :                 Word32 tmp = 0;
    6803       14400 :                 move32();
    6804       43200 :                 FOR( dir = 0; dir < numDirs; dir++ )
    6805             :                 {
    6806       28800 :                     tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
    6807       28800 :                     inMeta->directional_meta[dir].energy_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
    6808       28800 :                     move32();
    6809             :                 }
    6810       14400 :                 tmp_e = 0;
    6811       14400 :                 move16();
    6812       14400 :                 tmp = 0;
    6813       14400 :                 move32();
    6814       14400 :                 tmp = BASOP_Util_Divide3232_Scale_newton( inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band], ratioSum_fx, &tmp_e );
    6815       14400 :                 inMeta->common_meta.diffuse_to_total_ratio_fx[sf][band] = L_shl( tmp, sub( tmp_e, 1 ) ); /* Q30 */
    6816       14400 :                 move32();
    6817             :             }
    6818             :         }
    6819             :     }
    6820             : 
    6821         750 :     FOR( sf = 0; sf < MAX_PARAM_SPATIAL_SUBFRAMES; sf++ )
    6822             :     {
    6823       15000 :         FOR( band = 0; band < MASA_FREQUENCY_BANDS; band++ )
    6824             :         {
    6825       14400 :             outMeta->diffuseToTotalRatio[sf][band] = UINT8_MAX;
    6826       14400 :             move16();
    6827       43200 :             FOR( dir = 0; dir < numDirs; dir++ )
    6828             :             {
    6829       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 );
    6830       28800 :                 outMeta->directToTotalRatio[dir][sf][band] = (UWord8) L_shr( inMeta->directional_meta[dir].energy_ratio_fx[sf][band], Q22 );
    6831       28800 :                 outMeta->diffuseToTotalRatio[sf][band] = (UWord8) sub( outMeta->diffuseToTotalRatio[sf][band], outMeta->directToTotalRatio[dir][sf][band] );
    6832       28800 :                 outMeta->spreadCoherence[dir][sf][band] = (UWord8) shr( inMeta->directional_meta[dir].spread_coherence_fx[sf][band], Q7 );
    6833             : 
    6834       28800 :                 move16();
    6835       28800 :                 move16();
    6836       28800 :                 move16();
    6837       28800 :                 move16();
    6838             :             }
    6839       14400 :             outMeta->surroundCoherence[sf][band] = (UWord8) shr( inMeta->common_meta.surround_coherence_fx[sf][band], Q7 );
    6840       14400 :             move16();
    6841             :         }
    6842             :     }
    6843             : 
    6844         150 :     copy_masa_descriptive_meta_fx( &( outMeta->descriptiveMeta ), &( inMeta->descriptive_meta ) );
    6845             : 
    6846         150 :     accumulate2dArrayToBuffer_fx( tmpBuffer_fx, &outAudio );
    6847             : 
    6848         150 :     return;
    6849             : }
    6850             : 
    6851       18150 : static ivas_error renderInputMasa(
    6852             :     input_masa *masaInput,
    6853             :     const AUDIO_CONFIG outConfig,
    6854             :     IVAS_REND_AudioBuffer outAudio )
    6855             : {
    6856             :     IVAS_REND_AudioBuffer inAudio;
    6857             :     Word16 ch;
    6858             :     Word16 maxBin;
    6859             :     Word32 *tmpBuffer_fx[MAX_OUTPUT_CHANNELS];
    6860             :     Word32 tmpBuffer_buff_fx[MAX_OUTPUT_CHANNELS][L_FRAME48k];
    6861             : 
    6862       18150 :     IF( !masaInput->metadataHasBeenFed )
    6863             :     {
    6864           0 :         return IVAS_ERR_MISSING_METADATA;
    6865             :     }
    6866             : 
    6867       18150 :     inAudio = masaInput->base.inputBuffer;
    6868       18150 :     IF( NE_32( masaInput->base.numNewSamplesPerChannel, outAudio.config.numSamplesPerChannel ) )
    6869             :     {
    6870           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" );
    6871             :     }
    6872       18150 :     masaInput->base.numNewSamplesPerChannel = 0;
    6873       18150 :     move32();
    6874             : 
    6875       18150 :     *outAudio.pq_fact = outAudio.q_factor;
    6876       18150 :     move16();
    6877             :     /* Apply input gain to new audio */
    6878       18150 :     v_multc_fixed( inAudio.data_fx, masaInput->base.gain_fx, inAudio.data_fx, i_mult( inAudio.config.numSamplesPerChannel, inAudio.config.numChannels ) );
    6879       18150 :     *outAudio.pq_fact = sub( *outAudio.pq_fact, 1 ); // to compensate for the qfactor reduction in gain multiplication.
    6880       18150 :     move16();
    6881             : 
    6882       18150 :     maxBin = extract_l( Mpy_32_32( *masaInput->base.ctx.pOutSampleRate, INV_CLDFB_BANDWIDTH_Q31 ) ); /* Q0 */
    6883             : 
    6884             :     /* set combined orientation subframe info to start info */
    6885       18150 :     ivas_combined_orientation_set_to_start_index( *( masaInput->base.ctx.pCombinedOrientationData ) );
    6886             : 
    6887       18150 :     IF( EQ_32( getAudioConfigType( outConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    6888             :     {
    6889             :         /* MASA prerendering path for MASA -> MASA */
    6890         150 :         renderMasaToMasa( masaInput, outAudio );
    6891             :     }
    6892             :     ELSE
    6893             :     {
    6894             :         /* MASA external renderer -> other formats */
    6895             :         Word16 num_subframes, exp;
    6896      306000 :         FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
    6897             :         {
    6898      288000 :             tmpBuffer_fx[ch] = tmpBuffer_buff_fx[ch];
    6899             :         }
    6900       18000 :         copyBufferTo2dArray_fx( masaInput->base.inputBuffer, tmpBuffer_buff_fx );
    6901             : 
    6902       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 );
    6903       18000 :         num_subframes = shr( num_subframes, sub( 15, exp ) ); /* Q0 */
    6904             : 
    6905       18000 :         SWITCH( masaInput->hMasaExtRend->renderer_type )
    6906             :         {
    6907       12750 :             case RENDERER_DIRAC:
    6908             : 
    6909       12750 :                 copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
    6910       12750 :                 intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 1 );
    6911      123000 :                 FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
    6912             :                 {
    6913      110250 :                     masaInput->hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state = Q11;
    6914      110250 :                     move16();
    6915             :                 }
    6916      216750 :                 FOR( ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++ )
    6917             :                 {
    6918      204000 :                     Scale_sig32( tmpBuffer_buff_fx[ch], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    6919             :                 }
    6920             : 
    6921       12750 :                 scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    6922             : 
    6923       12750 :                 ivas_masa_ext_dirac_render_fx( masaInput->hMasaExtRend, tmpBuffer_fx, num_subframes );
    6924             : 
    6925       12750 :                 *outAudio.pq_fact = Q11;
    6926       12750 :                 move16();
    6927             : 
    6928      123000 :                 FOR( ch = 0; ch < masaInput->hMasaExtRend->hDirACRend->hOutSetup.nchan_out_woLFE + masaInput->hMasaExtRend->hDirACRend->hOutSetup.num_lfe; ch++ )
    6929             :                 {
    6930      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 */
    6931      110250 :                     masaInput->hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
    6932      110250 :                     move16();
    6933             :                 }
    6934             : 
    6935       12750 :                 intermidiate_ext_dirac_render( masaInput->hMasaExtRend, 0 );
    6936       12750 :                 BREAK;
    6937        4500 :             case RENDERER_STEREO_PARAMETRIC:
    6938             :             case RENDERER_BINAURAL_PARAMETRIC:
    6939             :             case RENDERER_BINAURAL_PARAMETRIC_ROOM:
    6940             : 
    6941        4500 :                 copyMasaMetadataToDiracRenderer_fx( &masaInput->masaMetadata, masaInput->hMasaExtRend->hSpatParamRendCom, maxBin );
    6942             : 
    6943        4500 :                 Scale_sig32( tmpBuffer_buff_fx[0], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    6944        4500 :                 Scale_sig32( tmpBuffer_buff_fx[1], L_FRAME48k, sub( Q11, *outAudio.pq_fact ) ); /* Q11 */
    6945             : 
    6946        4500 :                 scale_sig32( outAudio.data_fx, i_mult( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ), sub( Q11, *outAudio.pq_fact ) );
    6947             : 
    6948        4500 :                 ivas_masa_ext_rend_parambin_render_fx( masaInput->hMasaExtRend, *masaInput->base.ctx.pCombinedOrientationData, tmpBuffer_fx, num_subframes );
    6949        4500 :                 *outAudio.pq_fact = Q11;
    6950        4500 :                 move16();
    6951        4500 :                 BREAK;
    6952         750 :             case RENDERER_DISABLE:
    6953         750 :                 BREAK; /* This happens for 1TC MASA to MONO where we just copy input transport to output */
    6954           0 :             default:
    6955           0 :                 return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
    6956             :         }
    6957             : 
    6958       18000 :         accumulate2dArrayToBuffer_fx( tmpBuffer_buff_fx, &outAudio );
    6959             :     }
    6960             : 
    6961       18150 :     return IVAS_ERR_OK;
    6962             : }
    6963     1126140 : static ivas_error renderActiveInputsMasa(
    6964             :     IVAS_REND_HANDLE hIvasRend,
    6965             :     IVAS_REND_AudioBuffer outAudio )
    6966             : {
    6967             :     Word16 i;
    6968             :     input_masa *pCurrentInput;
    6969             :     ivas_error error;
    6970             : 
    6971     2252280 :     FOR( ( i = 0, pCurrentInput = hIvasRend->inputsMasa ); i < RENDERER_MAX_MASA_INPUTS; ( ++i, ++pCurrentInput ) )
    6972             :     {
    6973     1126140 :         IF( EQ_16( pCurrentInput->base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    6974             :         {
    6975             :             /* Skip inactive inputs */
    6976     1107990 :             CONTINUE;
    6977             :         }
    6978             : 
    6979       18150 :         *outAudio.pq_fact = Q8;
    6980       18150 :         move16();
    6981             : 
    6982       18150 :         IF( NE_32( ( error = renderInputMasa( pCurrentInput, hIvasRend->outputConfig, outAudio ) ), IVAS_ERR_OK ) )
    6983             :         {
    6984           0 :             return error;
    6985             :         }
    6986             :     }
    6987             : 
    6988     1126140 :     return IVAS_ERR_OK;
    6989             : }
    6990             : 
    6991             : /*---------------------------------------------------------------------*
    6992             :  * IVAS_REND_GetMasaMetadata( )
    6993             :  *
    6994             :  * Get metadata of the estimated MASA frame
    6995             :  *---------------------------------------------------------------------*/
    6996             : 
    6997           0 : ivas_error IVAS_REND_GetMasaMetadata(
    6998             :     IVAS_REND_HANDLE hIvasRend,                        /* i/o: IVAS renderer handle                                                    */
    6999             :     MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o  : pointer to handle, which will be set to point to analyzed MASA metadata */
    7000             :     const IVAS_REND_AudioConfigType inputType          /* i  : Input type                                                              */
    7001             : )
    7002             : {
    7003           0 :     IF( hIvasRend == NULL )
    7004             :     {
    7005           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    7006             :     }
    7007             : 
    7008             :     /* Get the metadata handle */
    7009           0 :     IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
    7010             :     {
    7011           0 :         *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
    7012             :     }
    7013           0 :     ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    7014             :     {
    7015           0 :         *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
    7016             :     }
    7017           0 :     ELSE IF( EQ_32( inputType, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    7018             :     {
    7019           0 :         *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
    7020             :     }
    7021             :     ELSE
    7022             :     {
    7023           0 :         return IVAS_ERR_NOT_SUPPORTED_OPTION;
    7024             :     }
    7025             : 
    7026           0 :     return IVAS_ERR_OK;
    7027             : }
    7028             : 
    7029             : 
    7030             : /*---------------------------------------------------------------------*
    7031             :  * IVAS_REND_MergeMasaMetadata( )
    7032             :  *
    7033             :  * Merge MASA metadata from two formats
    7034             :  *---------------------------------------------------------------------*/
    7035             : 
    7036         450 : ivas_error IVAS_REND_MergeMasaMetadata(
    7037             :     IVAS_REND_HANDLE hIvasRend,                        /* i/o: IVAS renderer handle                                             */
    7038             :     MASA_DECODER_EXT_OUT_META_HANDLE *hMasaExtOutMeta, /* o  : pointer to handle, which will be set to point to merged metadata */
    7039             :     const IVAS_REND_AudioConfigType inputType1,        /* i  : Input type 1                                                     */
    7040             :     const IVAS_REND_AudioConfigType inputType2         /* i  : Input type 2                                                     */
    7041             : )
    7042             : {
    7043             :     MASA_DECODER_EXT_OUT_META_HANDLE inMeta2;
    7044             :     Word32( *inEne1_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    7045             :     Word32( *inEne2_fx )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    7046             :     Word16( *inEne1_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    7047             :     Word16( *inEne2_e )[MAX_PARAM_SPATIAL_SUBFRAMES][MASA_FREQUENCY_BANDS];
    7048             : 
    7049         450 :     IF( hIvasRend == NULL )
    7050             :     {
    7051           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    7052             :     }
    7053             : 
    7054             :     /* Input1 metadata and energy */
    7055         450 :     IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
    7056             :     {
    7057             : 
    7058           0 :         *hMasaExtOutMeta = hIvasRend->inputsIsm->hOMasa->hMasaOut;
    7059           0 :         inEne1_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
    7060           0 :         inEne1_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
    7061             :     }
    7062         450 :     ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    7063             :     {
    7064             : 
    7065           0 :         *hMasaExtOutMeta = hIvasRend->inputsMc->hMcMasa->hMasaOut;
    7066           0 :         inEne1_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
    7067           0 :         inEne1_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
    7068             :     }
    7069         450 :     ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    7070             :     {
    7071             : 
    7072         450 :         *hMasaExtOutMeta = hIvasRend->inputsSba->hDirAC->hMasaOut;
    7073         450 :         inEne1_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
    7074         450 :         inEne1_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
    7075             :     }
    7076           0 :     ELSE IF( EQ_32( inputType1, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    7077             :     {
    7078             : 
    7079           0 :         *hMasaExtOutMeta = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
    7080           0 :         inEne1_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
    7081           0 :         inEne1_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
    7082             :     }
    7083             :     ELSE
    7084             :     {
    7085           0 :         return IVAS_ERR_NOT_SUPPORTED_OPTION;
    7086             :     }
    7087             : 
    7088             :     /* Input2 metadata and energy */
    7089         450 :     IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_OBJECT_BASED ) )
    7090             :     {
    7091         150 :         inMeta2 = hIvasRend->inputsIsm->hOMasa->hMasaOut;
    7092         150 :         inEne2_fx = &( hIvasRend->inputsIsm->hOMasa->energy_fx );
    7093         150 :         inEne2_e = &( hIvasRend->inputsIsm->hOMasa->energy_e );
    7094             :     }
    7095         300 :     ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_CHANNEL_BASED ) )
    7096             :     {
    7097         150 :         inMeta2 = hIvasRend->inputsMc->hMcMasa->hMasaOut;
    7098         150 :         inEne2_fx = &( hIvasRend->inputsMc->hMcMasa->energy_fx );
    7099         150 :         inEne2_e = &( hIvasRend->inputsMc->hMcMasa->energy_e );
    7100             :     }
    7101         150 :     ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_AMBISONICS ) )
    7102             :     {
    7103           0 :         inMeta2 = hIvasRend->inputsSba->hDirAC->hMasaOut;
    7104           0 :         inEne2_fx = &( hIvasRend->inputsSba->hDirAC->energy_fx );
    7105           0 :         inEne2_e = &( hIvasRend->inputsSba->hDirAC->energy_e );
    7106             :     }
    7107         150 :     ELSE IF( EQ_32( inputType2, IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    7108             :     {
    7109             : 
    7110         150 :         inMeta2 = hIvasRend->inputsMasa->hMasaPrerend->hMasaOut;
    7111         150 :         inEne2_fx = &( hIvasRend->inputsMasa->hMasaPrerend->energy_fx );
    7112         150 :         inEne2_e = &( hIvasRend->inputsMasa->hMasaPrerend->energy_e );
    7113             :     }
    7114             :     ELSE
    7115             :     {
    7116           0 :         return IVAS_ERR_NOT_SUPPORTED_OPTION;
    7117             :     }
    7118             : 
    7119             :     /* Merge metadata */
    7120         450 :     ivas_prerend_merge_masa_metadata_fx( *hMasaExtOutMeta, *hMasaExtOutMeta, inputType1, *inEne1_fx, *inEne1_e, inMeta2, inputType2, *inEne2_fx, *inEne2_e );
    7121             : 
    7122             : 
    7123         450 :     IF( EQ_32( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_MASA1 ) )
    7124             :     {
    7125           0 :         ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 0u;
    7126           0 :         move16();
    7127             :     }
    7128             :     ELSE
    7129             :     {
    7130         450 :         ( *hMasaExtOutMeta )->descriptiveMeta.numberOfChannels = 1u;
    7131         450 :         move16();
    7132             :     }
    7133             : 
    7134         450 :     return IVAS_ERR_OK;
    7135             : }
    7136             : 
    7137             : 
    7138             : /*---------------------------------------------------------------------*
    7139             :  * IVAS_REND_SetTotalNumberOfObjects( )
    7140             :  *
    7141             :  * Set the total number of objects to the first object data
    7142             :  *---------------------------------------------------------------------*/
    7143             : 
    7144         182 : ivas_error IVAS_REND_SetTotalNumberOfObjects(
    7145             :     IVAS_REND_HANDLE hIvasRend,     /* i/o: IVAS renderer handle    */
    7146             :     const UWord16 total_num_objects /* i  : total number of objects */
    7147             : )
    7148             : {
    7149         182 :     IF( hIvasRend == NULL )
    7150             :     {
    7151           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    7152             :     }
    7153             : 
    7154         182 :     hIvasRend->inputsIsm[0].total_num_objects = total_num_objects;
    7155         182 :     move16();
    7156             : 
    7157         182 :     return IVAS_ERR_OK;
    7158             : }
    7159             : 
    7160             : 
    7161             : /*---------------------------------------------------------------------*
    7162             :  * IVAS_REND_SetIsmMetadataDelay( )
    7163             :  *
    7164             :  * Set the Metadata Delay in ms in order to sync with audio delay
    7165             :  *---------------------------------------------------------------------*/
    7166         182 : ivas_error IVAS_REND_SetIsmMetadataDelay(
    7167             :     IVAS_REND_HANDLE hIvasRend, /* i/o: IVAS renderer handle    */
    7168             :     const Word32 sync_md_delay  /* i  : ISM Metadata Delay in ms to sync with audio delay   */
    7169             : )
    7170             : {
    7171             :     Word16 i;
    7172             : 
    7173         182 :     IF( hIvasRend == NULL )
    7174             :     {
    7175           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    7176             :     }
    7177         910 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    7178             :     {
    7179         728 :         hIvasRend->inputsIsm[i].ism_metadata_delay_ms_fx = sync_md_delay;
    7180         728 :         move32();
    7181             :     }
    7182             : 
    7183         182 :     return IVAS_ERR_OK;
    7184             : }
    7185             : 
    7186             : /*-------------------------------------------------------------------*
    7187             :  * getSamplesInternal()
    7188             :  *
    7189             :  *
    7190             :  *-------------------------------------------------------------------*/
    7191             : 
    7192     1126140 : static ivas_error getSamplesInternal(
    7193             :     IVAS_REND_HANDLE hIvasRend,    /* i/o: Renderer handle          */
    7194             :     IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio  */
    7195             : )
    7196             : {
    7197             :     ivas_error error;
    7198             :     Word16 numOutChannels;
    7199             :     /* Validate function arguments */
    7200     1126140 :     test();
    7201     1126140 :     IF( hIvasRend == NULL || outAudio.data_fx == NULL )
    7202             :     {
    7203           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    7204             :     }
    7205             : 
    7206     1126140 :     test();
    7207     1126140 :     IF( outAudio.config.numSamplesPerChannel <= 0 || LT_16( MAX_BUFFER_LENGTH_PER_CHANNEL, outAudio.config.numSamplesPerChannel ) )
    7208             :     {
    7209           0 :         return IVAS_ERR_INVALID_BUFFER_SIZE;
    7210             :     }
    7211             : 
    7212     1126140 :     test();
    7213     1126140 :     IF( outAudio.config.numChannels <= 0 || LT_16( MAX_OUTPUT_CHANNELS, outAudio.config.numChannels ) )
    7214             :     {
    7215           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    7216             :     }
    7217             : 
    7218     1126140 :     test();
    7219     1126140 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_BINAURAL ) &&
    7220             :         NE_32( L_mult0( outAudio.config.numSamplesPerChannel, 1000 ), imult3216( hIvasRend->sampleRateOut, i_mult( hIvasRend->num_subframes, BINAURAL_RENDERING_FRAME_SIZE_MS ) ) ) )
    7221             :     {
    7222           0 :         return IVAS_ERROR( IVAS_ERR_INVALID_BUFFER_SIZE, "Binaural rendering requires specific frame size" );
    7223             :     }
    7224             : 
    7225             :     /* Check that there is allowed configuration for MASA format output */
    7226     1126140 :     IF( EQ_32( getAudioConfigType( hIvasRend->outputConfig ), IVAS_REND_AUDIO_CONFIG_TYPE_MASA ) )
    7227             :     {
    7228             :         Word16 i;
    7229         150 :         Word16 numMasaInputs = 0;
    7230         150 :         move16();
    7231         150 :         Word16 numOtherInputs = 0;
    7232         150 :         move16();
    7233             : 
    7234         300 :         FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; i++ )
    7235             :         {
    7236             :             // numMasaInputs += hIvasRend->inputsMasa[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    7237             : 
    7238         150 :             IF( EQ_32( hIvasRend->inputsMasa[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    7239             :             {
    7240           0 :                 numMasaInputs = add( numMasaInputs, 0 );
    7241             :             }
    7242             :             ELSE
    7243             :             {
    7244         150 :                 numMasaInputs = add( numMasaInputs, 1 );
    7245             :             }
    7246             :         }
    7247             : 
    7248         300 :         FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; i++ )
    7249             :         {
    7250             :             // numOtherInputs += hIvasRend->inputsMc[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    7251             : 
    7252         150 :             IF( EQ_32( hIvasRend->inputsMc[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    7253             :             {
    7254           0 :                 numOtherInputs = add( numOtherInputs, 0 );
    7255             :             }
    7256             :             ELSE
    7257             :             {
    7258         150 :                 numOtherInputs = add( numOtherInputs, 1 );
    7259             :             }
    7260             :         }
    7261             : 
    7262         300 :         FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; i++ )
    7263             :         {
    7264             :             // numOtherInputs += hIvasRend->inputsSba[i].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    7265             : 
    7266         150 :             IF( EQ_32( hIvasRend->inputsSba[i].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    7267             :             {
    7268           0 :                 numOtherInputs = add( numOtherInputs, 0 );
    7269             :             }
    7270             :             ELSE
    7271             :             {
    7272         150 :                 numOtherInputs = add( numOtherInputs, 1 );
    7273             :             }
    7274             :         }
    7275             : 
    7276             :         /* For ISM, we check only first as all ISMs are handled together via OMASA when merging to MASA. */
    7277             :         // numOtherInputs += hIvasRend->inputsIsm[0].base.inConfig == IVAS_AUDIO_CONFIG_INVALID ? 0 : 1;
    7278         150 :         IF( EQ_32( hIvasRend->inputsIsm[0].base.inConfig, IVAS_AUDIO_CONFIG_INVALID ) )
    7279             :         {
    7280           0 :             numOtherInputs = add( numOtherInputs, 0 );
    7281             :         }
    7282             :         ELSE
    7283             :         {
    7284         150 :             numOtherInputs = add( numOtherInputs, 1 );
    7285             :         }
    7286             : 
    7287         150 :         test();
    7288         150 :         IF( numMasaInputs == 0 || numOtherInputs == 0 )
    7289             :         {
    7290           0 :             return IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED;
    7291             :         }
    7292             :     }
    7293             : 
    7294     1126140 :     IF( NE_32( ( error = IVAS_REND_NumOutChannels( hIvasRend, &numOutChannels ) ), IVAS_ERR_OK ) )
    7295             :     {
    7296           0 :         return error;
    7297             :     }
    7298             : 
    7299     1126140 :     IF( NE_16( numOutChannels, outAudio.config.numChannels ) )
    7300             :     {
    7301           0 :         return IVAS_ERR_WRONG_NUM_CHANNELS;
    7302             :     }
    7303             : 
    7304             :     /* Clear original output buffer */
    7305     1126140 :     set32_fx( outAudio.data_fx, 0, imult1616( outAudio.config.numChannels, outAudio.config.numSamplesPerChannel ) );
    7306             : 
    7307     1126140 :     IF( NE_32( ( error = renderActiveInputsIsm( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    7308             :     {
    7309           0 :         return error;
    7310             :     }
    7311     1126140 :     IF( NE_32( ( error = renderActiveInputsMc( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    7312             :     {
    7313           0 :         return error;
    7314             :     }
    7315     1126140 :     IF( NE_32( ( error = renderActiveInputsSba( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    7316             :     {
    7317           0 :         return error;
    7318             :     }
    7319     1126140 :     IF( NE_32( ( error = renderActiveInputsMasa( hIvasRend, outAudio ) ), IVAS_ERR_OK ) )
    7320             :     {
    7321           0 :         return error;
    7322             :     }
    7323             : 
    7324     1126140 :     test();
    7325     1126140 :     test();
    7326             : 
    7327     1126140 :     Word32 limiter_thresold = L_lshl( IVAS_LIMITER_THRESHOLD, *outAudio.pq_fact );
    7328     1126140 :     limitRendererOutput_fx( hIvasRend->hLimiter, outAudio.data_fx, outAudio.config.numSamplesPerChannel, limiter_thresold, *outAudio.pq_fact );
    7329             : 
    7330             :     /* update global cominbed orientation start index */
    7331     1126140 :     ivas_combined_orientation_update_start_index( hIvasRend->hCombinedOrientationData, outAudio.config.numSamplesPerChannel );
    7332             : 
    7333     1126140 :     return IVAS_ERR_OK;
    7334             : }
    7335             : 
    7336             : /*-------------------------------------------------------------------*
    7337             :  * IVAS_REND_GetSamples()
    7338             :  *
    7339             :  *
    7340             :  *-------------------------------------------------------------------*/
    7341             : 
    7342     1126140 : ivas_error IVAS_REND_GetSamples(
    7343             :     IVAS_REND_HANDLE hIvasRend,    /* i/o: Renderer handle          */
    7344             :     IVAS_REND_AudioBuffer outAudio /* i/o: buffer for output audio  */
    7345             : )
    7346             : {
    7347             : 
    7348     1126140 :     return getSamplesInternal( hIvasRend, outAudio );
    7349             : }
    7350             : 
    7351             : 
    7352             : /*-------------------------------------------------------------------*
    7353             :  * IVAS_REND_Close()
    7354             :  *
    7355             :  *
    7356             :  *-------------------------------------------------------------------*/
    7357             : 
    7358             : 
    7359         666 : void IVAS_REND_Close(
    7360             :     IVAS_REND_HANDLE *phIvasRend /* i/o: Pointer to renderer handle */
    7361             : )
    7362             : {
    7363             :     UWord16 i;
    7364             :     IVAS_REND_HANDLE hIvasRend;
    7365             : 
    7366             :     /* Validate function arguments */
    7367         666 :     test();
    7368         666 :     IF( phIvasRend == NULL || *phIvasRend == NULL )
    7369             :     {
    7370           0 :         return;
    7371             :     }
    7372         666 :     hIvasRend = *phIvasRend;
    7373             : 
    7374         666 :     IF( hIvasRend->efapOutWrapper.hEfap != NULL )
    7375             :     {
    7376         471 :         efap_free_data_fx( &hIvasRend->efapOutWrapper.hEfap );
    7377             :     }
    7378             : 
    7379             :     /* clear inputs */
    7380        3330 :     FOR( i = 0; i < RENDERER_MAX_ISM_INPUTS; ++i )
    7381             :     {
    7382        2664 :         clearInputIsm( &hIvasRend->inputsIsm[i] );
    7383             :     }
    7384        1332 :     FOR( i = 0; i < RENDERER_MAX_MC_INPUTS; ++i )
    7385             :     {
    7386         666 :         clearInputMc( &hIvasRend->inputsMc[i] );
    7387             :     }
    7388        1332 :     FOR( i = 0; i < RENDERER_MAX_SBA_INPUTS; ++i )
    7389             :     {
    7390         666 :         clearInputSba( &hIvasRend->inputsSba[i] );
    7391             :     }
    7392        1332 :     FOR( i = 0; i < RENDERER_MAX_MASA_INPUTS; ++i )
    7393             :     {
    7394         666 :         clearInputMasa( &hIvasRend->inputsMasa[i] );
    7395             :     }
    7396             : 
    7397             :     /* clear Config. Renderer */
    7398         666 :     ivas_render_config_close( &( hIvasRend->hRendererConfig ) );
    7399             : 
    7400         666 :     ivas_limiter_close_fx( &hIvasRend->hLimiter );
    7401             : 
    7402             : 
    7403         666 :     closeHeadRotation( hIvasRend );
    7404             : 
    7405         666 :     ivas_external_orientation_close_fx( &hIvasRend->hExternalOrientationData );
    7406         666 :     ivas_combined_orientation_close_fx( &hIvasRend->hCombinedOrientationData );
    7407             : 
    7408         666 :     free( hIvasRend );
    7409         666 :     *phIvasRend = NULL;
    7410             : 
    7411         666 :     return;
    7412             : }
    7413             : 
    7414          34 : static ivas_error ivas_masa_ext_rend_dirac_rend_init(
    7415             :     input_masa *inputMasa )
    7416             : {
    7417             :     Word16 nchan_out_woLFE;
    7418             :     Word16 nchan_transport;
    7419             :     UWord16 i, j, k;
    7420             :     Word32 ls_azimuth_fx[MAX_OUTPUT_CHANNELS];   /*Q22*/
    7421             :     Word32 ls_elevation_fx[MAX_OUTPUT_CHANNELS]; /*Q22*/
    7422             :     Word32 output_Fs;
    7423             :     ivas_error error;
    7424             :     DIRAC_REND_HANDLE hDirACRend;
    7425             :     SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
    7426             : 
    7427          34 :     error = IVAS_ERR_OK;
    7428          34 :     move32();
    7429             : 
    7430          34 :     hDirACRend = NULL;
    7431          34 :     output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
    7432          34 :     move32();
    7433             : 
    7434          34 :     hSpatParamRendCom = inputMasa->hMasaExtRend->hSpatParamRendCom;
    7435             : 
    7436             :     /*-----------------------------------------------------------------*
    7437             :      * prepare library opening
    7438             :      *-----------------------------------------------------------------*/
    7439             : 
    7440          34 :     IF( ( hDirACRend = (DIRAC_REND_HANDLE) malloc( sizeof( DIRAC_REND_DATA ) ) ) == NULL )
    7441             :     {
    7442           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC renderer\n" ) );
    7443             :     }
    7444             : 
    7445          34 :     IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    7446             :     {
    7447          18 :         nchan_transport = 2;
    7448          18 :         move16();
    7449             :     }
    7450             :     ELSE
    7451             :     {
    7452          16 :         nchan_transport = 1;
    7453          16 :         move16();
    7454             :     }
    7455             : 
    7456             :     /*-----------------------------------------------------------------*
    7457             :      * output setup: for parametric binaural renderer, use output setup, otherwise internal setup
    7458             :      *-----------------------------------------------------------------*/
    7459             : 
    7460          34 :     ivas_output_init( &hDirACRend->hOutSetup, *inputMasa->base.ctx.pOutConfig );
    7461             : 
    7462          34 :     IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_LS_CUSTOM ) )
    7463             :     {
    7464             :         /* Copy from ivas_ls_custom_setup */
    7465           0 :         hDirACRend->hOutSetup.nchan_out_woLFE = inputMasa->base.ctx.pCustomLsOut->num_spk;
    7466           0 :         move16();
    7467           0 :         hDirACRend->hOutSetup.ls_azimuth_fx = inputMasa->base.ctx.pCustomLsOut->ls_azimuth_fx;
    7468           0 :         hDirACRend->hOutSetup.ls_elevation_fx = inputMasa->base.ctx.pCustomLsOut->ls_elevation_fx;
    7469             : 
    7470           0 :         hDirACRend->hOutSetup.num_lfe = inputMasa->base.ctx.pCustomLsOut->num_lfe;
    7471           0 :         move16();
    7472           0 :         hDirACRend->hOutSetup.index_lfe[0] = inputMasa->base.ctx.pCustomLsOut->lfe_idx[0];
    7473           0 :         move16();
    7474             : 
    7475           0 :         hDirACRend->hOutSetup.is_loudspeaker_setup = TRUE;
    7476           0 :         move16();
    7477           0 :         hDirACRend->hOutSetup.is_planar_setup = (Word8) inputMasa->base.ctx.pCustomLsOut->is_planar_setup;
    7478           0 :         move16();
    7479             :     }
    7480             : 
    7481          34 :     nchan_out_woLFE = hDirACRend->hOutSetup.nchan_out_woLFE;
    7482          34 :     move16();
    7483             : 
    7484          34 :     test();
    7485          34 :     IF( hDirACRend->hOutSetup.ls_azimuth_fx != NULL && hDirACRend->hOutSetup.ls_elevation_fx != NULL )
    7486             :     {
    7487          20 :         Copy32( hDirACRend->hOutSetup.ls_azimuth_fx, ls_azimuth_fx, nchan_out_woLFE );
    7488          20 :         Copy32( hDirACRend->hOutSetup.ls_elevation_fx, ls_elevation_fx, nchan_out_woLFE );
    7489             :     }
    7490             : 
    7491          34 :     IF( EQ_16( hDirACRend->hOutSetup.ambisonics_order, -1 ) )
    7492             :     {
    7493          22 :         hDirACRend->hOutSetup.ambisonics_order = SBA_HOA3_ORDER; /* Order 3 is used by default in DirAC for SHD processing */
    7494          22 :         move16();
    7495          22 :         test();
    7496          22 :         if ( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) || EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_STEREO ) )
    7497             :         {
    7498           2 :             hDirACRend->hOutSetup.ambisonics_order = SBA_FOA_ORDER;
    7499           2 :             move16();
    7500             :         }
    7501             :     }
    7502          12 :     ELSE IF( GE_16( hDirACRend->hOutSetup.ambisonics_order, SBA_FOA_ORDER ) )
    7503             :     {
    7504          12 :         Copy32( ls_azimuth_4d4_fx, ls_azimuth_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
    7505          12 :         Copy32( ls_elevation_4d4_fx, ls_elevation_fx, DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS );
    7506             :     }
    7507             : 
    7508             :     /*-----------------------------------------------------------------*
    7509             :      * set input parameters
    7510             :      *-----------------------------------------------------------------*/
    7511             : 
    7512          34 :     test();
    7513          34 :     IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
    7514             :     {
    7515           2 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_MONO;
    7516           2 :         move32();
    7517           2 :         hDirACRend->panningConf = DIRAC_PANNING_HOA3;
    7518           2 :         move32();
    7519           2 :         nchan_out_woLFE = 1;
    7520           2 :         move16();
    7521             :     }
    7522          32 :     ELSE IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
    7523             :     {
    7524          20 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_LS;
    7525          20 :         hDirACRend->panningConf = DIRAC_PANNING_VBAP;
    7526          20 :         move32();
    7527          20 :         move32();
    7528             :     }
    7529          12 :     ELSE IF( !hDirACRend->hOutSetup.is_loudspeaker_setup && GT_16( nchan_transport, 1 ) )
    7530             :     {
    7531           6 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_PSD_SHD;
    7532           6 :         move32();
    7533           6 :         hDirACRend->panningConf = DIRAC_PANNING_HOA3;
    7534           6 :         move32();
    7535             :     }
    7536             :     ELSE
    7537             :     {
    7538           6 :         hDirACRend->synthesisConf = DIRAC_SYNTHESIS_GAIN_SHD;
    7539           6 :         move32();
    7540           6 :         hDirACRend->panningConf = DIRAC_PANNING_HOA3;
    7541           6 :         move32();
    7542             :     }
    7543             : 
    7544          34 :     IF( ( hDirACRend->frequency_axis_fx = (Word16 *) malloc( hSpatParamRendCom->num_freq_bands * sizeof( Word16 ) ) ) == NULL )
    7545             :     {
    7546           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7547             :     }
    7548          34 :     set16_fx( hDirACRend->frequency_axis_fx, 0, hSpatParamRendCom->num_freq_bands );
    7549          34 :     ivas_dirac_dec_get_frequency_axis_fx( hDirACRend->frequency_axis_fx, output_Fs, hSpatParamRendCom->num_freq_bands );
    7550             : 
    7551             : 
    7552          34 :     test();
    7553          34 :     IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) && EQ_16( nchan_transport, 2 ) )
    7554             :     {
    7555           8 :         IF( ( hDirACRend->masa_stereo_type_detect = (MASA_STEREO_TYPE_DETECT *) malloc( sizeof( MASA_STEREO_TYPE_DETECT ) ) ) == NULL )
    7556             :         {
    7557           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7558             :         }
    7559           8 :         ivas_masa_init_stereotype_detection_fx( hDirACRend->masa_stereo_type_detect );
    7560             :     }
    7561             :     ELSE
    7562             :     {
    7563          26 :         hDirACRend->masa_stereo_type_detect = NULL;
    7564             :     }
    7565             : 
    7566          34 :     hSpatParamRendCom->numIsmDirections = 0;
    7567          34 :     move16();
    7568             : 
    7569             :     /*-----------------------------------------------------------------*
    7570             :      * (re)configure sub-modules
    7571             :      *-----------------------------------------------------------------*/
    7572             : 
    7573             :     /* prototype signal computation */
    7574             :     /* allocate output setup related arrays */
    7575          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
    7576             :     {
    7577             :         /* Directional and diffuses components in output LS format */
    7578          20 :         hDirACRend->num_outputs_diff = nchan_out_woLFE;
    7579          20 :         move16();
    7580          20 :         hDirACRend->num_outputs_dir = nchan_out_woLFE;
    7581          20 :         move16();
    7582             :     }
    7583          14 :     ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    7584             :     {
    7585             :         /* Directional and diffuses components in SHD */
    7586             :         /* Diffuseness components up to 1st order */
    7587           6 :         hDirACRend->num_outputs_diff = imult1616( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ), ( add( s_min( hDirACRend->hOutSetup.ambisonics_order, 1 ), 1 ) ) );
    7588           6 :         hDirACRend->num_outputs_dir = ivas_sba_get_nchan_fx( hDirACRend->hOutSetup.ambisonics_order, 0 );
    7589             :     }
    7590           8 :     ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
    7591             :     {
    7592           6 :         hDirACRend->num_outputs_diff = DIRAC_HOA_RENDERING_NUM_VIRT_DECORR_LS;
    7593           6 :         move16();
    7594           6 :         hDirACRend->num_outputs_dir = nchan_out_woLFE;
    7595           6 :         move16();
    7596             :     }
    7597           2 :     ELSE IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
    7598             :     {
    7599           2 :         hDirACRend->num_outputs_diff = 1; /* There is one output channel in mono */
    7600           2 :         move16();
    7601           2 :         hDirACRend->num_outputs_dir = 2; /* Two channels are pre-rendered for stereo type detection */
    7602           2 :         move16();
    7603             :     }
    7604             :     ELSE
    7605             :     {
    7606           0 :         assert( 0 && "DirAC: not existing synthesis methods!" );
    7607             :     }
    7608             : 
    7609          34 :     IF( ( hDirACRend->proto_index_dir = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
    7610             :     {
    7611           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7612             :     }
    7613             : 
    7614          34 :     IF( ( hDirACRend->proto_index_diff = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_diff ) ) == NULL )
    7615             :     {
    7616           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7617             :     }
    7618             : 
    7619          34 :     set16_fx( hDirACRend->proto_index_dir, 0, hDirACRend->num_outputs_dir );
    7620          34 :     set16_fx( hDirACRend->proto_index_diff, 0, hDirACRend->num_outputs_diff );
    7621             : 
    7622          34 :     hDirACRend->sba_map_tc = sba_map_tc;
    7623             : 
    7624          34 :     IF( EQ_16( nchan_transport, 1 ) )
    7625             :     {
    7626          16 :         hDirACRend->num_protos_ambi = 1;
    7627          16 :         move16();
    7628          16 :         hDirACRend->num_protos_dir = 1;
    7629          16 :         move16();
    7630          16 :         hDirACRend->num_protos_diff = 1;
    7631          16 :         move16();
    7632             :     }
    7633          18 :     ELSE IF( EQ_16( nchan_transport, 2 ) )
    7634             :     {
    7635          18 :         IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    7636             :         {
    7637           0 :             hDirACRend->num_protos_ambi = 2;
    7638           0 :             move16();
    7639           0 :             hDirACRend->num_protos_diff = 1;
    7640           0 :             move16();
    7641           0 :             hDirACRend->num_protos_dir = 2;
    7642           0 :             move16();
    7643           0 :             hDirACRend->proto_index_dir[1] = 1;
    7644           0 :             move16();
    7645             :         }
    7646          18 :         ELSE IF( EQ_16( hDirACRend->hOutSetup.output_config, IVAS_AUDIO_CONFIG_MONO ) )
    7647             :         {
    7648             :             /* Following the foa rendering for code compatibility */
    7649           2 :             hDirACRend->num_protos_ambi = 2;
    7650           2 :             move16();
    7651           2 :             hDirACRend->num_protos_dir = 2;
    7652           2 :             move16();
    7653           2 :             hDirACRend->num_protos_diff = 3;
    7654           2 :             move16();
    7655           2 :             hDirACRend->proto_index_dir[0] = 0;
    7656           2 :             move16();
    7657           2 :             hDirACRend->proto_index_diff[0] = 0;
    7658           2 :             move16();
    7659             :         }
    7660             :         ELSE
    7661             :         {
    7662          16 :             hDirACRend->num_protos_ambi = 2;
    7663          16 :             move16();
    7664          16 :             hDirACRend->num_protos_diff = 3;
    7665          16 :             move16();
    7666             : 
    7667         142 :             FOR( k = 0; k < hDirACRend->num_outputs_diff; k++ )
    7668             :             {
    7669         126 :                 IF( ls_azimuth_fx[k] > 0 )
    7670             :                 {
    7671          58 :                     hDirACRend->proto_index_diff[k] = 1;
    7672             :                 }
    7673          68 :                 ELSE IF( ls_azimuth_fx[k] < 0 )
    7674             :                 {
    7675          58 :                     hDirACRend->proto_index_diff[k] = 2;
    7676             :                 }
    7677             :                 ELSE
    7678             :                 {
    7679          10 :                     hDirACRend->proto_index_diff[k] = 0;
    7680             :                 }
    7681         126 :                 move16();
    7682             :             }
    7683             : 
    7684          16 :             IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
    7685             :             {
    7686          10 :                 hDirACRend->num_protos_dir = 3;
    7687          10 :                 move16();
    7688          10 :                 Copy( hDirACRend->proto_index_diff, hDirACRend->proto_index_dir, nchan_out_woLFE );
    7689             :             }
    7690             :             ELSE
    7691             :             {
    7692           6 :                 hDirACRend->num_protos_dir = 2;
    7693           6 :                 move16();
    7694           6 :                 hDirACRend->proto_index_dir[1] = 1;
    7695           6 :                 move16();
    7696             :             }
    7697             :         }
    7698             :     }
    7699             : 
    7700             :     /* direct/diffuse responses */
    7701             : 
    7702          34 :     IF( ( hDirACRend->diffuse_response_function_fx = (Word16 *) malloc( sizeof( Word16 ) * hDirACRend->num_outputs_dir ) ) == NULL )
    7703             :     {
    7704           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7705             :     }
    7706             : 
    7707          34 :     test();
    7708          34 :     test();
    7709          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 ) )
    7710             :     {
    7711          28 :         initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, nchan_out_woLFE, hDirACRend->hOutSetup.output_config,
    7712          28 :                                  hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
    7713             :     }
    7714             :     ELSE
    7715             :     {
    7716           6 :         initDiffuseResponses_fx( hDirACRend->diffuse_response_function_fx, hDirACRend->num_outputs_dir, IVAS_AUDIO_CONFIG_FOA,
    7717           6 :                                  hDirACRend->hOutSetup, hDirACRend->hOutSetup.ambisonics_order, MASA_FORMAT, &hDirACRend->num_ele_spk_no_diffuse_rendering, IVAS_AUDIO_CONFIG_INVALID );
    7718             :     }
    7719             : 
    7720          34 :     hDirACRend->hoa_encoder_fx = NULL;
    7721          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) )
    7722             :     {
    7723           6 :         IF( ( hDirACRend->hoa_encoder_fx = (Word32 *) malloc( nchan_out_woLFE * hDirACRend->num_outputs_diff * sizeof( Word32 ) ) ) == NULL )
    7724             :         {
    7725           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7726             :         }
    7727             : 
    7728           6 :         set32_fx( hDirACRend->hoa_encoder_fx, 0, imult1616( nchan_out_woLFE, hDirACRend->num_outputs_diff ) );
    7729           6 :         compute_hoa_encoder_mtx_fx( ls_azimuth_fx, ls_elevation_fx, hDirACRend->hoa_encoder_fx, hDirACRend->num_outputs_diff, hDirACRend->hOutSetup.ambisonics_order );
    7730             :     }
    7731             : 
    7732             :     /* VBAP */
    7733          34 :     inputMasa->hMasaExtRend->hVBAPdata = NULL;
    7734             : 
    7735          34 :     IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_VBAP ) )
    7736             :     {
    7737          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 ) )
    7738             :         {
    7739           0 :             return error;
    7740             :         }
    7741             :     }
    7742             : 
    7743             :     /* HOA panning/dec */
    7744          34 :     hDirACRend->hoa_decoder = NULL;
    7745          34 :     IF( EQ_16( hDirACRend->panningConf, DIRAC_PANNING_HOA3 ) )
    7746             :     {
    7747          14 :         IF( hDirACRend->hOutSetup.is_loudspeaker_setup )
    7748             :         {
    7749           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 ) )
    7750             :             {
    7751           0 :                 return error;
    7752             :             }
    7753             : 
    7754           2 :             hDirACRend->hoa_decoder = inputMasa->hMasaExtRend->hoa_dec_mtx;
    7755             :         }
    7756             :     }
    7757             : 
    7758             :     /* decorrelation */
    7759          34 :     hDirACRend->proto_signal_decorr_on = 1;
    7760          34 :     move16();
    7761          34 :     if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_MONO ) )
    7762             :     {
    7763           2 :         hDirACRend->proto_signal_decorr_on = 0;
    7764           2 :         move16();
    7765             :     }
    7766             : 
    7767          34 :     IF( hDirACRend->proto_signal_decorr_on )
    7768             :     {
    7769          32 :         IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDirACRend->h_freq_domain_decorr_ap_params ),
    7770             :                                                             &( hDirACRend->h_freq_domain_decorr_ap_state ),
    7771             :                                                             hSpatParamRendCom->num_freq_bands,
    7772             :                                                             hDirACRend->num_outputs_diff,
    7773             :                                                             hDirACRend->num_protos_diff,
    7774             :                                                             hDirACRend->synthesisConf,
    7775             :                                                             hDirACRend->frequency_axis_fx,
    7776             :                                                             nchan_transport,
    7777             :                                                             output_Fs ) ),
    7778             :                    IVAS_ERR_OK ) )
    7779             :         {
    7780           0 :             return error;
    7781             :         }
    7782             :     }
    7783             : 
    7784             :     /* output synthesis */
    7785          34 :     IF( NE_32( ( ivas_dirac_dec_output_synthesis_open_fx( hSpatParamRendCom, hDirACRend, RENDERER_DIRAC, nchan_transport, output_Fs, 0 ) ), IVAS_ERR_OK ) )
    7786             :     {
    7787           0 :         return error;
    7788             :     }
    7789          34 :     hDirACRend->h_output_synthesis_psd_params.use_onset_filters = hDirACRend->proto_signal_decorr_on;
    7790          34 :     move16();
    7791             : 
    7792          34 :     test();
    7793          34 :     if ( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_SHD ) || EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    7794             :     {
    7795          12 :         hDirACRend->h_output_synthesis_psd_params.use_onset_filters = 0;
    7796          12 :         move16();
    7797             :     }
    7798             : 
    7799             :     /*-----------------------------------------------------------------*
    7800             :      * memory allocation
    7801             :      *-----------------------------------------------------------------*/
    7802             : 
    7803          34 :     IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_GAIN_SHD ) )
    7804             :     {
    7805           6 :         hDirACRend->proto_frame_f_fx = NULL;
    7806             :     }
    7807             :     ELSE
    7808             :     {
    7809          28 :         IF( ( hDirACRend->proto_frame_f_fx = (Word32 *) malloc( sizeof( Word32 ) * shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 ) ) ) == NULL )
    7810             :         {
    7811           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC\n" ) );
    7812             :         }
    7813          28 :         hDirACRend->proto_frame_f_len = shl( imult1616( hDirACRend->num_protos_diff, hSpatParamRendCom->num_freq_bands ), 1 );
    7814          28 :         move16();
    7815             :     }
    7816             : 
    7817             : 
    7818          34 :     hDirACRend->buffer_energy_fx = NULL;
    7819         136 :     FOR( i = 0; i < DIRAC_NUM_DIMS; i++ )
    7820             :     {
    7821        3366 :         FOR( j = 0; j < DIRAC_NO_COL_AVG_DIFF; j++ )
    7822             :         {
    7823        3264 :             hDirACRend->buffer_intensity_real_fx[i][j] = NULL;
    7824             :         }
    7825             :     }
    7826             : 
    7827             :     /* output synthesis */
    7828          34 :     ivas_dirac_dec_output_synthesis_init_fx( hSpatParamRendCom, hDirACRend, nchan_out_woLFE, 0 );
    7829             : 
    7830             :     /* Allocate stack memory */
    7831          34 :     IF( NE_32( ( error = ivas_dirac_alloc_mem_fx( hDirACRend, RENDERER_DIRAC, hSpatParamRendCom->num_freq_bands, &( hDirACRend->stack_mem ), 0 ) ), IVAS_ERR_OK ) )
    7832             :     {
    7833           0 :         return error;
    7834             :     }
    7835             : 
    7836          34 :     inputMasa->hMasaExtRend->hDirACRend = hDirACRend;
    7837             : 
    7838          34 :     return error;
    7839             : }
    7840             : 
    7841             : 
    7842          12 : static ivas_error ivas_masa_ext_rend_parambin_init(
    7843             :     input_masa *inputMasa /* i/o: MASA external renderer structure        */
    7844             : )
    7845             : {
    7846             :     DIRAC_DEC_BIN_HANDLE hDiracDecBin;
    7847             :     HRTFS_PARAMBIN_HANDLE hHrtfParambin;
    7848             :     Word16 nBins;
    7849             :     Word32 output_Fs;
    7850             :     RENDERER_TYPE renderer_type;
    7851             :     Word16 j, k, bin;
    7852             :     Word32 binCenterFreq_fx;
    7853             :     Word16 tmpFloat_fx;
    7854             :     ivas_error error;
    7855             :     Word16 frequency_axis_fx[CLDFB_NO_CHANNELS_MAX];
    7856             :     Word16 tmp;
    7857             :     Word16 tmp_e;
    7858             :     Word16 tmp2;
    7859             : 
    7860          12 :     error = IVAS_ERR_OK;
    7861          12 :     move32();
    7862             : 
    7863          12 :     hHrtfParambin = inputMasa->hMasaExtRend->hHrtfParambin;
    7864             : 
    7865             :     /* Set common variables and defaults */
    7866          12 :     output_Fs = *( inputMasa->base.ctx.pOutSampleRate );
    7867          12 :     move32();
    7868          12 :     nBins = inputMasa->hMasaExtRend->hSpatParamRendCom->num_freq_bands;
    7869          12 :     move16();
    7870          12 :     renderer_type = inputMasa->hMasaExtRend->renderer_type;
    7871          12 :     move32();
    7872             : 
    7873          12 :     hDiracDecBin = inputMasa->hMasaExtRend->hDiracDecBin;
    7874             : 
    7875             :     /* Init assumes that no reconfiguration is required in external renderer. Instead, free and rebuild whole rendering. */
    7876          12 :     IF( ( hDiracDecBin = (DIRAC_DEC_BIN_HANDLE) malloc( sizeof( DIRAC_DEC_BIN_DATA ) ) ) == NULL )
    7877             :     {
    7878           0 :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for DirAC binaural handle " );
    7879             :     }
    7880             : 
    7881          12 :     hDiracDecBin->hTdDecorr = NULL;
    7882          12 :     hDiracDecBin->hReverb = NULL;
    7883          12 :     hDiracDecBin->h_freq_domain_decorr_ap_params = NULL;
    7884          12 :     hDiracDecBin->h_freq_domain_decorr_ap_state = NULL;
    7885          12 :     hDiracDecBin->hDiffuseDist = NULL; /* Not used in external renderer */
    7886          12 :     hDiracDecBin->useTdDecorr = 0;     /* Always use frequency domain decorrelator in external renderer */
    7887          12 :     move16();
    7888             : 
    7889          36 :     FOR( j = 0; j < BINAURAL_CHANNELS; j++ )
    7890             :     {
    7891         168 :         FOR( k = 0; k < BINAURAL_CHANNELS + MAX_NUM_OBJECTS; k++ )
    7892             :         {
    7893         144 :             set16_fx( hDiracDecBin->processMtxRe_fx[j][k], 0, nBins );
    7894         144 :             set16_fx( hDiracDecBin->processMtxIm_fx[j][k], 0, nBins );
    7895             :         }
    7896             : 
    7897          72 :         FOR( k = 0; k < BINAURAL_CHANNELS; k++ )
    7898             :         {
    7899          48 :             set16_fx( hDiracDecBin->processMtxDecRe_fx[j][k], 0, nBins );
    7900          48 :             set16_fx( hDiracDecBin->processMtxDecIm_fx[j][k], 0, nBins );
    7901             :         }
    7902          24 :         hDiracDecBin->q_processMtx = Q15;
    7903          24 :         hDiracDecBin->q_processMtxSCCR = Q15;
    7904          24 :         hDiracDecBin->q_processMtxPrev = Q15;
    7905          24 :         hDiracDecBin->q_processMtxPrevSCCR = Q15;
    7906          24 :         hDiracDecBin->q_processMtxDec = Q15;
    7907          24 :         hDiracDecBin->q_processMtxDecPrev = Q15;
    7908          24 :         move16();
    7909          24 :         move16();
    7910          24 :         move16();
    7911          24 :         move16();
    7912          24 :         move16();
    7913          24 :         move16();
    7914          24 :         set_zero_fx( hDiracDecBin->ChEnePrev_fx[j], nBins );
    7915          24 :         set_zero_fx( hDiracDecBin->ChEneOutPrev_fx[j], nBins );
    7916          24 :         set16_fx( hDiracDecBin->ChEnePrev_e[j], 0, nBins );
    7917          24 :         set16_fx( hDiracDecBin->ChEneOutPrev_e[j], 0, nBins );
    7918             :     }
    7919          12 :     set_zero_fx( hDiracDecBin->ChCrossRePrev_fx, nBins );
    7920          12 :     set_zero_fx( hDiracDecBin->ChCrossImPrev_fx, nBins );
    7921          12 :     set_zero_fx( hDiracDecBin->ChCrossReOutPrev_fx, nBins );
    7922          12 :     set_zero_fx( hDiracDecBin->ChCrossImOutPrev_fx, nBins );
    7923          12 :     set16_fx( hDiracDecBin->ChCrossRePrev_e, 0, nBins );
    7924          12 :     set16_fx( hDiracDecBin->ChCrossImPrev_e, 0, nBins );
    7925          12 :     set16_fx( hDiracDecBin->ChCrossReOutPrev_e, 0, nBins );
    7926          12 :     set16_fx( hDiracDecBin->ChCrossImOutPrev_e, 0, nBins );
    7927          12 :     hDiracDecBin->renderStereoOutputInsteadOfBinaural = 0;
    7928          12 :     move16();
    7929             : 
    7930         732 :     FOR( bin = 0; bin < nBins; bin++ )
    7931             :     {
    7932         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*/
    7933             :         /* These formulas and values are from Christian Borss's publication for binaural diffuse field coherence */
    7934         720 :         tmp = BASOP_Util_Divide3232_Scale( binCenterFreq_fx, L_shl( 2700, Q15 ), &tmp_e );
    7935         720 :         IF( tmp_e < 0 )
    7936             :         {
    7937          36 :             tmp = shl( tmp, tmp_e ); /*q15*/
    7938          36 :             tmp_e = 0;
    7939          36 :             move16();
    7940             :         }
    7941         720 :         tmpFloat_fx = s_max( 0, sub( shl_sat( 1, sub( 15, tmp_e ) ), tmp ) ) /*max( 0.0f, 1.0f - binCenterFreq / 2700.0f )*/;                                                             /*Q30*/
    7942         720 :         tmp2 = extract_l( Mult_32_32( binCenterFreq_fx, 1952258 /*=2^31*180/(550)/360*/ ) % 32767 );                                                                                      //*binCenterFreq_fx * EVS_PI / 550.0f*/
    7943         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 );*/
    7944         720 :         hDiracDecBin->diffuseFieldCoherence_fx[bin] = L_shl( hDiracDecBin->diffuseFieldCoherence_fx[bin], 1 );                                                                            /* Q31 */
    7945         720 :         move32();
    7946         720 :         move32();
    7947             :     }
    7948             : 
    7949             :     /* No SPAR in external renderer so set directive diffuse field coherence tables to zero */
    7950          12 :     set_zero_fx( hDiracDecBin->diffuseFieldCoherenceX_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
    7951          12 :     set_zero_fx( hDiracDecBin->diffuseFieldCoherenceY_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
    7952          12 :     set_zero_fx( hDiracDecBin->diffuseFieldCoherenceZ_fx, BINAURAL_COHERENCE_DIFFERENCE_BINS );
    7953             : 
    7954          12 :     IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC ) ) /* Indication of binaural rendering without room effect */
    7955             :     {
    7956           8 :         set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
    7957           8 :         hDiracDecBin->q_earlyPartEneCorrection = Q28;
    7958           8 :         move16();
    7959           8 :         hDiracDecBin->hReverb = NULL;
    7960             :     }
    7961           4 :     ELSE IF( EQ_16( renderer_type, RENDERER_BINAURAL_PARAMETRIC_ROOM ) ) /* Indication of binaural rendering with room effect */
    7962             :     {
    7963           0 :         Copy32( hHrtfParambin->parametricEarlyPartEneCorrection_fx, hDiracDecBin->earlyPartEneCorrection_fx, nBins );
    7964           0 :         hDiracDecBin->q_earlyPartEneCorrection = Q28;
    7965           0 :         move16();
    7966             : 
    7967           0 :         IF( hDiracDecBin->hReverb == NULL )
    7968             :         {
    7969             :             /* 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. */
    7970           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 ) )
    7971             :             {
    7972           0 :                 return error;
    7973             :             }
    7974             :         }
    7975             :     }
    7976           4 :     ELSE IF( EQ_16( renderer_type, RENDERER_STEREO_PARAMETRIC ) )
    7977             :     {
    7978           4 :         set32_fx( hDiracDecBin->earlyPartEneCorrection_fx, ONE_IN_Q28 /*1.0f Q28*/, CLDFB_NO_CHANNELS_MAX );
    7979           4 :         hDiracDecBin->q_earlyPartEneCorrection = Q28;
    7980           4 :         move16();
    7981           4 :         hDiracDecBin->hReverb = NULL;
    7982           4 :         hDiracDecBin->renderStereoOutputInsteadOfBinaural = 1;
    7983           4 :         move16();
    7984             :     }
    7985             :     ELSE /* Not valid renderer type for this renderer */
    7986             :     {
    7987           0 :         assert( false );
    7988             :     }
    7989             : 
    7990             :     /* Always open frequency domain decorrelator */
    7991          12 :     ivas_dirac_dec_get_frequency_axis_fx( frequency_axis_fx, output_Fs, nBins );
    7992             : 
    7993          12 :     IF( NE_32( ( error = ivas_dirac_dec_decorr_open_fx( &( hDiracDecBin->h_freq_domain_decorr_ap_params ),
    7994             :                                                         &( hDiracDecBin->h_freq_domain_decorr_ap_state ),
    7995             :                                                         nBins,
    7996             :                                                         BINAURAL_CHANNELS,
    7997             :                                                         BINAURAL_CHANNELS,
    7998             :                                                         DIRAC_SYNTHESIS_PSD_LS,
    7999             :                                                         frequency_axis_fx,
    8000             :                                                         BINAURAL_CHANNELS,
    8001             :                                                         output_Fs ) ),
    8002             :                IVAS_ERR_OK ) )
    8003             :     {
    8004           0 :         return error;
    8005             :     }
    8006             :     /* External renderer uses constant regularization factor */
    8007          12 :     hDiracDecBin->reqularizationFactor_fx = 6554; /* 0.4f in Q14 */
    8008          12 :     move16();
    8009             : 
    8010          12 :     inputMasa->hMasaExtRend->hDiracDecBin = hDiracDecBin;
    8011             : 
    8012          12 :     return error;
    8013             : }
    8014             : 
    8015          48 : static ivas_error initMasaExtRenderer(
    8016             :     input_masa *inputMasa,
    8017             :     const AUDIO_CONFIG outConfig )
    8018             : {
    8019             :     Word16 i;
    8020             :     ivas_error error;
    8021             :     MASA_EXT_REND_HANDLE hMasaExtRend;
    8022             : 
    8023          48 :     error = IVAS_ERR_OK;
    8024          48 :     move32();
    8025             : 
    8026          48 :     IF( ( hMasaExtRend = (MASA_EXT_REND_HANDLE) malloc( sizeof( MASA_EXT_REND_DATA ) ) ) == NULL )
    8027             :     {
    8028           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for MASA external renderer structure\n" ) );
    8029             :     }
    8030             : 
    8031          48 :     inputMasa->hMasaExtRend = hMasaExtRend;
    8032             : 
    8033             :     /* Default init */
    8034          48 :     hMasaExtRend->renderer_type = RENDERER_DISABLE;
    8035          48 :     move32();
    8036          48 :     hMasaExtRend->hDirACRend = NULL;
    8037          48 :     hMasaExtRend->hSpatParamRendCom = NULL;
    8038          48 :     hMasaExtRend->hDiracDecBin = NULL;
    8039          48 :     hMasaExtRend->hReverb = NULL;
    8040          48 :     hMasaExtRend->hHrtfParambin = NULL;
    8041          48 :     hMasaExtRend->hVBAPdata = NULL;
    8042          48 :     hMasaExtRend->hoa_dec_mtx = NULL;
    8043             : 
    8044          48 :     IF( NE_32( ( error = getAudioConfigNumChannels( inputMasa->base.inConfig, &hMasaExtRend->nchan_input ) ), IVAS_ERR_OK ) )
    8045             :     {
    8046           0 :         return error;
    8047             :     }
    8048             : 
    8049          48 :     IF( NE_32( ( error = getAudioConfigNumChannels( outConfig, &hMasaExtRend->nchan_output ) ), IVAS_ERR_OK ) )
    8050             :     {
    8051           0 :         return error;
    8052             :     }
    8053             : 
    8054          48 :     SWITCH( outConfig )
    8055             :     {
    8056           4 :         case IVAS_AUDIO_CONFIG_MONO:
    8057           4 :             IF( EQ_16( inputMasa->base.inConfig, IVAS_AUDIO_CONFIG_MASA2 ) )
    8058             :             {
    8059           2 :                 hMasaExtRend->renderer_type = RENDERER_DIRAC;
    8060           2 :                 move32();
    8061             :             }
    8062             :             ELSE
    8063             :             {
    8064             :                 /* 1TC MASA to mono does not need rendering. */
    8065           2 :                 hMasaExtRend->renderer_type = RENDERER_DISABLE;
    8066           2 :                 move32();
    8067             :             }
    8068           4 :             BREAK;
    8069             : 
    8070           4 :         case IVAS_AUDIO_CONFIG_STEREO:
    8071           4 :             hMasaExtRend->renderer_type = RENDERER_STEREO_PARAMETRIC;
    8072           4 :             move32();
    8073           4 :             BREAK;
    8074             : 
    8075          32 :         case IVAS_AUDIO_CONFIG_5_1:
    8076             :         case IVAS_AUDIO_CONFIG_7_1:
    8077             :         case IVAS_AUDIO_CONFIG_5_1_2:
    8078             :         case IVAS_AUDIO_CONFIG_5_1_4:
    8079             :         case IVAS_AUDIO_CONFIG_7_1_4:
    8080             :         case IVAS_AUDIO_CONFIG_LS_CUSTOM:
    8081             :         case IVAS_AUDIO_CONFIG_FOA:
    8082             :         case IVAS_AUDIO_CONFIG_HOA2:
    8083             :         case IVAS_AUDIO_CONFIG_HOA3:
    8084          32 :             hMasaExtRend->renderer_type = RENDERER_DIRAC;
    8085          32 :             move32();
    8086          32 :             BREAK;
    8087             : 
    8088           8 :         case IVAS_AUDIO_CONFIG_BINAURAL:
    8089           8 :             hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC;
    8090           8 :             move32();
    8091           8 :             BREAK;
    8092             : 
    8093           0 :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR:
    8094             :         case IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB:
    8095           0 :             hMasaExtRend->renderer_type = RENDERER_BINAURAL_PARAMETRIC_ROOM;
    8096           0 :             move32();
    8097           0 :             BREAK;
    8098             : 
    8099           0 :         default:
    8100           0 :             return ( IVAS_ERROR( IVAS_ERR_IO_CONFIG_PAIR_NOT_SUPPORTED, "Wrong output config for MASA input in external renderer\n" ) );
    8101             :     }
    8102             : 
    8103          48 :     IF( NE_16( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
    8104             :     {
    8105             :         Word16 subframe;
    8106          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 ) )
    8107             :         {
    8108           0 :             return error;
    8109             :         }
    8110             :         /* Simple population of the metadata index map as no adaptation is present */
    8111          46 :         set16_fx( hMasaExtRend->hSpatParamRendCom->render_to_md_map, 0, MAX_JBM_SUBFRAMES_5MS * JBM_CLDFB_SLOTS_IN_SUBFRAME );
    8112         230 :         FOR( subframe = 0; subframe < MAX_PARAM_SPATIAL_SUBFRAMES; subframe++ )
    8113             :         {
    8114         184 :             hMasaExtRend->hSpatParamRendCom->render_to_md_map[subframe] = subframe;
    8115         184 :             move16();
    8116             :         }
    8117          46 :         hMasaExtRend->hSpatParamRendCom->subframes_rendered = 0;
    8118          46 :         move16();
    8119             :     }
    8120             : 
    8121          48 :     IF( EQ_16( hMasaExtRend->renderer_type, RENDERER_DIRAC ) )
    8122             :     {
    8123          34 :         IF( NE_32( ( error = ivas_masa_ext_rend_dirac_rend_init( inputMasa ) ), IVAS_ERR_OK ) )
    8124             :         {
    8125           0 :             return error;
    8126             :         }
    8127             :     }
    8128             : 
    8129          48 :     test();
    8130          48 :     test();
    8131          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 ) )
    8132             :     {
    8133          12 :         IF( NE_16( hMasaExtRend->renderer_type, RENDERER_STEREO_PARAMETRIC ) )
    8134             :         {
    8135           8 :             IF( NE_32( ( error = ivas_dirac_dec_binaural_copy_hrtfs_fx( &inputMasa->hMasaExtRend->hHrtfParambin ) ), IVAS_ERR_OK ) )
    8136             :             {
    8137           0 :                 return error;
    8138             :             }
    8139             :         }
    8140             : 
    8141          12 :         IF( NE_32( ( error = ivas_masa_ext_rend_parambin_init( inputMasa ) ), IVAS_ERR_OK ) )
    8142             :         {
    8143           0 :             return error;
    8144             :         }
    8145             :     }
    8146             : 
    8147             :     /* Init CLDFB for analysis & synthesis if renderer is used. Otherwise, NULL. */
    8148         144 :     FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
    8149             :     {
    8150          96 :         hMasaExtRend->cldfbAnaRend[i] = NULL;
    8151             :     }
    8152             : 
    8153         816 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    8154             :     {
    8155         768 :         hMasaExtRend->cldfbSynRend[i] = NULL;
    8156             :     }
    8157             : 
    8158          48 :     IF( NE_32( hMasaExtRend->renderer_type, RENDERER_DISABLE ) )
    8159             :     {
    8160         116 :         FOR( i = 0; i < hMasaExtRend->nchan_input; i++ )
    8161             :         {
    8162          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 ) )
    8163             :             {
    8164           0 :                 return error;
    8165             :             }
    8166             :         }
    8167             : 
    8168         364 :         FOR( i = 0; i < hMasaExtRend->nchan_output; i++ )
    8169             :         {
    8170         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 ) )
    8171             :             {
    8172           0 :                 return error;
    8173             :             }
    8174             :         }
    8175             :     }
    8176             : 
    8177          48 :     inputMasa->hMasaExtRend = hMasaExtRend;
    8178             : 
    8179          48 :     return IVAS_ERR_OK;
    8180             : }
    8181             : 
    8182         666 : static void freeMasaExtRenderer(
    8183             :     MASA_EXT_REND_HANDLE *hMasaExtRendOut )
    8184             : {
    8185             :     MASA_EXT_REND_HANDLE hMasaExtRend;
    8186             :     Word16 i;
    8187             : 
    8188         666 :     test();
    8189         666 :     IF( hMasaExtRendOut == NULL || *hMasaExtRendOut == NULL )
    8190             :     {
    8191         618 :         return;
    8192             :     }
    8193             : 
    8194          48 :     hMasaExtRend = *hMasaExtRendOut;
    8195             : 
    8196          48 :     IF( hMasaExtRend->hDirACRend != NULL )
    8197             :     {
    8198          34 :         ivas_dirac_rend_close_fx( &hMasaExtRend->hDirACRend );
    8199             :     }
    8200             : 
    8201          48 :     IF( hMasaExtRend->hSpatParamRendCom != NULL )
    8202             :     {
    8203          46 :         ivas_spat_hSpatParamRendCom_close_fx( &hMasaExtRend->hSpatParamRendCom );
    8204             :     }
    8205             : 
    8206          48 :     IF( hMasaExtRend->hDiracDecBin != NULL )
    8207             :     {
    8208          12 :         ivas_dirac_dec_close_binaural_data( &hMasaExtRend->hDiracDecBin );
    8209             :     }
    8210             : 
    8211          48 :     IF( hMasaExtRend->hReverb != NULL )
    8212             :     {
    8213           0 :         ivas_binaural_reverb_close_fx( &hMasaExtRend->hReverb );
    8214             :     }
    8215             : 
    8216          48 :     IF( hMasaExtRend->hHrtfParambin != NULL )
    8217             :     {
    8218           8 :         ivas_HRTF_parambin_binary_close_fx( &hMasaExtRend->hHrtfParambin );
    8219             :     }
    8220             : 
    8221          48 :     IF( hMasaExtRend->hVBAPdata != NULL )
    8222             :     {
    8223          20 :         vbap_free_data_fx( &hMasaExtRend->hVBAPdata );
    8224             :     }
    8225             : 
    8226          48 :     IF( hMasaExtRend->hoa_dec_mtx != NULL )
    8227             :     {
    8228           2 :         free( hMasaExtRend->hoa_dec_mtx );
    8229             :     }
    8230             : 
    8231         144 :     FOR( i = 0; i < MASA_MAX_TRANSPORT_CHANNELS; i++ )
    8232             :     {
    8233          96 :         IF( hMasaExtRend->cldfbAnaRend[i] != NULL )
    8234             :         {
    8235          70 :             deleteCldfb_ivas_fx( &hMasaExtRend->cldfbAnaRend[i] );
    8236             :         }
    8237             :     }
    8238             : 
    8239         816 :     FOR( i = 0; i < MAX_OUTPUT_CHANNELS; i++ )
    8240             :     {
    8241         768 :         IF( hMasaExtRend->cldfbSynRend[i] != NULL )
    8242             :         {
    8243         318 :             deleteCldfb_ivas_fx( &hMasaExtRend->cldfbSynRend[i] );
    8244             :         }
    8245             :     }
    8246             : 
    8247          48 :     free( hMasaExtRend );
    8248          48 :     *hMasaExtRendOut = NULL;
    8249             : 
    8250          48 :     return;
    8251             : }
    8252             : 
    8253       25500 : static void intermidiate_ext_dirac_render(
    8254             :     MASA_EXT_REND_HANDLE hMasaExtRend, /* i/o: MASA renderer structure             */
    8255             :     Word16 to_fix )
    8256             : {
    8257             :     SPAT_PARAM_REND_COMMON_DATA_HANDLE hSpatParamRendCom;
    8258       25500 :     hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
    8259             :     DIRAC_DEC_STACK_MEM DirAC_mem;
    8260             :     Word16 ch;
    8261             :     DIRAC_REND_HANDLE hDirACRend;
    8262             :     Word16 subframe_idx;
    8263             :     Word16 slot_idx;
    8264             :     Word16 nchan_transport;
    8265             :     Word16 tmp;
    8266             : 
    8267       25500 :     hDirACRend = hMasaExtRend->hDirACRend;
    8268       25500 :     hSpatParamRendCom = hMasaExtRend->hSpatParamRendCom;
    8269       25500 :     nchan_transport = hMasaExtRend->nchan_input;
    8270             :     DIRAC_OUTPUT_SYNTHESIS_STATE *h_dirac_output_synthesis_state;
    8271             : 
    8272       25500 :     h_dirac_output_synthesis_state = &( hDirACRend->h_output_synthesis_psd_state );
    8273             : 
    8274       25500 :     subframe_idx = hSpatParamRendCom->subframes_rendered;
    8275       25500 :     move16();
    8276             : 
    8277       25500 :     DirAC_mem = hDirACRend->stack_mem;
    8278             : 
    8279       25500 :     IF( to_fix )
    8280             :     {
    8281             : #ifdef FIX_867_CLDFB_NRG_SCALE
    8282       12750 :         DirAC_mem.reference_power_smooth_q[0] = DirAC_mem.reference_power_q[0] = Q31;
    8283       12750 :         DirAC_mem.reference_power_smooth_q[1] = DirAC_mem.reference_power_q[1] = Q31;
    8284       12750 :         move16();
    8285       12750 :         move16();
    8286             : #else
    8287             :         DirAC_mem.reference_power_smooth_q = DirAC_mem.reference_power_q = Q31;
    8288             :         move16();
    8289             : #endif
    8290       12750 :         move16();
    8291       43486 :         FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
    8292             :         {
    8293       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 */
    8294       30736 :             hDirACRend->h_output_synthesis_psd_state.direct_responses_q = Q30;
    8295       30736 :             move16();
    8296             :         }
    8297             : 
    8298       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_fx )
    8299             :         {
    8300       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 );
    8301       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) */
    8302       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 );
    8303       12750 :             move16();
    8304             :         }
    8305       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_cross_dir_smooth_prev_fx )
    8306             :         {
    8307       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 );
    8308       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) */
    8309       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 );
    8310       12750 :             move16();
    8311             :         }
    8312             : 
    8313       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_fx )
    8314             :         {
    8315       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 ) );
    8316       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) */
    8317       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 );
    8318       10500 :             move16();
    8319             :         }
    8320             : 
    8321       12750 :         Word16 num_channels_dir = hDirACRend->num_outputs_dir;
    8322       12750 :         move16();
    8323             : 
    8324       12750 :         IF( EQ_16( hDirACRend->synthesisConf, DIRAC_SYNTHESIS_PSD_LS ) )
    8325             :         {
    8326        7500 :             num_channels_dir = hDirACRend->hOutSetup.nchan_out_woLFE;
    8327        7500 :             move16();
    8328             :         }
    8329             : 
    8330       12750 :         IF( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx )
    8331             :         {
    8332       12750 :             tmp = L_norm_arr( h_dirac_output_synthesis_state->cy_auto_diff_smooth_fx, imult1616( num_channels_dir, hSpatParamRendCom->num_freq_bands ) );
    8333       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) */
    8334       12750 :             h_dirac_output_synthesis_state->q_cy_auto_diff_smooth = add( h_dirac_output_synthesis_state->q_cy_auto_diff_smooth, tmp );
    8335       12750 :             move16();
    8336             :         }
    8337             : 
    8338       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_diff_smooth_prev_fx )
    8339             :         {
    8340       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 );
    8341       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) */
    8342       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 );
    8343       12750 :             move16();
    8344             :         }
    8345             : 
    8346       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 */
    8347       12750 :         hDirACRend->h_output_synthesis_psd_state.gains_dir_prev_q = Q26;
    8348       12750 :         move16();
    8349       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 */
    8350       12750 :         hDirACRend->h_output_synthesis_psd_state.gains_diff_prev_q = Q26;
    8351       12750 :         move16();
    8352       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.cy_auto_dir_smooth_prev_fx )
    8353             :         {
    8354       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 ) );
    8355       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) */
    8356       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 );
    8357       10500 :             move16();
    8358             :         }
    8359             : 
    8360       12750 :         IF( EQ_16( hDirACRend->proto_signal_decorr_on, 1 ) )
    8361             :         {
    8362       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 );
    8363       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) */
    8364       12000 :             hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer = add( hDirACRend->h_freq_domain_decorr_ap_state->q_decorr_buffer, tmp );
    8365       12000 :             move16();
    8366             :         }
    8367             : 
    8368       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_len > 0 )
    8369             :         {
    8370             :             Word16 shift, norm1, norm2;
    8371             :             Word32 tmp1, tmp2;
    8372       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 );
    8373       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 );
    8374             : 
    8375       12000 :             IF( tmp1 == 0 )
    8376             :             {
    8377          32 :                 norm1 = 31;
    8378          32 :                 move16();
    8379             :             }
    8380             :             ELSE
    8381             :             {
    8382       11968 :                 norm1 = norm_l( tmp1 );
    8383             :             }
    8384             : 
    8385       12000 :             IF( tmp2 == 0 )
    8386             :             {
    8387          32 :                 norm2 = 31;
    8388          32 :                 move16();
    8389             :             }
    8390             :             ELSE
    8391             :             {
    8392       11968 :                 norm2 = norm_l( tmp2 );
    8393             :             }
    8394             : 
    8395       12000 :             shift = s_min( norm1, norm2 );
    8396             : 
    8397       12000 :             Word16 hr_exp = sub( 31, shift );
    8398             : 
    8399       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) */
    8400       12000 :             hDirACRend->h_output_synthesis_psd_state.proto_diffuse_buffer_f_q = sub( 31, hr_exp );
    8401       12000 :             move16();
    8402             :         }
    8403             : 
    8404       43486 :         FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[subframe_idx]; slot_idx++ )
    8405             :         {
    8406             :             /* CLDFB Analysis*/
    8407       77744 :             FOR( ch = 0; ch < nchan_transport; ch++ )
    8408             :             {
    8409       47008 :                 hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
    8410       47008 :                 move16();
    8411             :             }
    8412             :         }
    8413       12750 :         hDirACRend->proto_frame_dec_f_q = sub( 31, hDirACRend->proto_frame_dec_f_q );
    8414       12750 :         move16();
    8415             : 
    8416       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx )
    8417             :         {
    8418             : #ifdef FIX_867_CLDFB_NRG_SCALE
    8419       10500 :             tmp = 0;
    8420       10500 :             move16();
    8421       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 ) )
    8422             :             {
    8423       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 ) ) );
    8424             :             }
    8425       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 ) )
    8426             :             {
    8427       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) */
    8428             :             }
    8429       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 );
    8430       10500 :             move16();
    8431       10500 :             tmp = 0;
    8432       10500 :             move16();
    8433       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 ) )
    8434             :             {
    8435       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 ) ) ) );
    8436             :             }
    8437       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 ) )
    8438             :             {
    8439       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) */
    8440             :             }
    8441       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 );
    8442       10500 :             move16();
    8443             : #else
    8444             :             tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_fx, imult1616( hDirACRend->num_protos_dir, hSpatParamRendCom->num_freq_bands ) );
    8445             :             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) */
    8446             :             hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q = add( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_q, tmp );
    8447             :             move16();
    8448             : #endif
    8449             : #ifdef FIX_867_CLDFB_NRG_SCALE
    8450       10500 :             tmp = 0;
    8451       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 ) )
    8452             :             {
    8453       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 ) ) );
    8454             :             }
    8455       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 ) )
    8456             :             {
    8457       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) */
    8458             :             }
    8459       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] );
    8460       10500 :             move16();
    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 :                 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 ) ) ) );
    8464             :             }
    8465       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 ) )
    8466             :             {
    8467       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) */
    8468             :             }
    8469       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] );
    8470       10500 :             move16();
    8471             : #else
    8472             :             tmp = L_norm_arr( hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_fx, imult1616( hDirACRend->num_protos_dir, hSpatParamRendCom->num_freq_bands ) );
    8473             :             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) */
    8474             :             hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q = add( tmp, hDirACRend->h_output_synthesis_psd_state.proto_power_smooth_prev_q );
    8475             :             move16();
    8476             : #endif
    8477             :         }
    8478       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_fx != NULL )
    8479             :         {
    8480             : 
    8481       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 );
    8482       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) */
    8483       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 );
    8484       10500 :             move16();
    8485             :         }
    8486             : 
    8487       12750 :         IF( hDirACRend->h_output_synthesis_psd_state.proto_power_diff_smooth_prev_fx != NULL )
    8488             :         {
    8489        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 );
    8490        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) */
    8491        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 );
    8492        9750 :             move16();
    8493             :         }
    8494             :     }
    8495             :     ELSE
    8496             :     {
    8497       43350 :         FOR( slot_idx = 0; slot_idx < hSpatParamRendCom->subframe_nbslots[hSpatParamRendCom->subframes_rendered]; slot_idx++ )
    8498             :         {
    8499             :             /* CLDFB Analysis*/
    8500       77400 :             FOR( ch = 0; ch < nchan_transport; ch++ )
    8501             :             {
    8502       46800 :                 scale_sig32( hMasaExtRend->cldfbAnaRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbAnaRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbAnaRend[0]->Q_cldfb_state ) ); /* Q11 */
    8503       46800 :                 hMasaExtRend->cldfbAnaRend[ch]->Q_cldfb_state = Q11;
    8504       46800 :                 move16();
    8505             :             }
    8506             :         }
    8507             : 
    8508      123000 :         FOR( ch = 0; ch < hDirACRend->hOutSetup.nchan_out_woLFE + hDirACRend->hOutSetup.num_lfe; ch++ )
    8509             :         {
    8510      110250 :             scale_sig32( hMasaExtRend->cldfbSynRend[ch]->cldfb_state_fx, hMasaExtRend->cldfbSynRend[ch]->cldfb_size, sub( Q11, hMasaExtRend->cldfbSynRend[0]->Q_cldfb_state ) ); /* Q11 */
    8511      110250 :             hMasaExtRend->cldfbSynRend[ch]->Q_cldfb_state = Q11;
    8512      110250 :             move16();
    8513             :         }
    8514             :     }
    8515       25500 : }
    8516             : 
    8517         666 : static ivas_error printConfigInfo_rend(
    8518             :     IVAS_REND_HANDLE hIvasRend /* i  : IVAS renderer handle     */
    8519             : )
    8520             : {
    8521             :     ivas_error error;
    8522             :     Word8 config_str[50];
    8523             : 
    8524             :     /*-----------------------------------------------------------------*
    8525             :      * Print output audio configuration
    8526             :      *-----------------------------------------------------------------*/
    8527             : 
    8528         666 :     IF( NE_32( ( error = get_channel_config( hIvasRend->outputConfig, &config_str[0] ) ), IVAS_ERR_OK ) )
    8529             :     {
    8530           0 :         return error;
    8531             :     }
    8532             : 
    8533         666 :     fprintf( stdout, "Output configuration:   %s\n", config_str );
    8534             : 
    8535             :     /*-----------------------------------------------------------------*
    8536             :      * Print renderer configurations
    8537             :      *-----------------------------------------------------------------*/
    8538             : 
    8539         666 :     fprintf( stdout, "Output sampling rate:   %d Hz\n", hIvasRend->sampleRateOut );
    8540             : 
    8541         666 :     if ( hIvasRend->headRotData.headRotEnabled )
    8542             :     {
    8543         666 :         fprintf( stdout, "Head-tracking:          ON\n" );
    8544             :     }
    8545             : 
    8546         666 :     IF( EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL ) ||
    8547             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_IR ) ||
    8548             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_ROOM_REVERB ) ||
    8549             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_CODED ) ||
    8550             :         EQ_16( hIvasRend->outputConfig, IVAS_AUDIO_CONFIG_BINAURAL_SPLIT_PCM ) )
    8551             :     {
    8552         188 :         fprintf( stdout, "Render framesize:       %dms\n", mult( hIvasRend->num_subframes, 5 ) );
    8553             :     }
    8554             : 
    8555         666 :     return IVAS_ERR_OK;
    8556             : }
    8557             : 
    8558             : 
    8559             : /*---------------------------------------------------------------------*
    8560             :  * IVAS_REND_PrintInputConfig()
    8561             :  *
    8562             :  *
    8563             :  *---------------------------------------------------------------------*/
    8564             : 
    8565         729 : void IVAS_REND_PrintInputConfig(
    8566             :     const IVAS_AUDIO_CONFIG inputConfig /* i  : input audio configuration    */
    8567             : )
    8568             : {
    8569             :     Word8 config_str[50];
    8570             : 
    8571         729 :     get_channel_config( inputConfig, &config_str[0] );
    8572         729 :     fprintf( stdout, "Input configuration:    %s\n", config_str );
    8573             : 
    8574         729 :     return;
    8575             : }
    8576             : 
    8577             : 
    8578             : /*---------------------------------------------------------------------*
    8579             :  * IVAS_REND_PrintConfig()
    8580             :  *
    8581             :  *
    8582             :  *---------------------------------------------------------------------*/
    8583             : 
    8584         666 : ivas_error IVAS_REND_PrintConfig(
    8585             :     IVAS_REND_HANDLE hIvasRend /* i  : IVAS renderer handle    */
    8586             : )
    8587             : {
    8588         666 :     if ( hIvasRend == NULL )
    8589             :     {
    8590           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    8591             :     }
    8592             : 
    8593         666 :     return printConfigInfo_rend( hIvasRend );
    8594             : }
    8595             : 
    8596             : 
    8597             : /*---------------------------------------------------------------------*
    8598             :  * IVAS_REND_PrintDisclaimer()
    8599             :  *
    8600             :  * Print IVAS disclaimer to console
    8601             :  *---------------------------------------------------------------------*/
    8602             : 
    8603         666 : void IVAS_REND_PrintDisclaimer( void )
    8604             : {
    8605         666 :     print_disclaimer( stderr );
    8606             : 
    8607         666 :     return;
    8608             : }

Generated by: LCOV version 1.14