LCOV - code coverage report
Current view: top level - lib_rend - ivas_efap_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 957 1017 94.1 %
Date: 2025-05-03 01:55:50 Functions: 33 34 97.1 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : #include <stdint.h>
      34             : #include <math.h>
      35             : #include <assert.h>
      36             : #include <stdio.h>
      37             : #include "options.h"
      38             : #include "prot_fx.h"
      39             : #include "ivas_prot_rend_fx.h"
      40             : #include "ivas_stat_dec.h"
      41             : #include "wmc_auto.h"
      42             : #include "ivas_prot_fx.h"
      43             : 
      44             : /*-----------------------------------------------------------------------*
      45             :  * Local constants
      46             :  *-----------------------------------------------------------------------*/
      47             : 
      48             : #define EFAP_MAX_SIZE_TMP_BUFF 30
      49             : #define EFAP_MAX_GHOST_LS      5       /* Maximum number of ghost Loudspeakers, for memory allocation purpose */
      50             : #define POLY_THRESH_Q29        53687LL // Q29
      51             : #define POLY_THRESH_Q28        26843   // Q28
      52             : #define Q22_1                  4194304
      53             : #define Q22_45_DEG             188743680
      54             : #define Q22_90_DEG             377487360
      55             : #define Q22_180_DEG            754974720
      56             : #define Q22_360_DEG            1509949440
      57             : #define Q22_120_DEG            503316480
      58             : #define Q22_240_DEG            1006632960
      59             : 
      60             : /*-----------------------------------------------------------------------*
      61             :  * Local function prototypes
      62             :  *-----------------------------------------------------------------------*/
      63             : 
      64             : 
      65             : static ivas_error poly_init_fx( EFAP *efap, const Word16 efip_flag );
      66             : static ivas_error sphere_triangulation_fx( const Word16 numSpk, EFAP_VERTEX_DATA *vtxData, EFAP_POLYSET_DATA *polyData, Word32 ***dmTranspose /*q31*/, Word16 *numTot, const Word16 efip_flag );
      67             : static void initial_polyeder_fx( EFAP_VERTEX_DATA *vtxData, EFAP_LS_TRIANGLE *triArray, Word16 *numTri, Word16 *vtxInHull );
      68             : static void add_ghost_speakers_fx( EFAP_VERTEX *vertexArray, Word16 *numVtx, const Word16 efip_flag );
      69             : static void add_vertex_to_convex_hull_fx( const EFAP_VERTEX_DATA *vtxData, const Word16 vtxIdx, Word16 *vtxInHull, EFAP_LS_TRIANGLE *triArray, Word16 *szTri );
      70             : static void sort_vertices_fx( const EFAP_VERTEX *vertexArray, const Word16 *numVtx, Word16 *order );
      71             : static void visible_edges_fx( const EFAP_LS_TRIANGLE *triArray, const Word16 *visible, const Word16 numSurface, Word16 *numEdges, Word16 *edges );
      72             : 
      73             : 
      74             : static void flip_plane_fx( const EFAP_VERTEX *vtxArray, Word16 *surface, const Word32 centroid[3] /*q31*/ );
      75             : static void remap_ghosts_fx( EFAP_VERTEX *vtxArray, EFAP_LS_TRIANGLE *triArray, Word16 numSpk, Word16 *numVertex, Word16 numTri, Word32 **downmixMatrix /*q31*/ );
      76             : static void vertex_init_fx( const Word32 *aziSpk /*q22*/, const Word32 *eleSpk /*q22*/, EFAP_VERTEX_DATA *efapVtxData );
      77             : static void efap_panning_fx( const Word32 azi /*q22*/, const Word32 ele /*q22*/, const EFAP_POLYSET_DATA *polyData, Word32 *bufferL /*q31*/ );
      78             : static void get_poly_gains_fx( const Word32 azi /*q22*/, const Word32 ele /*q22*/, const Word32 aziPoly[EFAP_MAX_CHAN_NUM] /*q22*/, const Word32 elePoly[EFAP_MAX_CHAN_NUM] /*q22*/, const Word16 numChan, Word32 *buffer /*q31*/ );
      79             : static Word32 get_tri_gain_fx( const Word32 A[2] /*q22*/, const Word32 B[2] /*q22*/, const Word32 C[2] /*q22*/, const Word32 P_minus_A[2] /*q22*/ );
      80             : 
      81             : /*-----------------------------------------------------------------------*
      82             :  * EFAP Utils
      83             :  *-----------------------------------------------------------------------*/
      84             : 
      85             : static void add_vertex_fx( EFAP_VERTEX *vtxArray, const Word32 azi /*q22*/, const Word32 ele /*q22*/, const Word16 pos, const EFAP_VTX_DMX_TYPE );
      86             : static void efap_sort_s_fx( Word16 *x, Word16 *idx, const Word16 len );
      87             : 
      88             : 
      89             : static Word32 vertex_distance_fx( const EFAP_VERTEX *vtxArray, const EFAP_LS_TRIANGLE tri, const Word16 vtxIdx );
      90             : static Word32 point_plane_distance_fx( const Word32 P1[3] /*q31*/, const Word32 P2[3] /*q31*/, const Word32 P3[3] /*q31*/, const Word32 X[3] /*q31*/ );
      91             : static Word32 point_poly_distance_fx( const EFAP_POLYSET poly, const Word32 X[3] /*q31*/ );
      92             : static void efap_crossp_fx( const Word32 *v1 /*q30*/, const Word32 *v2 /*q30*/, Word32 *v /*q29*/ );
      93             : static Word16 find_int_in_tri_fx( const EFAP_LS_TRIANGLE *tri, const Word16 n, const Word16 r, Word16 *pos );
      94             : static void remove_vertex_fx( EFAP_VERTEX *vtxArray, const Word16 idx, const Word16 L );
      95             : static Word16 get_neighbours_fx( const EFAP_LS_TRIANGLE *triArray, const Word16 vtxIdx, const Word16 numTri, Word16 *neighbours );
      96             : 
      97             : static void matrix_times_row_fx( Word32 mat[EFAP_MAX_SIZE_TMP_BUFF][EFAP_MAX_SIZE_TMP_BUFF] /*q31*/, const Word32 *vec /*q31*/, const Word16 L, Word32 *out /*q31*/ );
      98             : static void tri_to_poly_fx( const EFAP_VERTEX *vtxArray, const EFAP_LS_TRIANGLE *triArray, const Word16 numVtx, const Word16 numTri, Word16 sortedChan[EFAP_MAX_POLY_SET][EFAP_MAX_CHAN_NUM], Word16 *outLengthPS, Word16 outLengthSorted[EFAP_MAX_POLY_SET] );
      99             : static Word16 compare_poly_fx( Word16 *old, Word16 lenOld, Word16 *new, Word16 lenNew );
     100             : 
     101             : static void sort_channels_vertex_fx( const EFAP_VERTEX *vtxArray, const EFAP_LS_TRIANGLE *triArray, Word16 channels[EFAP_MAX_CHAN_NUM], const Word16 lengthChannels, Word16 idxTri );
     102             : static Word32 efap_32mod32( const Word32 x /*q22*/, const Word32 y /*q22*/ );
     103             : static Word16 get_poly_num_fx( const Word32 P[2] /*q22*/, const EFAP_POLYSET_DATA *polyData );
     104             : static Word16 in_poly_fx( const Word32 P[2] /*q22*/, const EFAP_POLYSET poly );
     105             : static Word16 in_tri_fx( Word32 A[2] /*q22*/, Word32 B[2] /*q22*/, Word32 C[2] /*q22*/, Word32 P_minus_A[2] /*q22*/ );
     106             : static void sph2cart_fx( const Word32 azi /*q22*/, const Word32 ele /*q22*/, Word32 *pos /*q31*/ );
     107             : 
     108             : /*-----------------------------------------------------------------------*
     109             :  * Global function definitions
     110             :  *-----------------------------------------------------------------------*/
     111             : 
     112             : /*-------------------------------------------------------------------------*
     113             :  * efap_init_data_fx()
     114             :  *
     115             :  * Wrap the internal functions to initialize the EFAP data structure
     116             :  *-------------------------------------------------------------------------*/
     117             : 
     118         900 : ivas_error efap_init_data_fx(
     119             :     EFAP_HANDLE *hEFAPdata,             /* i/o: handle for EFAP data structure that will be initialized */
     120             :     const Word32 *speaker_node_azi_deg, /* i  : vector of speaker node azimuths (positive left) Q22     */
     121             :     const Word32 *speaker_node_ele_deg, /* i  : vector of speaker node elevations (positive up) Q22     */
     122             :     const Word16 num_speaker_nodes,     /* i  : number of speaker nodes in the set                      */
     123             :     const Word16 efap_mode              /* i  : indicates whether EFAP or EFIP is used                  */
     124             : )
     125             : {
     126             :     /* Handle instance declaration  */
     127             :     EFAP *efap;
     128             :     ivas_error error;
     129             : 
     130         900 :     error = IVAS_ERR_OK;
     131         900 :     move32();
     132             : 
     133             :     /* Basic init checks */
     134         900 :     test();
     135         900 :     IF( !speaker_node_azi_deg || !speaker_node_ele_deg )
     136             :     {
     137           0 :         hEFAPdata = NULL;
     138           0 :         return IVAS_ERROR( IVAS_ERR_WRONG_PARAMS, "EFAP requires arrays of speaker azimuths and elevations" );
     139             :     }
     140             : 
     141             :     /*-----------------------------------------------------------------*
     142             :      * Allocate memory
     143             :      *-----------------------------------------------------------------*/
     144             : 
     145             :     /* Memory Allocations for efap */
     146         900 :     IF( ( efap = (EFAP *) malloc( sizeof( EFAP ) ) ) == NULL )
     147             :     {
     148           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP handle\n" ) );
     149             :     }
     150             : 
     151             :     /* Memory Allocation and update for aziSpk & eleSpk arrays*/
     152         900 :     IF( ( efap->aziSpk = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL )
     153             :     {
     154           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP speaker azimuths\n" ) );
     155             :     }
     156         900 :     IF( ( efap->eleSpk = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL )
     157             :     {
     158           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP speaker elevations\n" ) );
     159             :     }
     160             : 
     161             :     /* Memory Allocation for vertexArray */
     162         900 :     IF( ( efap->vtxData.vertexArray = (EFAP_VERTEX *) malloc( ( num_speaker_nodes + EFAP_MAX_GHOST_LS ) * sizeof( EFAP_VERTEX ) ) ) == NULL )
     163             :     {
     164           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP Vertex Array\n" ) );
     165             :     }
     166             : 
     167             :     /* Memory allocation for the tmp buffer short */
     168         900 :     IF( ( efap->bufferShort_fx = (Word32 *) malloc( num_speaker_nodes * sizeof( Word32 ) ) ) == NULL )
     169             :     {
     170           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP bufferS\n" ) );
     171             :     }
     172             : 
     173             :     /*-----------------------------------------------------------------*
     174             :      * Initialize values
     175             :      *-----------------------------------------------------------------*/
     176             : 
     177         900 :     efap->numSpk = num_speaker_nodes;
     178         900 :     move16();
     179             : 
     180             :     /* The number of vertex is first set to the number of LS but will evolve further */
     181         900 :     efap->vtxData.numVtx = num_speaker_nodes;
     182         900 :     move16();
     183             : 
     184             :     /* Loudspeaker configuration */
     185         900 :     Copy32( speaker_node_azi_deg, efap->aziSpk, num_speaker_nodes ); // Q22
     186         900 :     Copy32( speaker_node_ele_deg, efap->eleSpk, num_speaker_nodes ); // Q22
     187             : 
     188             :     /* Initialization of the vertex */
     189         900 :     vertex_init_fx( efap->aziSpk, efap->eleSpk, &efap->vtxData );
     190             : 
     191             :     /* Initialization of polygons and ghost LS */
     192         900 :     IF( ( error = poly_init_fx( efap, efap_mode ) ) != IVAS_ERR_OK )
     193             :     {
     194           0 :         return error;
     195             :     }
     196             : 
     197             :     /* Memory allocation for the tmp buffer long */
     198         900 :     IF( ( efap->bufferLong_fx = (Word32 *) malloc( efap->vtxData.numVtx * sizeof( Word32 ) ) ) == NULL )
     199             :     {
     200           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP bufferL\n" ) );
     201             :     }
     202             : 
     203         900 :     *hEFAPdata = efap;
     204         900 :     return error;
     205             : }
     206             : 
     207             : /*-------------------------------------------------------------------------*
     208             :  * efap_determine_gains_fx()
     209             :  *
     210             :  * Obtain amplitude panning gains for all speaker nodes based on the
     211             :  * given direction
     212             :  *-------------------------------------------------------------------------*/
     213             : 
     214      762315 : void efap_determine_gains_fx(
     215             :     EFAP_HANDLE hEFAPdata, /* i  : EFAP structure                                               */
     216             :     Word32 *gains,         /* o  : gain vector for speaker nodes for given direction Q30        */
     217             :     const Word32 azi_deg,  /* i  : azimuth in degrees for panning direction (positive left) Q22 */
     218             :     const Word32 ele_deg,  /* i  : elevation in degrees for panning direction (positive up) Q22 */
     219             :     const Word16 efap_mode /* i  : indicates whether EFAP or EFIP is used                       */
     220             : )
     221             : {
     222             :     Word16 i, j;
     223             :     Word32 azi_wrap_int, ele_wrap_int;
     224             :     Word32 normBuffer;
     225             : 
     226             :     /* Resetting bufferShort and bufferLong */
     227      762315 :     set32_fx( hEFAPdata->bufferShort_fx, 0, hEFAPdata->numSpk );
     228      762315 :     set32_fx( hEFAPdata->bufferLong_fx, 0, hEFAPdata->vtxData.numVtx );
     229             : 
     230             :     /* Wrap angles to correct range */
     231      762315 :     panning_wrap_angles_fx( azi_deg, ele_deg, &azi_wrap_int, &ele_wrap_int ); // ouputs in q22
     232             : 
     233             :     /* Panning */
     234      762315 :     efap_panning_fx( azi_wrap_int, ele_wrap_int, &hEFAPdata->polyData, hEFAPdata->bufferLong_fx ); // hEFAPdata->bufferLong_fx q31
     235             : 
     236      762315 :     IF( efap_mode == EFAP_MODE_EFAP )
     237             :     {
     238      755665 :         normBuffer = 0;
     239      755665 :         move32();
     240     6878896 :         FOR( j = 0; j < hEFAPdata->numSpk; ++j )
     241             :         {
     242     6123231 :             hEFAPdata->bufferShort_fx[j] = 0;
     243     6123231 :             move32();
     244             :             /* Multiplying by the downmixMatrix */
     245    75058390 :             FOR( i = 0; i < hEFAPdata->vtxData.numVtx; ++i )
     246             :             {
     247    68935159 :                 hEFAPdata->bufferShort_fx[j] = L_add_sat( hEFAPdata->bufferShort_fx[j], L_shr( Mpy_32_32( hEFAPdata->bufferLong_fx[i], hEFAPdata->dmTranspose_fx[i][j] ), Q1 ) ); /* Q30 */
     248    68935159 :                 move32();
     249             :             }
     250     6123231 :             normBuffer = L_add_sat( normBuffer, Mpy_32_32( hEFAPdata->bufferShort_fx[j], hEFAPdata->bufferShort_fx[j] ) ); /* Q29 */
     251             :         }
     252      755665 :         Word16 exp = 2;
     253      755665 :         move16();
     254      755665 :         normBuffer = ISqrt32( normBuffer, &exp ); // Q=(31-exp)
     255             : 
     256     6878896 :         FOR( j = 0; j < hEFAPdata->numSpk; ++j )
     257             :         {
     258     6123231 :             hEFAPdata->bufferShort_fx[j] = Mpy_32_32( hEFAPdata->bufferShort_fx[j], normBuffer ); // Q=(30+31-exp-31)=>(30-exp)
     259     6123231 :             move32();
     260     6123231 :             hEFAPdata->bufferShort_fx[j] = L_shl( hEFAPdata->bufferShort_fx[j], exp ); /* Q30 */
     261     6123231 :             move32();
     262             :         }
     263             :     }
     264             :     ELSE
     265             :     {
     266        6650 :         normBuffer = 0;
     267        6650 :         move32();
     268       69580 :         FOR( j = 0; j < hEFAPdata->numSpk; ++j )
     269             :         {
     270       62930 :             hEFAPdata->bufferShort_fx[j] = 0;
     271       62930 :             move32();
     272             :             /* Multiplying by the downmixMatrix */
     273      829220 :             FOR( i = 0; i < hEFAPdata->vtxData.numVtx; ++i )
     274             :             {
     275      766290 :                 hEFAPdata->bufferShort_fx[j] = L_add_sat( hEFAPdata->bufferShort_fx[j], L_shr( Mpy_32_32( hEFAPdata->bufferLong_fx[i], hEFAPdata->dmTranspose_fx[i][j] ), Q1 ) ); /* Q30 */
     276      766290 :                 move32();
     277             :             }
     278       62930 :             normBuffer = L_add_sat( normBuffer, L_shr( hEFAPdata->bufferShort_fx[j], Q1 ) ); /* Q29 */
     279             :         }
     280        6650 :         Word16 exp = 2;
     281        6650 :         move16();
     282        6650 :         normBuffer = Inv16( extract_l( L_shr( normBuffer, Q16 ) ), &exp ); /*Q=(15-exp)*/
     283             : 
     284       69580 :         FOR( j = 0; j < hEFAPdata->numSpk; ++j )
     285             :         {
     286       62930 :             Word16 exp_temp = add( exp, 1 );
     287       62930 :             hEFAPdata->bufferShort_fx[j] = Sqrt32( Mpy_32_16_1( hEFAPdata->bufferShort_fx[j], extract_l( normBuffer ) ) /*Q(30-exp)*/, &exp_temp ); // Q=(31-exp_temp)
     288       62930 :             move32();
     289       62930 :             hEFAPdata->bufferShort_fx[j] = L_shl( hEFAPdata->bufferShort_fx[j], sub( exp_temp, 1 ) ); /* Q30 */
     290       62930 :             move32();
     291             :         }
     292             :     }
     293             : 
     294             :     /* Copy gains to output */
     295      762315 :     Copy32( hEFAPdata->bufferShort_fx, gains, hEFAPdata->numSpk ); /* Q30 */
     296             : 
     297      762315 :     return;
     298             : }
     299             : 
     300             : 
     301             : /*-------------------------------------------------------------------------*
     302             :  * efap_free_data()
     303             :  *
     304             :  * Wrapper to free EFAP data structure
     305             :  *-------------------------------------------------------------------------*/
     306             : 
     307        1677 : void efap_free_data_fx(
     308             :     EFAP_HANDLE *hEFAPdata /* i/o: EFAP handle to be freed */
     309             : )
     310             : {
     311             :     Word16 i, dim1;
     312             :     void **p_dmTranspose;
     313             : 
     314        1677 :     test();
     315        1677 :     IF( hEFAPdata == NULL || *hEFAPdata == NULL )
     316             :     {
     317         777 :         return;
     318             :     }
     319             : 
     320         900 :     dim1 = ( *hEFAPdata )->numTot;
     321         900 :     move16();
     322             : 
     323             :     /* instance buffer members */
     324         900 :     free( ( *hEFAPdata )->aziSpk );
     325         900 :     ( *hEFAPdata )->aziSpk = NULL;
     326             : 
     327         900 :     free( ( *hEFAPdata )->eleSpk );
     328         900 :     ( *hEFAPdata )->eleSpk = NULL;
     329             : 
     330         900 :     free( ( *hEFAPdata )->vtxData.vertexArray );
     331         900 :     ( *hEFAPdata )->vtxData.vertexArray = NULL;
     332             : 
     333         900 :     free( ( *hEFAPdata )->vtxData.vtxOrder );
     334         900 :     ( *hEFAPdata )->vtxData.vtxOrder = NULL;
     335             : 
     336         900 :     free( ( *hEFAPdata )->bufferLong_fx );
     337         900 :     ( *hEFAPdata )->bufferLong_fx = NULL;
     338             : 
     339         900 :     free( ( *hEFAPdata )->bufferShort_fx );
     340         900 :     ( *hEFAPdata )->bufferShort_fx = NULL;
     341             : 
     342         900 :     p_dmTranspose = (void **) ( *hEFAPdata )->dmTranspose_fx;
     343             : 
     344       10588 :     FOR( i = 0; i < dim1; i++ )
     345             :     {
     346        9688 :         free( p_dmTranspose[i] );
     347             :     }
     348         900 :     free( p_dmTranspose );
     349             : 
     350             :     /* instance */
     351         900 :     free( *hEFAPdata );
     352         900 :     *hEFAPdata = NULL;
     353             : 
     354         900 :     return;
     355             : }
     356             : 
     357             : 
     358             : /*-----------------------------------------------------------------------*
     359             :  * Local function definitions
     360             :  *-----------------------------------------------------------------------*/
     361             : 
     362             : 
     363             : /*-------------------------------------------------------------------------*
     364             :  * poly_init()
     365             :  *
     366             :  * Main function for the Efap initialization whose purpose is to initialize
     367             :  * the different polygons and to add the ghost speakers
     368             :  *-------------------------------------------------------------------------*/
     369             : 
     370         900 : static ivas_error poly_init_fx(
     371             :     EFAP *efap,            /* i/o: A pointer to a handle to efap instance                                  */
     372             :     const Word16 efip_flag /* i  : flag to indicate whether initialization is for EFIP (used for ALLRAD)   */
     373             : )
     374             : {
     375             :     Word16 n, m, j;
     376             :     Word16 finalLength, lengthTri2PolyPS;
     377             :     Word16 lengthTri2PolySorted[EFAP_MAX_POLY_SET];
     378             :     Word16 sortedChan[EFAP_MAX_POLY_SET][EFAP_MAX_CHAN_NUM];
     379             :     Word32 tmpMax, tmpMin;
     380             :     ivas_error error;
     381             : 
     382         900 :     error = IVAS_ERR_OK;
     383         900 :     move32();
     384             : 
     385             :     /* Safety Check */
     386         900 :     assert( efap != NULL && "EFAP: efap == NULL" );
     387             : 
     388       45900 :     FOR( n = 0; n < EFAP_MAX_POLY_SET; n++ )
     389             :     {
     390       45000 :         set16_fx( sortedChan[n], 0, EFAP_MAX_CHAN_NUM );
     391             :     }
     392             : 
     393             :     /* Computing the different ghost vertex, the downmix matrix and the triangle array */
     394         900 :     IF( NE_32( ( error = sphere_triangulation_fx( efap->numSpk, &efap->vtxData, &efap->polyData, &efap->dmTranspose_fx, &efap->numTot, efip_flag ) ), IVAS_ERR_OK ) )
     395             :     {
     396           0 :         return error;
     397             :     }
     398             : 
     399             :     /* set isNaN for ghost loudspeakers */
     400       10588 :     FOR( n = 0; n < efap->vtxData.numVtx; ++n )
     401             :     {
     402        9688 :         test();
     403       18476 :         if ( GT_32( efap->vtxData.vertexArray[n].ele /*Q22*/, ( Q22_90_DEG /*90.0 Q22*/ - 4 /*1e-6 Q22*/ ) ) ||
     404        8788 :              LT_32( efap->vtxData.vertexArray[n].ele /*Q22*/, ( 4 /*1e-6 Q22*/ - Q22_90_DEG /*90.0 Q22*/ ) ) )
     405             :         {
     406        1800 :             efap->vtxData.vertexArray[n].isNaN = 1;
     407        1800 :             move16();
     408             :         }
     409             :     }
     410             : 
     411             :     /* Converting the triangle to polygon structure */
     412         900 :     tri_to_poly_fx( efap->vtxData.vertexArray, efap->polyData.triArray, efap->vtxData.numVtx, efap->polyData.numTri, sortedChan, &lengthTri2PolyPS, lengthTri2PolySorted );
     413             : 
     414             :     /* Completing the polyData Structure */
     415         900 :     finalLength = -1;
     416         900 :     move16();
     417             : 
     418       15941 :     FOR( n = 0; n < lengthTri2PolyPS; ++n )
     419             :     {
     420       15041 :         m = add( finalLength, 1 );
     421             : 
     422             :         /* Complete the fields of the polygon */
     423       60899 :         FOR( j = 0; j < lengthTri2PolySorted[n]; ++j )
     424             :         {
     425       45858 :             efap->polyData.polysetArray[m].chan[j] = sortedChan[n][j];
     426       45858 :             move16();
     427       45858 :             efap->polyData.polysetArray[m].polyAzi[j] = efap->vtxData.vertexArray[sortedChan[n][j]].azi; /* Q22 */
     428       45858 :             move32();
     429       45858 :             efap->polyData.polysetArray[m].polyEle[j] = efap->vtxData.vertexArray[sortedChan[n][j]].ele; /* Q22 */
     430       45858 :             move32();
     431       45858 :             efap->polyData.polysetArray[m].isNaN[j] = efap->vtxData.vertexArray[sortedChan[n][j]].isNaN;
     432       45858 :             move16();
     433             :         }
     434             : 
     435       15041 :         efap->polyData.polysetArray[m].numChan = lengthTri2PolySorted[n];
     436       15041 :         move16();
     437             : 
     438             :         /* In case tmpMax - tmpMin > 180, wrap polygon azimuth */
     439       15041 :         maximum_l( efap->polyData.polysetArray[m].polyAzi, lengthTri2PolySorted[n], &tmpMax );
     440       15041 :         minimum_l( efap->polyData.polysetArray[m].polyAzi, lengthTri2PolySorted[n], &tmpMin );
     441             : 
     442       15041 :         IF( GT_32( L_sub( tmpMax /*q22*/, tmpMin /*q22*/ ), Q22_180_DEG /*180 in Q22*/ ) )
     443             :         {
     444       10524 :             FOR( j = 0; j < lengthTri2PolySorted[n]; ++j )
     445             :             {
     446        8007 :                 assert( ( m + 2 < EFAP_MAX_POLY_SET ) && "EFAP: maximum polygons exceeded!" );
     447             : 
     448             :                 /* add two new polygons with azimuths wrapped to differing bounds */
     449        8007 :                 efap->polyData.polysetArray[m + 1].polyAzi[j] = efap_32mod32( efap->polyData.polysetArray[m].polyAzi[j] /*q22*/, Q22_360_DEG /*360 q22*/ ); /* Q22 */
     450        8007 :                 move32();
     451        8007 :                 efap->polyData.polysetArray[m + 2].polyAzi[j] = L_sub( efap->polyData.polysetArray[m + 1].polyAzi[j] /*q22*/, Q22_360_DEG /*360 q22*/ ); /* Q22 */
     452        8007 :                 move32();
     453             : 
     454             :                 /* Copy the rest of the fields */
     455        8007 :                 efap->polyData.polysetArray[m + 1].chan[j] = efap->polyData.polysetArray[m].chan[j];
     456        8007 :                 move16();
     457        8007 :                 efap->polyData.polysetArray[m + 1].polyEle[j] = efap->polyData.polysetArray[m].polyEle[j]; /* Q22 */
     458        8007 :                 move32();
     459        8007 :                 efap->polyData.polysetArray[m + 1].isNaN[j] = efap->polyData.polysetArray[m].isNaN[j];
     460        8007 :                 move16();
     461        8007 :                 efap->polyData.polysetArray[m + 1].numChan = lengthTri2PolySorted[n];
     462        8007 :                 move16();
     463             : 
     464        8007 :                 efap->polyData.polysetArray[m + 2].chan[j] = efap->polyData.polysetArray[m].chan[j];
     465        8007 :                 move16();
     466        8007 :                 efap->polyData.polysetArray[m + 2].polyEle[j] = efap->polyData.polysetArray[m].polyEle[j]; /* Q22 */
     467        8007 :                 move32();
     468        8007 :                 efap->polyData.polysetArray[m + 2].isNaN[j] = efap->polyData.polysetArray[m].isNaN[j];
     469        8007 :                 move16();
     470        8007 :                 efap->polyData.polysetArray[m + 2].numChan = lengthTri2PolySorted[n];
     471        8007 :                 move16();
     472             :             }
     473        2517 :             finalLength = add( finalLength, 2 );
     474             :         }
     475       15041 :         finalLength = add( finalLength, 1 );
     476             :     }
     477         900 :     finalLength = add( finalLength, 1 );
     478             : 
     479             :     /* Updating the number of polygons */
     480         900 :     efap->polyData.numPoly = finalLength;
     481         900 :     move16();
     482             : 
     483             : 
     484         900 :     return error;
     485             : }
     486             : 
     487             : 
     488             : /*-------------------------------------------------------------------------*
     489             :  * sphere_triangulation()
     490             :  *
     491             :  *
     492             :  *-------------------------------------------------------------------------*/
     493             : 
     494         900 : static ivas_error sphere_triangulation_fx(
     495             :     const Word16 numSpk,         /* i  : Number of speakers                                                        */
     496             :     EFAP_VERTEX_DATA *vtxData,   /* i/o: Vertex data structure                                                     */
     497             :     EFAP_POLYSET_DATA *polyData, /* o  : Polygon data structure                                                    */
     498             :     Word32 ***dmTranspose_fx,    /* o  : Transpose of the downmix matrix                                       Q31 */
     499             :     Word16 *numTot,              /* o  : Number of speakers (real + ghost)                                         */
     500             :     const Word16 efip_flag       /* i  : flag to indicate whether initialization is for EFIP (used for ALLRAD)     */
     501             : )
     502             : {
     503             :     Word16 i;
     504             :     void **p_dmTranspose;
     505             :     Word16 vtxInHull[EFAP_MAX_SIZE_TMP_BUFF];
     506             : 
     507         900 :     set16_fx( vtxInHull, 0, EFAP_MAX_SIZE_TMP_BUFF );
     508             : 
     509             :     /* Add Imaginary Speakers */
     510         900 :     add_ghost_speakers_fx( vtxData->vertexArray, &vtxData->numVtx, efip_flag );
     511             : 
     512             :     /* Sort the vertices according to their index */
     513         900 :     IF( ( vtxData->vtxOrder = (Word16 *) malloc( vtxData->numVtx * sizeof( Word16 ) ) ) == NULL )
     514             :     {
     515           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for EFAP Vertex Order\n" ) );
     516             :     }
     517             : 
     518         900 :     sort_vertices_fx( vtxData->vertexArray, &vtxData->numVtx, vtxData->vtxOrder );
     519             : 
     520             :     /* Computing the initial Polyeder   */
     521         900 :     initial_polyeder_fx( vtxData, polyData->triArray, &polyData->numTri, &vtxInHull[0] );
     522             : 
     523             :     /* Add the vertex to the convex hull */
     524       10588 :     FOR( i = 0; i < vtxData->numVtx; ++i )
     525             :     {
     526        9688 :         add_vertex_to_convex_hull_fx( vtxData, vtxData->vtxOrder[i], &vtxInHull[0], polyData->triArray, &polyData->numTri );
     527             :     }
     528             : 
     529         900 :     assert( polyData->numTri != 0 && "EFAP: failed to construct convex hull!" );
     530             : 
     531             :     /* Allocate the DM matrix transpose */
     532         900 :     IF( ( p_dmTranspose = malloc( vtxData->numVtx * sizeof( Word32 * ) ) ) == NULL )
     533             :     {
     534           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "EFAP: can not allocate memory for dmTranspose\n" ) );
     535             :     }
     536             : 
     537             :     /* Store the value of numVtx to be used for freeing later (numVtx will change after remap_ghosts() ) */
     538         900 :     *numTot = vtxData->numVtx;
     539         900 :     move16();
     540             : 
     541       10588 :     FOR( i = 0; i < vtxData->numVtx; i++ ){
     542        9688 :         IF( ( p_dmTranspose[i] = malloc( numSpk * sizeof( Word32 ) ) ) == NULL ){
     543           0 :             return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "EFAP: can not allocate memory for dmTranspose\n" ) );
     544             : }
     545             : }
     546         900 : *dmTranspose_fx = (Word32 **) p_dmTranspose;
     547             : 
     548             : /* Remap Ghosts */
     549         900 : remap_ghosts_fx( vtxData->vertexArray, polyData->triArray, numSpk, &vtxData->numVtx, polyData->numTri, *dmTranspose_fx ); // dmTranspose_fx q31
     550             : 
     551         900 : return IVAS_ERR_OK;
     552             : }
     553             : 
     554             : 
     555             : /*-------------------------------------------------------------------------*
     556             :  * initial_polyeder()
     557             :  *
     558             :  *
     559             :  *-------------------------------------------------------------------------*/
     560             : 
     561             : 
     562         900 : static void initial_polyeder_fx(
     563             :     EFAP_VERTEX_DATA *vtxData,  /* i  : Vertex data structure                              */
     564             :     EFAP_LS_TRIANGLE *triArray, /* o  : Triangle array structure                           */
     565             :     Word16 *numTri,             /* o  : Size of triangle array                             */
     566             :     Word16 *vtxInHull           /* o  : Flag if the vertex was added to the inital simplex */
     567             : )
     568             : {
     569             :     Word16 i;
     570             :     Word16 numVtx;
     571             :     Word16 tmpSurface[3];
     572             :     Word16 tetrahedron[4];
     573             :     Word32 tmp;
     574             :     Word32 centroid[3];
     575             :     Word32 tmpCross[3];
     576             :     Word32 tmp1[3], tmp2[3], tmp3[3];
     577             : 
     578             :     /* Safety check */
     579         900 :     assert( triArray != NULL && "EFAP: triArray==NULL" );
     580             : 
     581             :     /* initialize variables */
     582         900 :     set16_fx( tmpSurface, -1, 3 );
     583         900 :     set32_fx( centroid, 0, 3 );
     584         900 :     set32_fx( tmp1, 0, 3 );
     585         900 :     set32_fx( tmp2, 0, 3 );
     586         900 :     set32_fx( tmp3, 0, 3 );
     587         900 :     set32_fx( tmpCross, 0, 3 );
     588             : 
     589         900 :     numVtx = vtxData->numVtx;
     590         900 :     move16();
     591             : 
     592             :     /* seed vertices */
     593        4500 :     FOR( i = 0; i < 4; i++ )
     594             :     {
     595        3600 :         tetrahedron[i] = i;
     596        3600 :         move16();
     597             :     }
     598             : 
     599             :     /* 1. attempt to create an edge with nonzero length */
     600         900 :     test();
     601         900 :     WHILE( EQ_32( vtxData->vertexArray[tetrahedron[0]].azi /*q22*/, vtxData->vertexArray[tetrahedron[1]].azi /*q22*/ ) &&
     602             :            EQ_32( vtxData->vertexArray[tetrahedron[0]].ele /*q22*/, vtxData->vertexArray[tetrahedron[1]].ele /*q22*/ ) )
     603             :     {
     604           0 :         test();
     605           0 :         tetrahedron[1] = add( tetrahedron[1], 1 );
     606           0 :         move16();
     607           0 :         assert( tetrahedron[1] < numVtx && "EFAP: convex hull construction failed, vertices are coincident!" );
     608             :     }
     609             : 
     610             :     /* 2. attempt to create a triangle with nonzero area */
     611         900 :     tmp = 0;
     612         900 :     move32();
     613         900 :     v_sub_fixed( vtxData->vertexArray[tetrahedron[1]].pos, vtxData->vertexArray[tetrahedron[0]].pos, tmp1, 3, 1 ); // tmp1 Q(31-1)
     614         900 :     WHILE( LT_16( tetrahedron[2], numVtx ) )
     615             :     {
     616         900 :         v_sub_fixed( vtxData->vertexArray[tetrahedron[2]].pos, vtxData->vertexArray[tetrahedron[0]].pos, tmp2, 3, 1 ); // tmp2 Q(31-1)
     617         900 :         efap_crossp_fx( tmp1, tmp2, tmpCross );                                                                        // tmpCross Q29
     618        3600 :         FOR( i = 0; i < 3; i++ )
     619             :         {
     620        2700 :             tmp = L_add( tmp, Mpy_32_32( tmpCross[i], tmpCross[i] ) ); // tmp Q27
     621             :         }
     622         900 :         IF( GT_32( L_abs( tmp ), ( POLY_THRESH_Q29 /*1e-4f Q29*/ * POLY_THRESH_Q29 /*1e-4f Q29*/ ) >> 31 ) ) /* compare tmp against POLY_THRESH^2 instead of sqrtf(tmp) */
     623             :         {
     624         900 :             BREAK;
     625             :         }
     626           0 :         tetrahedron[2] = add( tetrahedron[2], 1 );
     627           0 :         move16();
     628             :     }
     629         900 :     assert( tetrahedron[2] < numVtx && "EFAP: convex hull construction failed, vertices are colinear!" );
     630             : 
     631             :     /* 3. attempt to create a tetrahedron with nonzero volume */
     632         900 :     tmp = 0;
     633         900 :     move32();
     634        3247 :     WHILE( LT_16( tetrahedron[3], numVtx ) )
     635             :     {
     636        3247 :         v_sub_fixed( vtxData->vertexArray[tetrahedron[3]].pos, vtxData->vertexArray[tetrahedron[0]].pos, tmp3, 3, 1 ); // tmp3 Q30
     637        3247 :         tmp = dotp_fixed( tmp3, tmpCross, 3 );                                                                         // tmp Q28
     638        3247 :         IF( GT_32( L_abs( tmp ), POLY_THRESH_Q28 /*1e-4f Q28*/ ) )
     639             :         {
     640         900 :             BREAK;
     641             :         }
     642        2347 :         tetrahedron[3] = add( tetrahedron[3], 1 );
     643        2347 :         move16();
     644             :     }
     645         900 :     assert( tetrahedron[3] < numVtx && "EFAP: convex hull construction failed, vertices are coplanar!" );
     646             : 
     647             :     /* 4. compute the centroid of the initial tetrahedron */
     648        4500 :     FOR( i = 0; i < 4; i++ )
     649             :     {
     650        3600 :         vtxInHull[tetrahedron[i]] = 1; /* set vertex as added to hull*/
     651        3600 :         move16();
     652        3600 :         centroid[0] = L_add( centroid[0], L_shr( vtxData->vertexArray[tetrahedron[i]].pos[0], Q2 ) ); // Q29
     653        3600 :         move32();
     654        3600 :         centroid[1] = L_add( centroid[1], L_shr( vtxData->vertexArray[tetrahedron[i]].pos[1], Q2 ) ); // Q29
     655        3600 :         move32();
     656        3600 :         centroid[2] = L_add( centroid[2], L_shr( vtxData->vertexArray[tetrahedron[i]].pos[2], Q2 ) ); // Q29
     657        3600 :         move32();
     658             :     }
     659             :     /* Executed below float operation
     660             :        centroid[0] /= 4;
     661             :        centroid[1] /= 4;
     662             :        centroid[2] /= 4;
     663             :     */
     664             : 
     665             :     /* 5. create and orient planes */
     666         900 :     tmpSurface[0] = tetrahedron[0];
     667         900 :     move16();
     668         900 :     tmpSurface[1] = tetrahedron[1];
     669         900 :     move16();
     670         900 :     tmpSurface[2] = tetrahedron[2];
     671         900 :     move16();
     672         900 :     flip_plane_fx( vtxData->vertexArray, tmpSurface, centroid );
     673         900 :     Copy( tmpSurface, triArray[0].LS, 3 );
     674             : 
     675         900 :     tmpSurface[0] = tetrahedron[0];
     676         900 :     move16();
     677         900 :     tmpSurface[1] = tetrahedron[1];
     678         900 :     move16();
     679         900 :     tmpSurface[2] = tetrahedron[3];
     680         900 :     move16();
     681         900 :     flip_plane_fx( vtxData->vertexArray, tmpSurface, centroid );
     682         900 :     Copy( tmpSurface, triArray[1].LS, 3 );
     683             : 
     684         900 :     tmpSurface[0] = tetrahedron[0];
     685         900 :     move16();
     686         900 :     tmpSurface[1] = tetrahedron[2];
     687         900 :     move16();
     688         900 :     tmpSurface[2] = tetrahedron[3];
     689         900 :     move16();
     690         900 :     flip_plane_fx( vtxData->vertexArray, tmpSurface, centroid );
     691         900 :     Copy( tmpSurface, triArray[2].LS, 3 );
     692             : 
     693         900 :     tmpSurface[0] = tetrahedron[1];
     694         900 :     move16();
     695         900 :     tmpSurface[1] = tetrahedron[2];
     696         900 :     move16();
     697         900 :     tmpSurface[2] = tetrahedron[3];
     698         900 :     move16();
     699         900 :     flip_plane_fx( vtxData->vertexArray, tmpSurface, centroid );
     700         900 :     Copy( tmpSurface, triArray[3].LS, 3 );
     701             : 
     702             :     /* set numTri */
     703         900 :     *numTri = 4;
     704         900 :     move16();
     705             : 
     706         900 :     return;
     707             : }
     708             : 
     709             : 
     710             : /*-------------------------------------------------------------------------*
     711             :  * add_ghost_speakers_fx()
     712             :  *
     713             :  *
     714             :  *-------------------------------------------------------------------------*/
     715             : 
     716         900 : static void add_ghost_speakers_fx(
     717             :     EFAP_VERTEX *vertexArray, /* i/o: Vertex array                                                          */
     718             :     Word16 *numVtx,           /* i/o: Size of vertex array                                                  */
     719             :     const Word16 efip_flag    /* i  : flag to indicate whether initialization is for EFIP (used for ALLRAD) */
     720             : )
     721             : {
     722             :     Word16 numVertex;
     723             :     Word16 lengthVertGhst; /* Nb of vertical ghost added */
     724             :     Word16 lengthHorGhst;  /* Nb of Horizontal Ghost */
     725             :     Word16 i, j, k, a;     /* Integer for loops */
     726             :     Word16 num_new;        /* Number of new vertices to add */
     727             :     Word32 maxAngle;       /* Max azimuth tolerance for extend the LS setup horizontaly */
     728             :     Word32 newDiff;        /* Angle differences that will help us set the extended LS setup */
     729             :     Word32 newAzi;         /* New azimuth for the new horizontal LS */
     730             :     Word32 ele[EFAP_MAX_SIZE_TMP_BUFF];
     731             :     Word32 tmpEle;
     732             :     Word32 tmpAzi[EFAP_MAX_SIZE_TMP_BUFF];
     733             :     Word32 tmpAngleDiff[EFAP_MAX_SIZE_TMP_BUFF]; /* tmp array of angles differences */
     734             :     Word32 sectors[EFAP_MAX_SIZE_TMP_BUFF];      /* Help us determine the zone where we should extend LS */
     735             :     EFAP_VTX_DMX_TYPE vtxDmxType;
     736             :     Word16 new_diff_e;
     737             : 
     738         900 :     vtxDmxType = EFAP_DMX_INTENSITY;
     739         900 :     move32();
     740         900 :     numVertex = *numVtx;
     741         900 :     move16();
     742         900 :     maxAngle = 13421773; //(1.f / 160.0f) in Q31
     743         900 :     move32();
     744             : 
     745             :     /* Extracting Azi and Ele for computation purposes */
     746        8568 :     FOR( i = 0; i < numVertex; ++i )
     747             :     {
     748        7668 :         ele[i] = vertexArray[i].ele; // q22
     749        7668 :         move32();
     750             :     }
     751             : 
     752             :     /* ADD VOG IF NECESSERAY (i.e. if the elevation of the highest LS is < 90 deg) */
     753         900 :     a = 0;
     754         900 :     move16();
     755         900 :     maximum_l( ele, numVertex, &tmpEle ); // tmpEle q22
     756             : 
     757         900 :     lengthVertGhst = 0;
     758         900 :     move16();
     759         900 :     IF( LT_32( tmpEle, Q22_90_DEG /*90 q22*/ ) )
     760             :     {
     761         900 :         IF( efip_flag )
     762             :         {
     763          95 :             IF( GT_32( tmpEle, Q22_45_DEG /*45 q22*/ ) )
     764             :             {
     765           3 :                 vtxDmxType = EFAP_DMX_NONE;
     766           3 :                 move32();
     767             :             }
     768             :             ELSE
     769             :             {
     770          92 :                 vtxDmxType = EFAP_DMX_AMPLITUDE;
     771          92 :                 move32();
     772             :             }
     773             :         }
     774         900 :         add_vertex_fx( vertexArray, 0, Q22_90_DEG /*90 q22*/, add( numVertex, a ), vtxDmxType );
     775         900 :         lengthVertGhst = add( lengthVertGhst, 1 );
     776         900 :         a = add( a, 1 );
     777             :     }
     778             : 
     779             :     /* ADD VOH IF NECESSERAY (i.e. if the elevation of the lowest LS is > -90 deg) */
     780         900 :     minimum_l( ele, numVertex, &tmpEle ); /*tmpEle q22*/
     781         900 :     IF( GT_32( tmpEle, -Q22_90_DEG /*90 q22*/ ) )
     782             :     {
     783         900 :         IF( efip_flag )
     784             :         {
     785          95 :             IF( LT_32( tmpEle, -Q22_45_DEG /*45 q22*/ ) )
     786             :             {
     787           3 :                 vtxDmxType = EFAP_DMX_NONE;
     788           3 :                 move32();
     789             :             }
     790             :             ELSE
     791             :             {
     792          92 :                 vtxDmxType = EFAP_DMX_AMPLITUDE;
     793          92 :                 move32();
     794             :             }
     795             :         }
     796             : 
     797         900 :         add_vertex_fx( vertexArray, 0, -Q22_90_DEG /*90 q22*/, add( numVertex, a ), vtxDmxType );
     798             : 
     799         900 :         lengthVertGhst = add( lengthVertGhst, 1 );
     800         900 :         a = add( a, 1 );
     801             :     }
     802             : 
     803             :     /* LIST ALL SURROUNDING loudspeakers */
     804         900 :     k = 0;
     805         900 :     move16();
     806             : 
     807        8568 :     FOR( i = 0; i < numVertex; ++i )
     808             :     {
     809        7668 :         IF( LT_32( L_abs( vertexArray[i].ele ), Q22_45_DEG /*45 q22*/ ) )
     810             :         {
     811        7464 :             tmpAzi[k] = vertexArray[i].azi; // q22
     812        7464 :             move32();
     813        7464 :             k = add( k, 1 );
     814             :         }
     815             :     }
     816             : 
     817         900 :     lengthHorGhst = 0;
     818         900 :     move16();
     819         900 :     IF( k == 0 ) /* no speakers found: add a triangle of ghost speakers */
     820             :     {
     821           0 :         add_vertex_fx( vertexArray, 0, 0, add( numVertex, a ), EFAP_DMX_INTENSITY );
     822           0 :         add_vertex_fx( vertexArray, Q22_120_DEG /*120 q22*/, 0, add( add( numVertex, a ), 1 ), EFAP_DMX_INTENSITY );
     823           0 :         add_vertex_fx( vertexArray, Q22_240_DEG /*240 q22*/, 0, add( add( numVertex, a ), 2 ), EFAP_DMX_INTENSITY );
     824           0 :         a = add( a, 3 );
     825           0 :         lengthHorGhst = add( lengthHorGhst, 3 );
     826             :     }
     827         900 :     ELSE IF( EQ_16( k, 1 ) ) /* only one speaker found: add two ghost speakers to complete a triangle */
     828             :     {
     829          81 :         add_vertex_fx( vertexArray, L_add( tmpAzi[0], Q22_120_DEG /*120 q22*/ ), 0, add( numVertex, a ), EFAP_DMX_INTENSITY );
     830          81 :         add_vertex_fx( vertexArray, L_add( tmpAzi[0], Q22_240_DEG /*240 q22*/ ), 0, add( add( numVertex, a ), 1 ), EFAP_DMX_INTENSITY );
     831          81 :         a = add( a, 2 );
     832          81 :         lengthHorGhst = add( lengthHorGhst, 2 );
     833             :     }
     834             :     ELSE /* fill gaps greater than maxAngle */
     835             :     {
     836             :         /* Here, k correspond to the number of LS whose ele is < 45 deg, should be = numVertex */
     837         819 :         sort_l( tmpAzi, k ); // tmpAzi q22
     838             : 
     839             :         /* The next lines correspond to angle_diff = [azi(2:end), azi(1) + 360] - azi; in Matlab */
     840        7383 :         FOR( i = 0; i < k - 1; ++i )
     841             :         {
     842        6564 :             tmpAngleDiff[i] = L_sub( tmpAzi[i + 1], tmpAzi[i] ); // q22
     843        6564 :             move32();
     844        6564 :             sectors[i] = ceil_fixed( Mpy_32_32( tmpAngleDiff[i], maxAngle ), Q22 ); // q22
     845        6564 :             move32();
     846             : 
     847        6564 :             if ( GT_32( sectors[i], Q22_1 /*1 q22*/ ) )
     848             :             {
     849           0 :                 lengthHorGhst = add( lengthHorGhst, 1 );
     850             :             }
     851             :         }
     852         819 :         tmpAngleDiff[k - 1] = L_sub( L_add( tmpAzi[0], Q22_360_DEG /*360 q22*/ ), tmpAzi[k - 1] ); // q22
     853             : 
     854         819 :         sectors[k - 1] = ceil_fixed( Mpy_32_32( tmpAngleDiff[k - 1], maxAngle ), Q22 ); // q22
     855             : 
     856         819 :         if ( GT_32( sectors[k - 1], Q22_1 /*1 q22*/ ) )
     857             :         {
     858          58 :             lengthHorGhst = add( lengthHorGhst, 1 );
     859             :         }
     860             : 
     861             :         /* Adding new virtual speakers */
     862        8202 :         FOR( i = 0; i < k; ++i )
     863             :         {
     864        7383 :             IF( GT_32( sectors[i], Q22_1 /*1 q22*/ ) )
     865             :             {
     866          58 :                 newDiff = BASOP_Util_Divide3232_Scale( tmpAngleDiff[i], sectors[i], &new_diff_e ); // Q=15-new_diff_e
     867          58 :                 newDiff = L_shl( newDiff, add( new_diff_e, 7 ) );                                  // q22
     868          58 :                 num_new = extract_l( L_shr( L_sub( sectors[i], Q22_1 /*1 q22*/ ), Q22 ) );         // q0
     869             : 
     870         116 :                 FOR( j = 0; j < num_new; ++j )
     871             :                 {
     872          58 :                     newAzi = L_add( tmpAzi[i], imult3216( newDiff, add( j, 1 ) ) ); // q22
     873             : 
     874          58 :                     add_vertex_fx( vertexArray, newAzi, 0, add( numVertex, a ), EFAP_DMX_INTENSITY );
     875          58 :                     a = add( a, 1 );
     876             : 
     877          58 :                     if ( j > 0 )
     878             :                     {
     879           0 :                         lengthHorGhst = add( lengthHorGhst, 1 );
     880             :                     }
     881             :                 }
     882             :             }
     883             :         }
     884             :     }
     885         900 :     *numVtx = add( add( numVertex, lengthHorGhst ), lengthVertGhst );
     886         900 :     move16();
     887             : 
     888         900 :     return;
     889             : }
     890             : 
     891             : /*-------------------------------------------------------------------------*
     892             :  * sort_vertices()
     893             :  *
     894             :  *
     895             :  *-------------------------------------------------------------------------*/
     896             : 
     897         900 : static void sort_vertices_fx(
     898             :     const EFAP_VERTEX *vertexArray, /* i  : Vertex array             */
     899             :     const Word16 *numVtx,           /* i  : Size of vertex array     */
     900             :     Word16 *order                   /* o  : Original index positions */
     901             : )
     902             : {
     903             :     Word16 tmpIdx[EFAP_MAX_SIZE_TMP_BUFF];
     904             :     Word16 i;
     905             : 
     906             :     /* Initializing tmpIdx  */
     907       10588 :     FOR( i = 0; i < *numVtx; ++i )
     908             :     {
     909        9688 :         tmpIdx[i] = vertexArray[i].idx;
     910        9688 :         move16();
     911             :     }
     912             : 
     913             :     /* Sorting indexes */
     914         900 :     efap_sort_s_fx( tmpIdx, order, *numVtx );
     915             : 
     916         900 :     return;
     917             : }
     918             : 
     919             : /*-------------------------------------------------------------------------*
     920             :  * add_vertex_to_convex_hull_fx()
     921             :  *
     922             :  *
     923             :  *-------------------------------------------------------------------------*/
     924             : 
     925        9688 : static void add_vertex_to_convex_hull_fx(
     926             :     const EFAP_VERTEX_DATA *vtxData, /* i  : Vertex data structure                                  */
     927             :     const Word16 vtxIdx,             /* i  : Vertex to be added to the hull                          */
     928             :     Word16 *vtxInHull,               /* i/o: Array indicating whether the vertex is part of the hull */
     929             :     EFAP_LS_TRIANGLE *triArray,      /* i/o: Triangle array                                          */
     930             :     Word16 *szTri                    /* i/o: Size of Triangle array                                  */
     931             : )
     932             : {
     933             :     Word16 i, k, l;
     934             :     Word16 visible[EFAP_MAX_SIZE_TMP_BUFF];
     935             :     Word16 edges[EFAP_MAX_SIZE_TMP_BUFF];
     936             :     Word16 numEdges[1];
     937             :     Word16 surface[3];
     938             :     Word32 numHullVtx;
     939             :     Word32 centroid[3];
     940        9688 :     const Word32 threshold = -268; // -1e-6f in Q28
     941        9688 :     move32();
     942             :     Word32 tmpDist;
     943             :     EFAP_LS_TRIANGLE triArrayNew[EFAP_MAX_POLY_SET];
     944             :     Word16 tmp16, tmp_e;
     945             :     Word32 tmp32;
     946             : 
     947             :     /* If the vertex is already part of the hull, nothing must be done */
     948        9688 :     IF( vtxInHull[vtxIdx] )
     949             :     {
     950        3600 :         return;
     951             :     }
     952             : 
     953             :     /* Compute the centroid of the current convex hull */
     954        6088 :     numHullVtx = 0;
     955        6088 :     move32();
     956        6088 :     set32_fx( centroid, 0, 3 );
     957       82752 :     FOR( i = 0; i < vtxData->numVtx; i++ )
     958             :     {
     959       76664 :         IF( vtxInHull[i] )
     960             :         {
     961       47464 :             numHullVtx = L_add( numHullVtx, 1 );
     962       47464 :             centroid[0] = L_add( centroid[0], L_shr( vtxData->vertexArray[i].pos[0], Q4 ) ); // q27
     963       47464 :             move32();
     964       47464 :             centroid[1] = L_add( centroid[1], L_shr( vtxData->vertexArray[i].pos[1], Q4 ) ); // q27
     965       47464 :             move32();
     966       47464 :             centroid[2] = L_add( centroid[2], L_shr( vtxData->vertexArray[i].pos[2], Q4 ) ); // q27
     967       47464 :             move32();
     968             :         }
     969             :     }
     970             :     /* numHullVtx = 1.0f / numHullVtx; */
     971        6088 :     tmp16 = BASOP_Util_Divide3232_Scale( 1, numHullVtx, &tmp_e ); // q15-tmp_e
     972        6088 :     tmp32 = L_shl_sat( tmp16, add( Q16, tmp_e ) );                /* Q31 */
     973             : 
     974        6088 :     centroid[0] = Mpy_32_32( centroid[0], tmp32 ); // q27
     975        6088 :     move32();
     976        6088 :     centroid[1] = Mpy_32_32( centroid[1], tmp32 ); // q27
     977        6088 :     move32();
     978        6088 :     centroid[2] = Mpy_32_32( centroid[1], tmp32 ); // q27
     979        6088 :     move32();
     980             : 
     981        6088 :     centroid[0] = L_shl( centroid[0], 4 ); // q31
     982        6088 :     move32();
     983        6088 :     centroid[1] = L_shl( centroid[1], 4 ); // q31
     984        6088 :     move32();
     985        6088 :     centroid[2] = L_shl( centroid[2], 4 ); // q31
     986        6088 :     move32();
     987             : 
     988             :     /* Processing */
     989        6088 :     k = 0;
     990        6088 :     move16();
     991        6088 :     l = 0;
     992        6088 :     move16();
     993             : 
     994       76664 :     FOR( i = 0; i < *szTri; ++i )
     995             :     {
     996       70576 :         tmpDist = vertex_distance_fx( vtxData->vertexArray, triArray[i], vtxIdx ); // Q28
     997       70576 :         IF( GT_32( tmpDist, threshold ) )
     998             :         {
     999       14829 :             visible[k] = i;
    1000       14829 :             move16();
    1001       14829 :             k = add( k, 1 );
    1002             :         }
    1003             :         ELSE
    1004             :         {
    1005       55747 :             Copy( triArray[i].LS, triArrayNew[l].LS, 3 );
    1006       55747 :             l = add( l, 1 );
    1007             :         }
    1008             :     }
    1009             : 
    1010        6088 :     visible_edges_fx( triArray, visible, k, numEdges, edges );
    1011             : 
    1012       33093 :     FOR( i = 0; i < numEdges[0]; i += 2 )
    1013             :     {
    1014       27005 :         surface[0] = edges[i];
    1015       27005 :         move16();
    1016       27005 :         surface[1] = edges[i + 1];
    1017       27005 :         move16();
    1018       27005 :         surface[2] = vtxIdx;
    1019       27005 :         move16();
    1020             : 
    1021       27005 :         flip_plane_fx( vtxData->vertexArray, surface, centroid );
    1022             : 
    1023       27005 :         Copy( surface, triArrayNew[l].LS, 3 );
    1024       27005 :         l = add( l, 1 );
    1025             :     }
    1026             : 
    1027             :     /* Outputs */
    1028       88840 :     FOR( i = 0; i < l; i++ )
    1029             :     {
    1030       82752 :         Copy( triArrayNew[i].LS, triArray[i].LS, 3 );
    1031             :     }
    1032        6088 :     *szTri = l;
    1033        6088 :     move16();
    1034             : 
    1035             :     /* Flag the vertex as added to the hull */
    1036        6088 :     vtxInHull[vtxIdx] = 1;
    1037        6088 :     move16();
    1038        6088 :     return;
    1039             : }
    1040             : 
    1041             : /*-------------------------------------------------------------------------*
    1042             :  * visible_edges()
    1043             :  *
    1044             :  *
    1045             :  *-------------------------------------------------------------------------*/
    1046             : 
    1047        6088 : static void visible_edges_fx(
    1048             :     const EFAP_LS_TRIANGLE *triArray, /* i  : Triangle array       */
    1049             :     const Word16 *visible,            /* i  : Visible surface flag */
    1050             :     const Word16 numSurface,          /* i  : Number of surfaces   */
    1051             :     Word16 *numEdges,                 /* i/o: Number of edges      */
    1052             :     Word16 *edges                     /* i/o: Array of edges       */
    1053             : )
    1054             : {
    1055             :     Word16 maxVertex;
    1056             :     Word16 i, j, k;
    1057             :     Word16 a, b;
    1058             :     Word16 tmpSurface[4];
    1059             :     Word16 counter[EFAP_MAX_SIZE_TMP_BUFF][EFAP_MAX_SIZE_TMP_BUFF];
    1060             :     Word16 counterTranspose[EFAP_MAX_SIZE_TMP_BUFF][EFAP_MAX_SIZE_TMP_BUFF];
    1061             :     Word16 tmpMax[EFAP_MAX_SIZE_TMP_BUFF];
    1062             : 
    1063             :     /* Set counter and counterTranspose to 0 */
    1064      188728 :     FOR( i = 0; i < EFAP_MAX_SIZE_TMP_BUFF; i++ )
    1065             :     {
    1066      182640 :         set16_fx( counter[i], 0, EFAP_MAX_SIZE_TMP_BUFF );
    1067      182640 :         set16_fx( counterTranspose[i], 0, EFAP_MAX_SIZE_TMP_BUFF );
    1068             :     }
    1069             : 
    1070             :     /* Finding the max vertex */
    1071       20917 :     FOR( i = 0; i < numSurface; ++i )
    1072             :     {
    1073       14829 :         tmpMax[i] = triArray[visible[i]].LS[0]; // q0
    1074       14829 :         move16();
    1075       44487 :         FOR( j = 1; j < 3; ++j )
    1076             :         {
    1077       29658 :             if ( LT_16( tmpMax[i], triArray[visible[i]].LS[j] ) )
    1078             :             {
    1079       14994 :                 tmpMax[i] = triArray[visible[i]].LS[j]; // q0
    1080       14994 :                 move16();
    1081             :             }
    1082             :         }
    1083             :     }
    1084        6088 :     maxVertex = tmpMax[maximum_s( tmpMax, numSurface, NULL )];
    1085       20917 :     FOR( i = 0; i < numSurface; ++i )
    1086             :     {
    1087       14829 :         tmpSurface[0] = triArray[visible[i]].LS[0];
    1088       14829 :         move16();
    1089       14829 :         tmpSurface[1] = triArray[visible[i]].LS[1];
    1090       14829 :         move16();
    1091       14829 :         tmpSurface[2] = triArray[visible[i]].LS[2];
    1092       14829 :         move16();
    1093       14829 :         tmpSurface[3] = triArray[visible[i]].LS[0];
    1094       14829 :         move16();
    1095             : 
    1096       59316 :         FOR( j = 0; j < 3; ++j )
    1097             :         {
    1098       44487 :             a = tmpSurface[j];
    1099       44487 :             move16();
    1100       44487 :             b = tmpSurface[j + 1];
    1101       44487 :             move16();
    1102       44487 :             counter[a][b] = add( counter[a][b], 1 );
    1103       44487 :             move16();
    1104       44487 :             counterTranspose[b][a] = counter[a][b];
    1105       44487 :             move16();
    1106             :         }
    1107             :     }
    1108             : 
    1109       76938 :     FOR( i = 0; i < maxVertex + 1; ++i )
    1110             :     {
    1111      958000 :         FOR( j = 0; j < maxVertex + 1; ++j )
    1112             :         {
    1113      887150 :             counter[i][j] = add( counterTranspose[i][j], counterTranspose[j][i] );
    1114      887150 :             move16();
    1115             :         }
    1116             :     }
    1117             : 
    1118             :     /* Finding the edges */
    1119        6088 :     k = 0;
    1120        6088 :     move16();
    1121             : 
    1122       70850 :     FOR( a = 0; a < maxVertex; ++a )
    1123             :     {
    1124      472912 :         FOR( b = a + 1; b < maxVertex + 1; ++b )
    1125             :         {
    1126      408150 :             IF( EQ_16( counter[a][b], 1 ) )
    1127             :             {
    1128       27005 :                 edges[k] = a;
    1129       27005 :                 move16();
    1130       27005 :                 edges[k + 1] = b;
    1131       27005 :                 move16();
    1132       27005 :                 k = add( k, 2 );
    1133             :             }
    1134             :         }
    1135             :     }
    1136             : 
    1137             :     /* Outputs */
    1138        6088 :     *numEdges = k;
    1139        6088 :     move16();
    1140             : 
    1141        6088 :     return;
    1142             : }
    1143             : 
    1144             : /*-------------------------------------------------------------------------* \
    1145             :  * flip_plane()                                                              \
    1146             :  *                                                                           \
    1147             :  *                                                                           \
    1148             :  *-------------------------------------------------------------------------*/
    1149             : 
    1150       30605 : static void flip_plane_fx(
    1151             :     const EFAP_VERTEX *vtxArray, /* i  : Vertex array                                                    */
    1152             :     Word16 *surface,             /* i/o: Surface/vertices to be flipped                                 */
    1153             :     const Word32 centroid[3]     /* i  : Centroid of convex hull from which to orient the planes outward q31*/
    1154             : )
    1155             : {
    1156             :     Word16 tmp;
    1157             :     Word32 dist;
    1158             : 
    1159       30605 :     dist = point_plane_distance_fx(
    1160       30605 :         vtxArray[surface[0]].pos,
    1161       30605 :         vtxArray[surface[1]].pos,
    1162       30605 :         vtxArray[surface[2]].pos,
    1163             :         centroid ); // q31
    1164             : 
    1165       30605 :     IF( dist > 0 )
    1166             :     {
    1167             :         /*efap_flipLeftRight( surface, 3 );*/
    1168       16094 :         tmp = surface[0];
    1169       16094 :         move16();
    1170       16094 :         surface[0] = surface[2];
    1171       16094 :         move16();
    1172       16094 :         surface[2] = tmp;
    1173       16094 :         move16();
    1174             :     }
    1175             : 
    1176       30605 :     return;
    1177             : }
    1178             : 
    1179             : 
    1180             : /*-------------------------------------------------------------------------*
    1181             :  * remap_ghosts()
    1182             :  *
    1183             :  *
    1184             :  *-------------------------------------------------------------------------*/
    1185         900 : static void remap_ghosts_fx(
    1186             :     EFAP_VERTEX *vtxArray,          /* i/o: Vertex array                    */
    1187             :     EFAP_LS_TRIANGLE *triArray,     /* i/o: Triangle array                  */
    1188             :     Word16 numSpk,                  /* i  : Number of speakers              */
    1189             :     Word16 *numVertex,              /* i/o: Size of vertex array            */
    1190             :     Word16 numTri,                  /* i  : Size of triangle array          */
    1191             :     Word32 **downmixMatrixTranspose /* o  : Transpose of downmix matrix Q31 */
    1192             : )
    1193             : {
    1194         900 :     Word16 numGhst = 0;
    1195         900 :     Word16 numVtx = *numVertex;
    1196             :     Word16 numTot;
    1197             :     Word16 g;
    1198             :     Word16 i, j;
    1199             :     Word16 tmpL;
    1200             :     Word32 inv_tmpL;
    1201             :     Word16 posFound[2];
    1202             :     Word16 neighbours[EFAP_MAX_SIZE_TMP_BUFF];
    1203             :     Word32 tmpVec[EFAP_MAX_SIZE_TMP_BUFF];
    1204             :     Word32 tmpVec2[EFAP_MAX_SIZE_TMP_BUFF];
    1205             :     Word32 tmpMat[EFAP_MAX_SIZE_TMP_BUFF][EFAP_MAX_SIZE_TMP_BUFF];    /* Q31 */
    1206             :     Word32 tmpNewMat[EFAP_MAX_SIZE_TMP_BUFF][EFAP_MAX_SIZE_TMP_BUFF]; /* Q31 */
    1207             :     Word32 tmpDist;
    1208             :     Word16 tmpDist_e;
    1209         900 :     const Word32 thresh = 214748; // 1e-4f in Q31
    1210             :     Word16 tmp16, tmp_e;
    1211         900 :     move32();
    1212             : 
    1213         900 :     set32_fx( tmpVec, 0, EFAP_MAX_SIZE_TMP_BUFF );
    1214         900 :     set32_fx( tmpVec2, 0, EFAP_MAX_SIZE_TMP_BUFF );
    1215             : 
    1216             :     /* Finding unused ghosts (i.e. ghost speakers that aren't used for triangulation */
    1217        2920 :     FOR( g = numVtx - 1; g > numSpk - 1; --g )
    1218             :     {
    1219             :         /* find(triangle_mat == ghost, 1, 'first') */
    1220        2020 :         IF( find_int_in_tri_fx( triArray, g, numTri, posFound ) == 0 )
    1221             :         {
    1222           0 :             remove_vertex_fx( vtxArray, g, numVtx );
    1223           0 :             numVtx = sub( numVtx, 1 );
    1224           0 :             FOR( i = 0; i < numTri; ++i )
    1225             :             {
    1226           0 :                 FOR( j = 0; j < 3; ++j )
    1227             :                 {
    1228           0 :                     IF( GT_16( triArray[i].LS[j], g ) )
    1229             :                     {
    1230           0 :                         triArray[i].LS[j] = sub( g, 1 );
    1231           0 :                         move16();
    1232             :                     }
    1233             :                 }
    1234             :             }
    1235             :         }
    1236             :         ELSE
    1237             :         {
    1238        2020 :             numGhst = add( numGhst, 1 );
    1239             :         }
    1240             :     }
    1241             : 
    1242             :     /* Final number of LS (real + ghosts) */
    1243         900 :     numTot = add( numSpk, numGhst );
    1244             : 
    1245             :     /* Initializing tmpMat as the identity matrix */
    1246       10588 :     FOR( i = 0; i < numTot; ++i )
    1247             :     {
    1248        9688 :         set32_fx( tmpMat[i], 0, numTot );
    1249        9688 :         set32_fx( tmpNewMat[i], 0, numTot );
    1250             : 
    1251        9688 :         tmpMat[i][i] = ONE_IN_Q31; // q31
    1252        9688 :         move32();
    1253        9688 :         tmpNewMat[i][i] = ONE_IN_Q31; // q31
    1254        9688 :         move32();
    1255             :     }
    1256             : 
    1257             :     /* Generate initial sound energy distribution matrix */
    1258        2920 :     FOR( i = numSpk; i < numTot; ++i )
    1259             :     {
    1260        2020 :         tmpL = get_neighbours_fx( triArray, i, numTri, neighbours );
    1261             : 
    1262             :         /* Initializing the column to 0 */
    1263       22496 :         FOR( j = 0; j < numTot; ++j )
    1264             :         {
    1265       20476 :             tmpMat[j][i] = 0;
    1266       20476 :             move32();
    1267       20476 :             tmpNewMat[j][i] = 0;
    1268       20476 :             move32();
    1269             :         }
    1270             : 
    1271             :         /* The neighbours are set to 1.0/tmpL */
    1272        2020 :         tmp16 = BASOP_Util_Divide3232_Scale( 1, tmpL, &tmp_e ); // Q=15-tmp_e
    1273        2020 :         inv_tmpL = L_shl_sat( tmp16, add( Q16, tmp_e ) );       /* Q31 */
    1274       11620 :         FOR( j = 0; j < tmpL; ++j )
    1275             :         {
    1276        9600 :             tmpMat[neighbours[j]][i] = inv_tmpL; /* Q31 */
    1277        9600 :             move32();
    1278        9600 :             tmpNewMat[neighbours[j]][i] = inv_tmpL; /* Q31 */
    1279        9600 :             move32();
    1280             :         }
    1281             :     }
    1282             : 
    1283             :     /* Redistributing sound energy */
    1284       10588 :     FOR( i = 0; i < numTot; ++i )
    1285             :     {
    1286      125104 :         FOR( j = 0; j < numTot; ++j )
    1287             :         {
    1288      115416 :             tmpNewMat[i][j] = tmpMat[j][i]; /* Q31 */
    1289      115416 :             move32();
    1290             :         }
    1291             :     }
    1292             : 
    1293        2920 :     FOR( i = numSpk; i < numTot; ++i )
    1294             :     {
    1295        2020 :         Copy32( tmpNewMat[i], tmpVec, numTot ); // q31
    1296             : 
    1297        2020 :         tmpDist_e = 0;
    1298        2020 :         move16();
    1299        2020 :         tmpDist = sum_32_fx( &tmpVec[numSpk], sub( numTot, numSpk ), &tmpDist_e ); // Q=31-tmpDist_e
    1300             : 
    1301       12508 :         WHILE( EQ_16( BASOP_Util_Cmp_Mant32Exp( tmpDist, tmpDist_e, thresh, 0 ), 1 ) )
    1302             :         {
    1303       10488 :             matrix_times_row_fx( tmpMat, tmpVec, numTot, tmpVec2 ); // tmpVec2 Q31
    1304       10488 :             Copy32( tmpVec2, tmpVec, numTot );                      // Q31
    1305       10488 :             set32_fx( tmpVec2, 0, numTot );
    1306       10488 :             tmpDist_e = 0;
    1307       10488 :             move16();
    1308       10488 :             tmpDist = sum_32_fx( &tmpVec[numSpk], sub( numTot, numSpk ), &tmpDist_e );
    1309             :         }
    1310        2020 :         Copy32( tmpVec, tmpNewMat[i], numTot ); // q31
    1311             :     }
    1312             : 
    1313        8568 :     FOR( i = 0; i < numSpk; ++i )
    1314             :     {
    1315             :         /* Applying a sqrt(2) coeff and obtaining the dmMatrix*/
    1316       86994 :         FOR( j = 0; j < numSpk; ++j )
    1317             :         {
    1318       79326 :             test();
    1319       79326 :             IF( tmpNewMat[j][i] == 0 || EQ_32( tmpNewMat[j][i], 0x7fffffff /*q31*/ ) )
    1320             :             {
    1321       79326 :                 downmixMatrixTranspose[j][i] = tmpNewMat[j][i]; /* Q31 */
    1322       79326 :                 move32();
    1323             :             }
    1324             :             ELSE
    1325             :             {
    1326           0 :                 Word16 exp = 0;
    1327           0 :                 move16();
    1328           0 :                 Word32 tmp_sqrt = Sqrt32( tmpNewMat[j][i], &exp ); /*31-exp*/
    1329           0 :                 tmp_sqrt = L_shl( tmp_sqrt, exp );                 /*q31*/
    1330           0 :                 downmixMatrixTranspose[j][i] = tmp_sqrt;           /* Q31 */
    1331           0 :                 move32();
    1332             :             }
    1333             :         }
    1334             :         /* Downmix ghost loudspeakers according to dmxType */
    1335       23282 :         FOR( ; j < numTot; ++j )
    1336             :         {
    1337       15614 :             SWITCH( vtxArray[j].dmxType )
    1338             :             {
    1339          72 :                 case EFAP_DMX_NONE:
    1340          72 :                     downmixMatrixTranspose[j][i] = 0; /* Q31 */
    1341          72 :                     move32();
    1342          72 :                     BREAK;
    1343        1726 :                 case EFAP_DMX_AMPLITUDE:
    1344        1726 :                     downmixMatrixTranspose[j][i] = tmpNewMat[j][i]; /* Q31 */
    1345        1726 :                     move32();
    1346        1726 :                     BREAK;
    1347       13816 :                 case EFAP_DMX_INTENSITY:
    1348             :                 default:
    1349       13816 :                     test();
    1350       13816 :                     IF( tmpNewMat[j][i] == 0 || EQ_32( tmpNewMat[j][i], ONE_IN_Q31 /*q31*/ ) )
    1351             :                     {
    1352        6264 :                         downmixMatrixTranspose[j][i] = tmpNewMat[j][i]; /* Q31 */
    1353        6264 :                         move32();
    1354             :                     }
    1355             :                     ELSE
    1356             :                     {
    1357        7552 :                         Word16 exp = 0;
    1358        7552 :                         move16();
    1359        7552 :                         Word32 tmp_sqrt = Sqrt32( tmpNewMat[j][i], &exp ); /*31-exp*/
    1360        7552 :                         tmp_sqrt = L_shl( tmp_sqrt, exp );                 /*31*/
    1361        7552 :                         downmixMatrixTranspose[j][i] = tmp_sqrt;           /* Q31 */
    1362        7552 :                         move32();
    1363             :                     }
    1364       13816 :                     BREAK;
    1365             :             }
    1366             :         }
    1367             :     }
    1368             : 
    1369             :     /* Output */
    1370         900 :     *numVertex = numTot;
    1371         900 :     move16();
    1372             : 
    1373         900 :     return;
    1374             : }
    1375             : 
    1376             : /*-------------------------------------------------------------------------*
    1377             :  * vertex_init_fx()
    1378             :  *
    1379             :  * Initialize the vertex structures
    1380             :  *-------------------------------------------------------------------------*/
    1381             : 
    1382         900 : static void vertex_init_fx(
    1383             :     const Word32 *aziSpk,         /* i  : Azimuths of the LS setup q22               */
    1384             :     const Word32 *eleSpk,         /* i  : Elevations of the LS setup q22             */
    1385             :     EFAP_VERTEX_DATA *efapVtxData /* i/o: Vertex data structure that will be updated */
    1386             : )
    1387             : {
    1388             :     Word16 i;
    1389             : 
    1390             :     /* Main Processing */
    1391        8568 :     FOR( i = 0; i < efapVtxData->numVtx; i++ )
    1392             :     {
    1393        7668 :         add_vertex_fx( efapVtxData->vertexArray, aziSpk[i], eleSpk[i], i, EFAP_DMX_INTENSITY );
    1394             :     }
    1395             : 
    1396         900 :     return;
    1397             : }
    1398             : 
    1399             : /*-------------------------------------------------------------------------*
    1400             :  * efap_panning_fx()
    1401             :  *
    1402             :  * Compute the gain without applying the downmix Matrix and the norm of the array
    1403             :  *-------------------------------------------------------------------------*/
    1404             : 
    1405      762315 : static void efap_panning_fx(
    1406             :     const Word32 azi,                  /* i  : Value of the azimuth q22                                   */
    1407             :     const Word32 ele,                  /* i  : Value of the elevation q22                                 */
    1408             :     const EFAP_POLYSET_DATA *polyData, /* i  : Polygon data                                               */
    1409             :     Word32 *bufferL                    /* o  : 1D array of length numSpk that will contain the tmp values q31*/
    1410             : )
    1411             : {
    1412             :     Word16 i;
    1413             :     Word16 polyIdx;
    1414             :     Word16 numChan;
    1415             :     Word16 chan[EFAP_MAX_CHAN_NUM];
    1416             :     Word32 aziPoly[EFAP_MAX_CHAN_NUM];
    1417             :     Word32 elePoly[EFAP_MAX_CHAN_NUM];
    1418             :     Word32 tmpBuff[EFAP_MAX_CHAN_NUM];
    1419             :     Word32 normTmpBuff;
    1420             :     Word32 P[2];
    1421             : 
    1422      762315 :     P[0] = azi; // q22
    1423      762315 :     move32();
    1424      762315 :     P[1] = ele; // q22
    1425      762315 :     move32();
    1426      762315 :     set32_fx( tmpBuff, 0, EFAP_MAX_CHAN_NUM );
    1427      762315 :     set32_fx( aziPoly, 0, EFAP_MAX_CHAN_NUM );
    1428      762315 :     set32_fx( elePoly, 0, EFAP_MAX_CHAN_NUM );
    1429      762315 :     set16_fx( chan, 0, EFAP_MAX_CHAN_NUM );
    1430             : 
    1431             :     /* Finding in which polygon the point is */
    1432      762315 :     polyIdx = get_poly_num_fx( P, polyData );
    1433             : 
    1434      762315 :     assert( polyIdx != -1 && "EFAP: polygon not found!" );
    1435             : 
    1436             :     /* Extracting the chan, the azimuth and the ele of the considered poly */
    1437      762315 :     numChan = polyData->polysetArray[polyIdx].numChan;
    1438      762315 :     move16();
    1439             : 
    1440     3098302 :     FOR( i = 0; i < numChan; ++i )
    1441             :     {
    1442     2335987 :         chan[i] = polyData->polysetArray[polyIdx].chan[i];
    1443     2335987 :         move16();
    1444     2335987 :         aziPoly[i] = polyData->polysetArray[polyIdx].polyAzi[i]; // q22
    1445     2335987 :         move32();
    1446             : 
    1447     2335987 :         if ( EQ_16( polyData->polysetArray[polyIdx].isNaN[i], 1 ) )
    1448             :         {
    1449      617266 :             aziPoly[i] = P[0]; // q22
    1450      617266 :             move32();
    1451             :         }
    1452             : 
    1453     2335987 :         elePoly[i] = polyData->polysetArray[polyIdx].polyEle[i]; // q22
    1454     2335987 :         move32();
    1455             :     }
    1456             : 
    1457             :     /* Computing the gain for the polygon */
    1458      762315 :     get_poly_gains_fx( P[0], P[1], aziPoly, elePoly, numChan, tmpBuff ); // tmpBuff q31
    1459             : 
    1460             :     /* Computing the norm of the tmp buffer */
    1461             :     Word64 suma;
    1462      762315 :     suma = Mpy_32_32( tmpBuff[0], tmpBuff[0] );
    1463     2335987 :     FOR( i = 1; i < numChan; i++ )
    1464             :     {
    1465     1573672 :         suma = W_add( suma, Mpy_32_32( tmpBuff[i], tmpBuff[i] ) );
    1466             :     }
    1467      762315 :     IF( GT_64( suma, MAX_32 ) )
    1468             :     {
    1469           0 :         normTmpBuff = MAX_32;
    1470           0 :         move32();
    1471             :     }
    1472             :     ELSE
    1473             :     {
    1474      762315 :         normTmpBuff = W_extract_l( suma ); // Q31
    1475             :     }
    1476             : 
    1477      762315 :     Word16 exp = 0;
    1478      762315 :     move16();
    1479      762315 :     normTmpBuff = ISqrt32( normTmpBuff, &exp ); // Q=31-exp
    1480             : 
    1481             :     /* Updating the buffer structure */
    1482     3098302 :     FOR( i = 0; i < numChan; ++i )
    1483             :     {
    1484     2335987 :         bufferL[chan[i]] = Mpy_32_32( tmpBuff[i], normTmpBuff ); // 31+(31-exp)-31=>31-exp
    1485     2335987 :         move32();
    1486     2335987 :         bufferL[chan[i]] = L_shl( bufferL[chan[i]], exp ); // Q31
    1487     2335987 :         move32();
    1488             :     }
    1489             : 
    1490      762315 :     return;
    1491             : }
    1492             : 
    1493             : 
    1494             : /*-------------------------------------------------------------------------*
    1495             :  * get_poly_gains_fx()
    1496             :  *
    1497             :  * Compute the gain for a precise polygon
    1498             :  *-------------------------------------------------------------------------*/
    1499             : 
    1500      762315 : static void get_poly_gains_fx(
    1501             :     const Word32 azi,                        /* i  : Value of the azimuth q22                                   */
    1502             :     const Word32 ele,                        /* i  : Value of the elevation q22                                 */
    1503             :     const Word32 aziPoly[EFAP_MAX_CHAN_NUM], /* i  : Azimuths of the considered polygons q22                    */
    1504             :     const Word32 elePoly[EFAP_MAX_CHAN_NUM], /* i  : Elevations of the considered polygons q22                  */
    1505             :     const Word16 numChan,                    /* i  : Length of aziPoly & elePoly                                */
    1506             :     Word32 *buffer                           /* o  : 1D array of length numSpk that will contain the tmp values q31*/
    1507             : )
    1508             : {
    1509             :     Word16 i, j;
    1510             :     Word16 idx1, idx2;
    1511             :     Word32 P[2];
    1512             :     Word32 A[2], B[2], C[2];
    1513             :     Word32 P_minus_A[2];
    1514             : 
    1515      762315 :     P[0] = azi; // q22
    1516      762315 :     move32();
    1517      762315 :     P[1] = ele; // q22
    1518      762315 :     move32();
    1519             : 
    1520             :     /* Processing, we search for the triangle in which belong P, then we compute the gain */
    1521     3098302 :     FOR( i = 1; i < numChan + 1; ++i )
    1522             :     {
    1523     2335987 :         A[0] = aziPoly[i - 1]; // q22
    1524     2335987 :         move32();
    1525     2335987 :         A[1] = elePoly[i - 1]; // q22
    1526     2335987 :         move32();
    1527             : 
    1528             : #ifdef VEC_ARITH_OPT_v1
    1529     2335987 :         v_sub_fixed_no_hdrm( P, A, P_minus_A, 2 ); /* Precalculate value of (P-A) q22*/
    1530             : #else                                              /* VEC_ARITH_OPT_v1 */
    1531             :         v_sub_fixed( P, A, P_minus_A, 2, 0 ); /* Precalculate value of (P-A) q22*/
    1532             : #endif                                             /* VEC_ARITH_OPT_v1 */
    1533             : 
    1534     2433866 :         FOR( j = i; j < numChan - 2 + i; ++j )
    1535             :         {
    1536     2433844 :             idx1 = add( 1, ( j % numChan ) );
    1537     2433844 :             idx2 = add( 1, ( idx1 % numChan ) );
    1538             : 
    1539     2433844 :             B[0] = aziPoly[idx1 - 1]; // q22
    1540     2433844 :             move32();
    1541     2433844 :             B[1] = elePoly[idx1 - 1]; // q22
    1542     2433844 :             move32();
    1543             : 
    1544     2433844 :             C[0] = aziPoly[idx2 - 1]; // q22
    1545     2433844 :             move32();
    1546     2433844 :             C[1] = elePoly[idx2 - 1]; // q22
    1547     2433844 :             move32();
    1548             : 
    1549     2433844 :             IF( in_tri_fx( A, B, C, P_minus_A ) )
    1550             :             {
    1551     2335965 :                 buffer[i - 1] = L_shl_sat( get_tri_gain_fx( A, B, C, P_minus_A ), Q18 ); // q13+q18->q31
    1552     2335965 :                 move32();
    1553     2335965 :                 BREAK;
    1554             :             }
    1555             :         }
    1556             :     }
    1557             : 
    1558      762315 :     return;
    1559             : }
    1560             : 
    1561             : /*-------------------------------------------------------------------------*
    1562             :  * get_tri_gain_fx()
    1563             :  *
    1564             :  * Compute the value of the gain for a given triangle
    1565             :  *-------------------------------------------------------------------------*/
    1566             : 
    1567     2335965 : static Word32 get_tri_gain_fx(
    1568             :     const Word32 A[2],        /* i  : Coordinate of one apex of the triangle q22*/
    1569             :     const Word32 B[2],        /* i  : Coordinate of one apex of the triangle q22*/
    1570             :     const Word32 C[2],        /* i  : Coordinate of one apex of the triangle q22*/
    1571             :     const Word32 P_minus_A[2] /* i  : Value of (P - A) q22                      */
    1572             : )
    1573             : {
    1574             :     Word32 N[2], tmpN[2];
    1575             :     Word32 tmpSub1[2];
    1576             :     Word32 tmpDot1, tmpDot2;
    1577             :     Word32 gain;
    1578             : 
    1579             :     /* Processing */
    1580     2335965 :     tmpN[0] = L_sub( B[1], C[1] ); // q22
    1581     2335965 :     move32();
    1582     2335965 :     tmpN[1] = L_sub( C[0], B[0] ); // q22
    1583     2335965 :     move32();
    1584             : 
    1585             : #ifdef VEC_ARITH_OPT_v1
    1586     2335965 :     v_sub_fixed_no_hdrm( B, A, tmpSub1, 2 ); // tmpSub1 q22
    1587             : #else                                        /* VEC_ARITH_OPT_v1 */
    1588             :     v_sub_fixed( B, A, tmpSub1, 2, 0 );       // tmpSub1 q22
    1589             : #endif                                       /* VEC_ARITH_OPT_v1 */
    1590             : 
    1591     2335965 :     tmpDot1 = dotp_fixed( tmpN, tmpSub1, 2 ); // Q13
    1592             : 
    1593     2335965 :     Word16 exp = Q18;
    1594     2335965 :     move16();
    1595     2335965 :     Word32 inv_tmpDot2 = L_shl( tmpDot1, norm_l( tmpDot1 ) );
    1596     2335965 :     exp = sub( exp, norm_l( tmpDot1 ) );
    1597     2335965 :     Word16 inv_tmpDot1 = Inv16( extract_h( inv_tmpDot2 ), &exp );       // 15-exp
    1598     2335965 :     v_multc_fixed( tmpN, L_shl( inv_tmpDot1, add( Q16, exp ) ), N, 2 ); // 22+31-31->22
    1599             : 
    1600     2335965 :     tmpDot2 = dotp_fixed( P_minus_A, N, 2 ); // 22+22-31->13
    1601             : 
    1602     2335965 :     if ( EQ_32( tmpDot2, 8191 ) )
    1603             :     {
    1604      141064 :         tmpDot2 = 8192; // Q13
    1605      141064 :         move32();
    1606             :     }
    1607             : 
    1608     2335965 :     gain = L_sub( 8192, tmpDot2 ); // Q13
    1609             :     /* Set gains <= -60dB to 0 to avoid problems in SVD */
    1610     2335965 :     if ( EQ_16( BASOP_Util_Cmp_Mant32Exp( L_abs( gain ), 18, 2147 /*1e-6 q31*/, 0 ), -1 ) )
    1611             :     {
    1612      364209 :         gain = 0;
    1613      364209 :         move32();
    1614             :     }
    1615     2335965 :     return gain; // Q13
    1616             : }
    1617             : 
    1618             : 
    1619             : /*-------------------------------------------------------------------------*
    1620             :  * add_vertex_fx()
    1621             :  *
    1622             :  * Add a vertex to the vertex array
    1623             :  *-------------------------------------------------------------------------*/
    1624             : 
    1625        9688 : static void add_vertex_fx(
    1626             :     EFAP_VERTEX *vtxArray,          /* i/o: Handle to the vertex array that will be updated       */
    1627             :     const Word32 azi,               /* i  : Azimuth of the vertex Q22                             */
    1628             :     const Word32 ele,               /* i  : Elevation of the vertex Q22                           */
    1629             :     const Word16 pos,               /* i  : Index in the vtxArray where we want to add the vertex */
    1630             :     const EFAP_VTX_DMX_TYPE dmxType /* i  : downmix type for the vertex                           */
    1631             : )
    1632             : {
    1633             :     Word32 idxAziTmp, idxEleTmp;
    1634             :     Word32 tmp;
    1635             : 
    1636        9688 :     assert( vtxArray != NULL && "EFAP: vtxArray == NULL" );
    1637             : 
    1638             :     /* Updating the vertex array */
    1639             : 
    1640        9688 :     tmp = efap_32mod32( L_sub( Q22_180_DEG /*180 q22*/, azi ), Q22_360_DEG /*360 q22*/ ); // q22
    1641        9688 :     vtxArray[pos].azi = L_sub( Q22_180_DEG /*180 q22*/, tmp );                            // q22
    1642        9688 :     move32();
    1643             : 
    1644        9688 :     IF( LT_32( Q22_180_DEG /*180 q22*/, ele ) )
    1645           0 :     tmp = Q22_180_DEG /*180 q22*/;
    1646             :     ELSE
    1647        9688 :         tmp = ele; // Q22
    1648        9688 :     move32();
    1649        9688 :     IF( GT_32( -Q22_180_DEG /*180 q22*/, tmp ) )
    1650           0 :     vtxArray[pos].ele = -Q22_180_DEG /*180 q22*/;
    1651             :     ELSE
    1652        9688 :         vtxArray[pos]
    1653        9688 :             .ele = tmp; // q22
    1654        9688 :     move32();
    1655             : 
    1656             :     /* Converting spherical coordinates to cartesians, assuming radius = 1 */
    1657        9688 :     sph2cart_fx( vtxArray[pos].azi, vtxArray[pos].ele, &vtxArray[pos].pos[0] ); // vtxArray[pos].pos[0] q31
    1658             : 
    1659             :     /* Computing the index defined by idx = idxAziTmp + 181 * idxEleTmp  */
    1660             : 
    1661             :     /* IdxAziTmp */
    1662        9688 :     tmp = L_abs( L_sub( Q22_90_DEG /*90 q22*/, L_abs( vtxArray[pos].azi ) ) ); // Q22
    1663        9688 :     idxAziTmp = L_shr( anint_fixed( tmp, Q22 ), Q22 );                         // q22-q22->q0
    1664             : 
    1665             :     /* IdxEleTmp */
    1666        9688 :     tmp = L_abs( vtxArray[pos].ele ); // q22
    1667        9688 :     idxEleTmp = tmp;                  // q22
    1668        9688 :     move16();
    1669        9688 :     idxEleTmp = L_sub( Q22_90_DEG /*90 q22*/, idxEleTmp ); // q22
    1670             : 
    1671             :     /* Final Idx */
    1672        9688 :     vtxArray[pos].idx = add( extract_l( idxAziTmp ), i_mult( 181, extract_l( L_shr( idxEleTmp, Q22 ) ) ) ); // q0
    1673             : 
    1674             :     /* Setting the nan flag to 0 */
    1675        9688 :     vtxArray[pos].isNaN = 0;
    1676        9688 :     move16();
    1677             : 
    1678             :     /* Set the default downmix type */
    1679        9688 :     vtxArray[pos].dmxType = dmxType;
    1680        9688 :     move32();
    1681             : 
    1682        9688 :     return;
    1683             : }
    1684             : 
    1685             : 
    1686             : /*-------------------------------------------------------------------------*
    1687             :  * efap_sort_s()
    1688             :  *
    1689             :  * Sort an integer array
    1690             :  * (modified version of sort() to return an index array)
    1691             :  *-------------------------------------------------------------------------*/
    1692             : 
    1693        2920 : static void efap_sort_s_fx(
    1694             :     Word16 *x,       /* i/o: Vector to be sorted      */
    1695             :     Word16 *idx,     /* o  : Original index positions */
    1696             :     const Word16 len /* i  : vector length            */
    1697             : )
    1698             : {
    1699             :     Word16 i, j;
    1700             :     Word16 tempr, tempi;
    1701             : 
    1702       41408 :     FOR( i = 0; i < len; i++ )
    1703             :     {
    1704       38488 :         idx[i] = i;
    1705       38488 :         move16();
    1706             :     }
    1707             : 
    1708       38488 :     FOR( i = len - 2; i >= 0; i-- )
    1709             :     {
    1710       35568 :         tempr = x[i];
    1711       35568 :         move16();
    1712       35568 :         tempi = idx[i];
    1713       35568 :         move16();
    1714       35568 :         test();
    1715      150053 :         FOR( j = i + 1; ( j < len ) && ( tempr > x[j] ); j++ )
    1716             :         {
    1717      114485 :             test();
    1718      114485 :             x[j - 1] = x[j];
    1719      114485 :             move16();
    1720      114485 :             idx[j - 1] = idx[j];
    1721      114485 :             move16();
    1722             :         }
    1723       35568 :         x[j - 1] = tempr;
    1724       35568 :         move16();
    1725       35568 :         idx[j - 1] = tempi;
    1726       35568 :         move16();
    1727             :     }
    1728             : 
    1729        2920 :     return;
    1730             : }
    1731             : 
    1732             : 
    1733             : /*-------------------------------------------------------------------------*
    1734             :  * vertex_distance()
    1735             :  *
    1736             :  * Compute the signed distance between a vertex and a hull surface
    1737             :  *-------------------------------------------------------------------------*/
    1738             : 
    1739       70576 : static Word32 vertex_distance_fx(
    1740             :     const EFAP_VERTEX *vtxArray, /* i  : The considered vertex          */
    1741             :     const EFAP_LS_TRIANGLE tri,  /* i  : The considered triangle        */
    1742             :     const Word16 vtxIdx          /* i  : Index of the considered vertex */
    1743             : )
    1744             : {
    1745             :     Word32 A[3], B[3], C[3], P[3];
    1746             :     Word16 i;
    1747             : 
    1748             :     /* Assigning the coordinates to the vector */
    1749      282304 :     FOR( i = 0; i < 3; ++i )
    1750             :     {
    1751      211728 :         A[i] = vtxArray[tri.LS[0]].pos[i]; // q31
    1752      211728 :         move32();
    1753      211728 :         B[i] = vtxArray[tri.LS[1]].pos[i]; // q31
    1754      211728 :         move32();
    1755      211728 :         C[i] = vtxArray[tri.LS[2]].pos[i]; // q31
    1756      211728 :         move32();
    1757             : 
    1758      211728 :         P[i] = vtxArray[vtxIdx].pos[i]; // q31
    1759      211728 :         move32();
    1760             :     }
    1761             : 
    1762       70576 :     return point_plane_distance_fx( A, B, C, P ); // q28
    1763             : }
    1764             : 
    1765             : 
    1766             : /*-------------------------------------------------------------------------*
    1767             :  * point_poly_distance_fx()
    1768             :  *
    1769             :  * Compute the signed distance between a point and polygon
    1770             :  *-------------------------------------------------------------------------*/
    1771             : 
    1772     1838303 : static Word32 point_poly_distance_fx(
    1773             :     const EFAP_POLYSET poly, /* i  : The polygon which forms a plane                */
    1774             :     const Word32 X[3]        /* i  : Cartesian coordinates of the point of interest q31*/
    1775             : )
    1776             : {
    1777             :     Word32 P1[3], P2[3], P3[3];
    1778             : 
    1779     1838303 :     sph2cart_fx( poly.polyAzi[0], poly.polyEle[0], &P1[0] ); // P1[0] q31
    1780     1838303 :     sph2cart_fx( poly.polyAzi[1], poly.polyEle[1], &P2[0] ); // P2[0] q31
    1781     1838303 :     sph2cart_fx( poly.polyAzi[2], poly.polyEle[2], &P3[0] ); // P3[0] q31
    1782             : 
    1783     1838303 :     return point_plane_distance_fx( P1, P2, P3, X ); // q28
    1784             : }
    1785             : 
    1786             : /*-------------------------------------------------------------------------*
    1787             :  * point_plane_distance_fx()
    1788             :  *
    1789             :  * Compute the signed distance between a point and a given plane
    1790             :  *-------------------------------------------------------------------------*/
    1791             : 
    1792     2131564 : static Word32 point_plane_distance_fx( // returns output in Q28
    1793             :     const Word32 P1[3],                /* i  : First point of the triangle that defines the planes q31*/
    1794             :     const Word32 P2[3],                /* i  : Second point of the triangle                        q31*/
    1795             :     const Word32 P3[3],                /* i  : Third point of the triangle                         q31*/
    1796             :     const Word32 X[3]                  /* i  : The point of interest                               q31*/
    1797             : )
    1798             : {
    1799             :     Word32 tmpCross1[3], tmpCross2[3];
    1800             :     Word32 resultCross[3];
    1801             :     Word32 tmpDot1[3], tmpDot2[3];
    1802             :     Word32 tmpNorm;
    1803             :     Word32 dist;
    1804             : 
    1805             :     /* Check if the point already matches a triangle vertex */
    1806     2131564 :     test();
    1807     2131564 :     test();
    1808     2131564 :     test();
    1809     2131564 :     test();
    1810     2131564 :     test();
    1811     2131564 :     test();
    1812     2131564 :     test();
    1813     2131564 :     test();
    1814     2131564 :     IF( ( EQ_32( X[0], P1[0] ) && EQ_32( X[1], P1[1] ) && EQ_32( X[2], P1[2] ) ) ||
    1815             :         ( EQ_32( X[0], P2[0] ) && EQ_32( X[1], P2[1] ) && EQ_32( X[2], P2[2] ) ) ||
    1816             :         ( EQ_32( X[0], P3[0] ) && EQ_32( X[1], P3[1] ) && EQ_32( X[2], P3[2] ) ) )
    1817             :     {
    1818       62656 :         return 0;
    1819             :     }
    1820             : 
    1821             :     /* Cross Product */
    1822     2068908 :     v_sub_fixed( P1, P2, tmpCross1, 3, 1 ); // tmpCross1 q30
    1823     2068908 :     v_sub_fixed( P1, P3, tmpCross2, 3, 1 ); // tmpCross2 q30
    1824             : 
    1825             :     /* resultCross = cross(P1-P2,P1-P3) */
    1826     2068908 :     efap_crossp_fx( tmpCross1, tmpCross2, resultCross ); // Q29
    1827             : 
    1828             :     /* Dot Product */
    1829     2068908 :     tmpNorm = dotp_fixed( resultCross, resultCross, 3 ); // Q27
    1830     2068908 :     Word16 exp = 4;
    1831     2068908 :     move16();
    1832     2068908 :     tmpNorm = ISqrt32( tmpNorm, &exp );                     // Q29
    1833     2068908 :     v_sub_fixed( X, P1, tmpDot1, 3, 1 );                    // Q30
    1834     2068908 :     v_multc_fixed( resultCross, tmpNorm, tmpDot2, 3 );      // Q29 - exp
    1835     2068908 :     dist = L_shl( dotp_fixed( tmpDot1, tmpDot2, 3 ), exp ); // Q28
    1836     2068908 :     return dist;
    1837             : }
    1838             : 
    1839             : 
    1840             : /*-------------------------------------------------------------------------*
    1841             :  * efap_crossp_fx()
    1842             :  *
    1843             :  * Compute the cross product between column vectors of float of size 3x1
    1844             :  *-------------------------------------------------------------------------*/
    1845             : 
    1846     2069808 : static void efap_crossp_fx(
    1847             :     const Word32 *v1, /* i  : First float vector  Q30 */
    1848             :     const Word32 *v2, /* i  : Second float vector Q30 */
    1849             :     Word32 *v         /* o  : Output vector       Q29 */
    1850             : )
    1851             : {
    1852     2069808 :     v[0] = L_sub( Mpy_32_32( v1[1], v2[2] ), Mpy_32_32( v1[2], v2[1] ) ); /* Q29 */
    1853     2069808 :     move32();
    1854     2069808 :     v[1] = L_sub( Mpy_32_32( v1[2], v2[0] ), Mpy_32_32( v1[0], v2[2] ) ); /* Q29 */
    1855     2069808 :     move32();
    1856     2069808 :     v[2] = L_sub( Mpy_32_32( v1[0], v2[1] ), Mpy_32_32( v1[1], v2[0] ) ); /* Q29 */
    1857     2069808 :     move32();
    1858             : 
    1859     2069808 :     return;
    1860             : }
    1861             : 
    1862             : /*-------------------------------------------------------------------------*
    1863             :  * find_int_in_tri()
    1864             :  *
    1865             :  * Find an integer in triangle array of integers
    1866             :  *-------------------------------------------------------------------------*/
    1867             : 
    1868       13640 : static Word16 find_int_in_tri_fx(
    1869             :     const EFAP_LS_TRIANGLE *tri, /* i  : Triangle array          */
    1870             :     const Word16 n,              /* i  : The integer to find     */
    1871             :     const Word16 r,              /* i  : Number of rows          */
    1872             :     Word16 *pos                  /* o  : Position of the integer */
    1873             : )
    1874             : {
    1875             :     Word16 i, j;
    1876             : 
    1877             :     /* Find the first element equal to n */
    1878      121176 :     FOR( i = 0; i < r; ++i )
    1879             :     {
    1880      453947 :         FOR( j = 0; j < 3; ++j )
    1881             :         {
    1882      346411 :             IF( EQ_16( tri[i].LS[j], n ) )
    1883             :             {
    1884       11620 :                 pos[0] = i;
    1885       11620 :                 move16();
    1886       11620 :                 pos[1] = j;
    1887       11620 :                 move16();
    1888       11620 :                 return 1;
    1889             :             }
    1890             :         }
    1891             :     }
    1892             : 
    1893        2020 :     return 0;
    1894             : }
    1895             : 
    1896             : /*-------------------------------------------------------------------------*
    1897             :  * remove_vertex()
    1898             :  *
    1899             :  * Remove a vertex from a vertex structure
    1900             :  *-------------------------------------------------------------------------*/
    1901           0 : static void remove_vertex_fx(
    1902             :     EFAP_VERTEX *vtxArray, /* i  : Vertex array                  */
    1903             :     const Word16 idx,      /* i  : Index of the vertex to remove */
    1904             :     const Word16 L         /* i  : Length of the Vertex array    */
    1905             : )
    1906             : {
    1907             :     Word16 i;
    1908             : 
    1909           0 :     assert( idx < L && "EFAP: index out of bounds" );
    1910             : 
    1911             :     /* Shift all vertex of one position, so vtxArray[i] will be vtxArray[i+1] and so on */
    1912           0 :     FOR( i = idx; i < L - 1; ++i )
    1913             :     {
    1914           0 :         add_vertex_fx( vtxArray, vtxArray[i + 1].azi, vtxArray[i + 1].ele, i, EFAP_DMX_INTENSITY );
    1915             :     }
    1916             : 
    1917             :     /* The last vertex is set to 0 */
    1918           0 :     add_vertex_fx( vtxArray, 0, 0, sub( L, 1 ), EFAP_DMX_INTENSITY );
    1919             : 
    1920           0 :     return;
    1921             : }
    1922             : 
    1923             : 
    1924             : /*-------------------------------------------------------------------------*
    1925             :  * get_neighbours()
    1926             :  *
    1927             :  * Returns the neighbouring triangles of a vertex
    1928             :  *-------------------------------------------------------------------------*/
    1929        2020 : static Word16 get_neighbours_fx(
    1930             :     const EFAP_LS_TRIANGLE *triArray, /* i  : Triangle array      */
    1931             :     const Word16 vtxIdx,              /* i  : Index of the vertex */
    1932             :     const Word16 numTri,              /* i  : Number of Triangles */
    1933             :     Word16 *neighbours                /* o  : Output vector       */
    1934             : )
    1935             : {
    1936             :     Word16 i, j, k;
    1937             :     Word16 tmpPos[2];
    1938             :     Word16 tmpNeighbours[EFAP_MAX_SIZE_TMP_BUFF];
    1939             :     Word16 dummy[EFAP_MAX_SIZE_TMP_BUFF];
    1940             :     EFAP_LS_TRIANGLE tmpTriArray[EFAP_MAX_POLY_SET];
    1941             : 
    1942             :     /* Processing */
    1943       34892 :     FOR( i = 0; i < numTri; ++i )
    1944             :     {
    1945       32872 :         Copy( triArray[i].LS, tmpTriArray[i].LS, 3 );
    1946             :     }
    1947             : 
    1948        2020 :     k = 0;
    1949        2020 :     move16();
    1950             :     WHILE( 1 )
    1951             :     {
    1952       11620 :         IF( find_int_in_tri_fx( tmpTriArray, vtxIdx, numTri, tmpPos ) == 0 )
    1953             :         {
    1954        2020 :             BREAK;
    1955             :         }
    1956             :         ELSE
    1957             :         {
    1958        9600 :             tmpNeighbours[k] = tmpTriArray[tmpPos[0]].LS[0];
    1959        9600 :             move16();
    1960        9600 :             tmpNeighbours[k + 1] = tmpTriArray[tmpPos[0]].LS[1];
    1961        9600 :             move16();
    1962        9600 :             tmpNeighbours[k + 2] = tmpTriArray[tmpPos[0]].LS[2];
    1963        9600 :             move16();
    1964        9600 :             k = add( k, 3 );
    1965        9600 :             tmpTriArray[tmpPos[0]].LS[tmpPos[1]] = -1;
    1966        9600 :             move16();
    1967             :         }
    1968             : 
    1969        9600 :         IF( GT_16( k, i_mult( 3, numTri ) ) )
    1970             :         {
    1971           0 :             BREAK;
    1972             :         }
    1973             :     }
    1974             : 
    1975             :     /* Sorting the neighbours vector */
    1976        2020 :     efap_sort_s_fx( tmpNeighbours, dummy, k );
    1977             : 
    1978             :     /* Creating the output vector, by eliminating redundancies and also deleting the indice == vtxIdx*/
    1979        2020 :     neighbours[0] = tmpNeighbours[0];
    1980        2020 :     move16();
    1981        2020 :     j = 1;
    1982        2020 :     move16();
    1983             : 
    1984       28800 :     FOR( i = 1; i < k; ++i )
    1985             :     {
    1986       26780 :         test();
    1987       26780 :         IF( NE_16( tmpNeighbours[i], tmpNeighbours[i - 1] ) &&
    1988             :             NE_16( tmpNeighbours[i], vtxIdx ) )
    1989             :         {
    1990        7580 :             neighbours[j] = tmpNeighbours[i];
    1991        7580 :             move16();
    1992        7580 :             j = add( j, 1 );
    1993             :         }
    1994             :     }
    1995             : 
    1996             :     /* Output, length of neighbours */
    1997        2020 :     return j;
    1998             : }
    1999             : 
    2000             : /*-------------------------------------------------------------------------*
    2001             :  * matrix_times_row_fx()
    2002             :  *
    2003             :  * Computes the product of a matrix and a row vector
    2004             :  *-------------------------------------------------------------------------*/
    2005             : 
    2006       10488 : static void matrix_times_row_fx(
    2007             :     Word32 mat[EFAP_MAX_SIZE_TMP_BUFF][EFAP_MAX_SIZE_TMP_BUFF], /* i  : The input matrix q31 */
    2008             :     const Word32 *vec,                                          /* i  : The input row vector q31*/
    2009             :     const Word16 L,                                             /* i  : Row length           */
    2010             :     Word32 *out                                                 /* o  : Output vector q31    */
    2011             : )
    2012             : {
    2013             :     Word16 i, j;
    2014             : 
    2015       62928 :     FOR( i = 0; i < L; ++i )
    2016             :     {
    2017      314640 :         FOR( j = 0; j < L; ++j )
    2018             :         {
    2019      262200 :             out[i] = L_add( out[i], Mpy_32_32( mat[i][j], vec[j] ) ); /*31+31-31=>31*/
    2020      262200 :             move32();
    2021             :         }
    2022             :     }
    2023             : 
    2024       10488 :     return;
    2025             : }
    2026             : 
    2027             : /*-------------------------------------------------------------------------*
    2028             :  * tri_to_poly()
    2029             :  *
    2030             :  * Combines triangles of a surface in order to create polygons
    2031             :  *-------------------------------------------------------------------------*/
    2032             : 
    2033         900 : static void tri_to_poly_fx(
    2034             :     const EFAP_VERTEX *vtxArray,                             /* i  : Vertex array                                                                          */
    2035             :     const EFAP_LS_TRIANGLE *triArray,                        /* i  : Triangle array                                                                        */
    2036             :     const Word16 numVtx,                                     /* i  : Number of vertices                                                                   */
    2037             :     const Word16 numTri,                                     /* i  : Number of triangles                                                                   */
    2038             :     Word16 sortedChan[EFAP_MAX_POLY_SET][EFAP_MAX_CHAN_NUM], /* o  : The matrix that will contain the sorted channels                                      */
    2039             :     Word16 *outLengthPS,                                     /* o  : The length of the sorted channels                                                     */
    2040             :     Word16 outLengthSorted[EFAP_MAX_POLY_SET]                /* o  : The number of channels for each poly (i.e. outLengthSorted[i] = length(sortedChan[i]) */
    2041             : )
    2042             : {
    2043             :     Word16 i, j;
    2044             :     Word16 lenPoly;
    2045             :     Word16 lenPolySet;
    2046             :     Word16 found;
    2047             :     Word16 replaceIdx;
    2048             : 
    2049             :     Word16 poly[EFAP_MAX_CHAN_NUM];
    2050             : 
    2051             :     Word16 sortedLengths[EFAP_MAX_POLY_SET];
    2052             :     Word16 sortedTri[EFAP_MAX_POLY_SET];
    2053             : 
    2054             :     Word32 dist;
    2055             : 
    2056         900 :     lenPolySet = 0;
    2057         900 :     move16();
    2058             :     /* Sorting the polygons */
    2059       16676 :     FOR( i = 0; i < numTri; ++i )
    2060             :     {
    2061             :         /* search for coplanar vertices and add them to the polygon */
    2062       15776 :         lenPoly = 0;
    2063       15776 :         move16();
    2064      207856 :         FOR( j = 0; j < numVtx; ++j )
    2065             :         {
    2066      192080 :             dist = L_abs( point_plane_distance_fx(
    2067      192080 :                 vtxArray[triArray[i].LS[0]].pos,
    2068      192080 :                 vtxArray[triArray[i].LS[1]].pos,
    2069      192080 :                 vtxArray[triArray[i].LS[2]].pos,
    2070      192080 :                 vtxArray[j].pos ) ); // Q28
    2071             : 
    2072      192080 :             IF( LT_32( dist, 268435 /* 1e-3f in Q28 */ ) )
    2073             :             {
    2074       48798 :                 assert( lenPoly < EFAP_MAX_CHAN_NUM && "EFAP: exceeded max polygon vertices!" );
    2075       48798 :                 poly[lenPoly] = j;
    2076       48798 :                 move16();
    2077       48798 :                 lenPoly = add( lenPoly, 1 );
    2078             :             }
    2079             :         }
    2080             : 
    2081             :         /* search existing polygons to determine whether the new one already exists/is a subset or is a superset */
    2082       15776 :         found = 0;
    2083       15776 :         move16();
    2084       15776 :         replaceIdx = -1;
    2085       15776 :         move16();
    2086      164573 :         FOR( j = 0; j < lenPolySet; ++j )
    2087             :         {
    2088      149532 :             found = compare_poly_fx( sortedChan[j], sortedLengths[j], poly, lenPoly );
    2089             : 
    2090      149532 :             IF( found > 0 )
    2091             :             {
    2092         735 :                 BREAK;
    2093             :             }
    2094      148797 :             ELSE IF( found < 0 )
    2095             :             {
    2096           0 :                 replaceIdx = j;
    2097           0 :                 move16();
    2098             :             }
    2099             :         }
    2100             : 
    2101       15776 :         IF( found == 0 )
    2102             :         {
    2103             :             /* append new poly */
    2104       15041 :             Copy( poly, sortedChan[lenPolySet], lenPoly );
    2105       15041 :             sortedTri[lenPolySet] = i;
    2106       15041 :             move16();
    2107       15041 :             sortedLengths[lenPolySet] = lenPoly;
    2108       15041 :             move16();
    2109       15041 :             lenPolySet = add( lenPolySet, 1 );
    2110             :         }
    2111         735 :         ELSE IF( EQ_16( found, -1 ) )
    2112             :         {
    2113             :             /* replace with superset */
    2114           0 :             Copy( poly, sortedChan[replaceIdx], lenPoly );
    2115           0 :             sortedTri[replaceIdx] = i;
    2116           0 :             move16();
    2117           0 :             sortedLengths[replaceIdx] = lenPoly;
    2118           0 :             move16();
    2119             :         }
    2120             :     }
    2121             : 
    2122             :     /* Sorting the vertex */
    2123       15941 :     FOR( i = 0; i < lenPolySet; ++i )
    2124             :     {
    2125       15041 :         sort_channels_vertex_fx( vtxArray, triArray, sortedChan[i], sortedLengths[i], sortedTri[i] );
    2126             :     }
    2127             : 
    2128             :     /* Output */
    2129         900 :     *outLengthPS = lenPolySet;
    2130         900 :     move16();
    2131         900 :     Copy( sortedLengths, outLengthSorted, EFAP_MAX_POLY_SET );
    2132         900 :     return;
    2133             : }
    2134             : 
    2135             : 
    2136             : /*-------------------------------------------------------------------------*
    2137             :  * compare_poly()
    2138             :  *
    2139             :  * Compares a newly created polygon with an existing one
    2140             :  *-------------------------------------------------------------------------*/
    2141             : 
    2142      149532 : static Word16 compare_poly_fx(
    2143             :     Word16 *old,   /* i  : Existing polygon            */
    2144             :     Word16 lenOld, /* i  : Length of existing polygon  */
    2145             :     Word16 *new,   /* i  : New polygon                 */
    2146             :     Word16 lenNew  /* i  : Length of new polygon       */
    2147             : )
    2148             : {
    2149             :     Word16 i, j;
    2150             :     Word16 count;
    2151             : 
    2152      149532 :     count = 0;
    2153      149532 :     move16();
    2154             : 
    2155      601971 :     FOR( i = 0; i < lenOld; ++i )
    2156             :     {
    2157     1573851 :         FOR( j = count; j < lenNew; ++j )
    2158             :         {
    2159     1220668 :             IF( EQ_16( old[i], new[j] ) )
    2160             :             {
    2161       99256 :                 count = add( count, 1 );
    2162       99256 :                 BREAK;
    2163             :             }
    2164             :         }
    2165             :     }
    2166             : 
    2167      149532 :     test();
    2168      149532 :     test();
    2169      149532 :     IF( EQ_16( count, lenOld ) && LT_16( lenOld, lenNew ) )
    2170             :     {
    2171             :         /* new polygon is a superset */
    2172           0 :         return -1;
    2173             :     }
    2174      149532 :     ELSE IF( EQ_16( count, lenNew ) && GE_16( lenOld, lenNew ) )
    2175             :     {
    2176             :         /* found as subset or identical */
    2177         735 :         return 1;
    2178             :     }
    2179             :     ELSE
    2180             :     {
    2181             :         /* not found */
    2182      148797 :         return 0;
    2183             :     }
    2184             : }
    2185             : 
    2186             : 
    2187             : /*-------------------------------------------------------------------------*
    2188             :  * sort_channels_vertex()
    2189             :  *
    2190             :  * Sort the channels of a polygon set according to the vertex azimuth
    2191             :  *-------------------------------------------------------------------------*/
    2192             : 
    2193       15041 : static void sort_channels_vertex_fx(
    2194             :     const EFAP_VERTEX *vtxArray,        /* i  : Vertex array                     */
    2195             :     const EFAP_LS_TRIANGLE *triArray,   /* i  : Triangle array                   */
    2196             :     Word16 channels[EFAP_MAX_CHAN_NUM], /* o  : Channels array to be modified    */
    2197             :     const Word16 lengthChannels,        /* i  : Length of the channels array     */
    2198             :     Word16 idxTri                       /* i  : Index of the considered triangle */
    2199             : )
    2200             : {
    2201             :     Word16 i, j;
    2202             : 
    2203             :     Word32 P1[3], P2[3], P3[3];
    2204             :     Word32 tmpU[3];
    2205             :     Word32 U[3], V[3];
    2206             :     Word32 tmpV1[3], tmpV2[3], tmpV3[3];
    2207             :     Word32 normU, normV;
    2208             :     Word32 MC[3];
    2209             :     Word32 tmpP[3], P[3];
    2210             : 
    2211             :     Word32 x, y;
    2212             : 
    2213             :     Word32 azi[EFAP_MAX_CHAN_NUM];
    2214             :     Word16 order[EFAP_MAX_CHAN_NUM];
    2215             : 
    2216             :     Word16 newChannels[EFAP_MAX_CHAN_NUM];
    2217             : 
    2218             : 
    2219             :     /* Initializing coordinates with the vertices of the considered triangle */
    2220       60164 :     FOR( i = 0; i < 3; ++i )
    2221             :     {
    2222       45123 :         P1[i] = vtxArray[triArray[idxTri].LS[0]].pos[i]; // Q31
    2223       45123 :         move32();
    2224       45123 :         P2[i] = vtxArray[triArray[idxTri].LS[1]].pos[i]; // Q31
    2225       45123 :         move32();
    2226       45123 :         P3[i] = vtxArray[triArray[idxTri].LS[2]].pos[i]; // Q31
    2227       45123 :         move32();
    2228             :     }
    2229             : 
    2230             :     /* First Base Vector */
    2231       15041 :     v_sub_fixed( P2, P1, tmpU, 3, 1 ); // tmpU Q30
    2232       15041 :     Word16 exp1 = 2;
    2233       15041 :     move16();
    2234       15041 :     normU = ISqrt32( dotp_fixed( tmpU, tmpU, 3 ) /*q29*/, &exp1 ); /*q=31-exp1*/
    2235             :     // normU = L_shl_sat( normU, exp ); //normU Q31
    2236       15041 :     v_multc_fixed( tmpU, normU, U, 3 ); // U Q30 - exp1
    2237             : 
    2238             :     /* Second Base Vector */
    2239       15041 :     v_sub_fixed( P3, P2, tmpV1, 3, 1 );                      // tmpV1 Q30
    2240       15041 :     v_multc_fixed( U, dotp_fixed( U, tmpV1, 3 ), tmpV2, 3 ); // tmpV2 Q28 - 2*exp1
    2241             : 
    2242       60164 :     FOR( i = 0; i < 3; i++ )
    2243             :     {
    2244       45123 :         tmpV2[i] = L_shl( tmpV2[i], add( Q2, shl( exp1, 1 ) ) ); // q30
    2245       45123 :         move32();
    2246             :     }
    2247             : 
    2248             : #ifdef VEC_ARITH_OPT_v1
    2249       15041 :     v_sub_fixed_no_hdrm( tmpV1, tmpV2, tmpV3, 3 ); // tmpV3 Q30
    2250             : #else                                              /* VEC_ARITH_OPT_v1 */
    2251             :     v_sub_fixed( tmpV1, tmpV2, tmpV3, 3, 0 ); // tmpV3 Q30
    2252             : #endif                                             /* VEC_ARITH_OPT_v1 */
    2253       15041 :     Word16 exp2 = 2;
    2254       15041 :     move16();
    2255       15041 :     normV = ISqrt32( dotp_fixed( tmpV3, tmpV3, 3 ) /*q29*/, &exp2 ); // q=31-exp2
    2256             : 
    2257       15041 :     v_multc_fixed( tmpV3, normV, V, 3 ); // V Q30 - exp2
    2258             : 
    2259             :     /* Center of the first Triangle  */
    2260       60164 :     FOR( i = 0; i < 3; ++i )
    2261             :     {
    2262       45123 :         MC[i] = L_shl( Mpy_32_32( L_add( L_add( L_shr( P1[i], Q2 ), L_shr( P2[i], Q2 ) ), L_shr( P3[i], Q2 ) ), 715827883 /* 1 / 3 in Q31 */ ), Q2 ); // q29+2=>q31
    2263       45123 :         move32();
    2264             :     }
    2265             : 
    2266             :     /* Sort Vertices */
    2267       60899 :     FOR( i = 0; i < lengthChannels; ++i )
    2268             :     {
    2269      183432 :         FOR( j = 0; j < 3; ++j )
    2270             :         {
    2271      137574 :             tmpP[j] = vtxArray[channels[i]].pos[j]; // q31
    2272      137574 :             move32();
    2273             :         }
    2274             : 
    2275       45858 :         v_sub_fixed( tmpP, MC, P, 3, 1 ); // P Q30
    2276             : 
    2277       45858 :         x = dotp_fixed( P, U, 3 ); // x Q29 - exp1
    2278       45858 :         y = dotp_fixed( P, V, 3 ); // y Q29 - exp2
    2279             : 
    2280             :         // Executing azi[i] = atan2f( y, x );
    2281       45858 :         azi[i] = L_shl( BASOP_util_atan2( y, x, sub( exp2, exp1 ) ), Q16 ); // azi 2Q29
    2282       45858 :         move32();
    2283             :     }
    2284             : 
    2285             :     /* Sorting the azi vec */
    2286       15041 :     v_sort_ind_fixed( azi, order, lengthChannels );
    2287             : 
    2288             :     /* Updating the channel array */
    2289       60899 :     FOR( i = 0; i < lengthChannels; ++i )
    2290             :     {
    2291       45858 :         newChannels[i] = channels[order[i]];
    2292       45858 :         move16();
    2293             :     }
    2294             : 
    2295             :     /* return Success */
    2296       15041 :     Copy( newChannels, channels, lengthChannels );
    2297             : 
    2298       15041 :     return;
    2299             : }
    2300             : 
    2301             : /*-------------------------------------------------------------------------*
    2302             :  * efap_32mod32()
    2303             :  *
    2304             :  * Modulus operation that will handle negative values the same way as matlab
    2305             :  *-------------------------------------------------------------------------*/
    2306             : 
    2307       17695 : static Word32 efap_32mod32(
    2308             :     const Word32 x, /* i  : Dividend q22*/
    2309             :     const Word32 y  /* i  : Divisor q22 */
    2310             : )
    2311             : {
    2312       17695 :     Word32 result = x % y; // q22
    2313       17695 :     move32();
    2314       17695 :     IF( result >= 0 )
    2315             :     {
    2316       14431 :         return result; // q22
    2317             :     }
    2318             :     ELSE
    2319             :     {
    2320        3264 :         return L_add( result, y ); // q22
    2321             :     }
    2322             : }
    2323             : 
    2324             : /*-------------------------------------------------------------------------*
    2325             :  * get_poly_num()
    2326             :  *
    2327             :  * Returns the index of the polygon in which the coordinate is
    2328             :  *-------------------------------------------------------------------------*/
    2329             : 
    2330      762315 : static Word16 get_poly_num_fx(
    2331             :     const Word32 P[2],                /* i  : Azimuth and elevation of the point q22*/
    2332             :     const EFAP_POLYSET_DATA *polyData /* i  : Polyset struct                     */
    2333             : )
    2334             : {
    2335             :     Word16 i;
    2336             :     Word16 num_poly, found_poly;
    2337             :     Word16 poly_tmp[EFAP_MAX_CHAN_NUM];
    2338             :     Word32 poly_dist[EFAP_MAX_CHAN_NUM];
    2339             : 
    2340             :     Word32 dist_tmp;
    2341             :     Word32 pos[3];
    2342             : 
    2343      762315 :     num_poly = 0;
    2344      762315 :     move16();
    2345             : 
    2346      762315 :     sph2cart_fx( P[0], P[1], &pos[0] ); // pos[0] q31
    2347             : 
    2348             :     /* Filter the polygon list with a fast 2d check */
    2349    16296608 :     FOR( i = 0; i < polyData->numPoly; ++i )
    2350             :     {
    2351    15549647 :         IF( in_poly_fx( P, polyData->polysetArray[i] ) )
    2352             :         {
    2353             :             /* select only polygons which are visible from the point */
    2354     1838303 :             dist_tmp = point_poly_distance_fx( polyData->polysetArray[i], pos ); // q28
    2355     1838303 :             IF( dist_tmp == 0 )
    2356             :             {
    2357       15354 :                 return i;
    2358             :             }
    2359     1822949 :             ELSE IF( dist_tmp > 0 )
    2360             :             {
    2361     1106628 :                 poly_tmp[num_poly] = i;
    2362     1106628 :                 move16();
    2363     1106628 :                 poly_dist[num_poly] = dist_tmp; // q28
    2364     1106628 :                 move32();
    2365     1106628 :                 num_poly = add( num_poly, 1 );
    2366             :             }
    2367             :         }
    2368             :     }
    2369      746961 :     IF( num_poly == 0 )
    2370             :     {
    2371           0 :         return -1;
    2372             :     }
    2373             : 
    2374             :     /* select the polygon with the smallest distance */
    2375      746961 :     found_poly = poly_tmp[0];
    2376      746961 :     move16();
    2377      746961 :     dist_tmp = poly_dist[0]; // q28
    2378      746961 :     move32();
    2379     1106628 :     FOR( i = 1; i < num_poly; i++ )
    2380             :     {
    2381      359667 :         IF( LT_32( poly_dist[i], dist_tmp ) )
    2382             :         {
    2383      259669 :             found_poly = poly_tmp[i];
    2384      259669 :             move16();
    2385      259669 :             dist_tmp = poly_dist[i]; // q28
    2386      259669 :             move32();
    2387             :         }
    2388             :     }
    2389             : 
    2390      746961 :     return found_poly;
    2391             : }
    2392             : 
    2393             : /*-------------------------------------------------------------------------*
    2394             :  * in_poly()
    2395             :  *
    2396             :  * Determines if a given point is within a polygon or not
    2397             :  *-------------------------------------------------------------------------*/
    2398             : 
    2399    15549647 : static Word16 in_poly_fx(                         /* Angles are in Q22 */
    2400             :                           const Word32 P[2],      /* i  : Azimuth and elevation of the point q22*/
    2401             :                           const EFAP_POLYSET poly /* i  : Polyset struct                     */
    2402             : )
    2403             : {
    2404             :     Word16 n;
    2405    15549647 :     Word16 numVertices = poly.numChan;
    2406             :     Word32 A[2];
    2407             :     Word32 B[2];
    2408             :     Word32 C[2];
    2409             :     Word32 P_minus_A[2];
    2410    15549647 :     move16();
    2411             : 
    2412             :     /* Safety check */
    2413             : 
    2414    15549647 :     IF( LT_16( numVertices, 3 ) )
    2415             :     {
    2416           0 :         return 0;
    2417             :     }
    2418             : 
    2419             :     /* See if the point is in one of the triangles available in the polygon */
    2420             : 
    2421    15549647 :     IF( poly.isNaN[0] )
    2422             :     {
    2423     1081411 :         A[0] = P[0]; // q22
    2424     1081411 :         move32();
    2425             :     }
    2426             :     ELSE
    2427             :     {
    2428    14468236 :         A[0] = poly.polyAzi[0]; // q22
    2429    14468236 :         move32();
    2430             :     }
    2431    15549647 :     A[1] = poly.polyEle[0]; // q22
    2432    15549647 :     move32();
    2433             : 
    2434             : #ifdef VEC_ARITH_OPT_v1
    2435    15549647 :     v_sub_fixed_no_hdrm( P, A, P_minus_A, 2 ); /* Precalculate value of (P-A) q22*/
    2436             : #else                                          /* VEC_ARITH_OPT_v1 */
    2437             :     v_sub_fixed( P, A, P_minus_A, 2, 0 );     /* Precalculate value of (P-A) q22*/
    2438             : #endif                                         /* VEC_ARITH_OPT_v1 */
    2439             : 
    2440    30450531 :     FOR( n = 1; n < sub( numVertices, 1 ); ++n )
    2441             :     {
    2442    16739187 :         IF( poly.isNaN[n] )
    2443             :         {
    2444     8586162 :             B[0] = P[0]; // q22
    2445     8586162 :             move32();
    2446             :         }
    2447             :         ELSE
    2448             :         {
    2449     8153025 :             B[0] = poly.polyAzi[n]; // q22
    2450     8153025 :             move32();
    2451             :         }
    2452    16739187 :         B[1] = poly.polyEle[n]; // q22
    2453    16739187 :         move32();
    2454             : 
    2455    16739187 :         IF( poly.isNaN[n + 1] )
    2456             :         {
    2457     1076794 :             C[0] = P[0]; // q22
    2458     1076794 :             move32();
    2459             :         }
    2460             :         ELSE
    2461             :         {
    2462    15662393 :             C[0] = poly.polyAzi[n + 1]; // q22
    2463    15662393 :             move32();
    2464             :         }
    2465    16739187 :         C[1] = poly.polyEle[n + 1]; // q22
    2466    16739187 :         move32();
    2467             : 
    2468    16739187 :         IF( in_tri_fx( A, B, C, P_minus_A ) )
    2469             :         {
    2470     1838303 :             return 1;
    2471             :         }
    2472             :     }
    2473             : 
    2474    13711344 :     return 0;
    2475             : }
    2476             : 
    2477             : /*-------------------------------------------------------------------------*
    2478             :  * in_tri()
    2479             :  *
    2480             :  * Determines if a given point is within a triangle or not
    2481             :  *-------------------------------------------------------------------------*/
    2482             : 
    2483    19173031 : static Word16 in_tri_fx(
    2484             :     Word32 A[2],        /* i  : Coordinate of one apex of the triangle q22*/
    2485             :     Word32 B[2],        /* i  : Coordinate of one apex of the triangle q22*/
    2486             :     Word32 C[2],        /* i  : Coordinate of one apex of the triangle q22*/
    2487             :     Word32 P_minus_A[2] /* i  : Value of (P - A)                       q22*/
    2488             : )
    2489             : {
    2490             :     Word32 tmpDot1[2], tmpDot2[2];
    2491             :     Word32 matInv[2][2];
    2492             :     Word32 invFactor;
    2493             :     Word16 tmp16, tmp_e;
    2494             :     Word64 S[2];
    2495             :     /* Threshold adjusted */
    2496    19173031 :     Word64 thresh_int = 35184640; // 1e-6f in Q45
    2497    19173031 :     move64();
    2498             : 
    2499             :     /*
    2500             :     Not a Valid Triangle : Colinear edges
    2501             :     In the matlab implementation, the rcond() function is used
    2502             :     Since it's very complex to implement this in C
    2503             :     I'll just compute the determinant and if it's equal to 0, that means the two vectors are colinear
    2504             :     */
    2505             : 
    2506             : #ifdef VEC_ARITH_OPT_v1
    2507    19173031 :     v_sub_fixed_no_hdrm( B, A, tmpDot1, 2 ); // tmpDot1 q22
    2508    19173031 :     v_sub_fixed_no_hdrm( C, A, tmpDot2, 2 ); // tmpDot2 q22
    2509             : #else                                        /* VEC_ARITH_OPT_v1 */
    2510             :     v_sub_fixed( B, A, tmpDot1, 2, 0 );       // tmpDot1 q22
    2511             :     v_sub_fixed( C, A, tmpDot2, 2, 0 );       // tmpDot2 q22
    2512             : #endif                                       /* VEC_ARITH_OPT_v1 */
    2513             : 
    2514             :     /* Verification of the non-colinearity : Q22 * Q22 = Q13 */
    2515    19173031 :     invFactor = L_sub( Mpy_32_32( tmpDot1[0], tmpDot2[1] ), Mpy_32_32( tmpDot1[1], tmpDot2[0] ) ); /*q22+q22-q31->q13*/
    2516             : 
    2517    19173031 :     IF( invFactor == 0 )
    2518             :     {
    2519         408 :         return 0;
    2520             :     }
    2521             : 
    2522             :     /* invFactor = 1.f / invFactor; */
    2523    19172623 :     tmp16 = BASOP_Util_Divide3232_Scale( ONE_IN_Q13, invFactor, &tmp_e ); /*15-tmp_e*/
    2524    19172623 :     invFactor = L_shl_sat( tmp16, add( Q16, tmp_e ) );                    /* Q31 */
    2525             : 
    2526    19172623 :     Word16 invFactor_exp = norm_l( invFactor );
    2527    19172623 :     invFactor = L_shl( invFactor, invFactor_exp ); // 31+invFactor_exp
    2528             : 
    2529             :     // Q22 = Q22 * Q31
    2530    19172623 :     matInv[0][0] = Mpy_32_32( tmpDot2[1], invFactor ); // q=22+invFactor_exp
    2531    19172623 :     move32();
    2532    19172623 :     matInv[0][1] = Mpy_32_32( L_negate( tmpDot2[0] ), invFactor ); // q=22+invFactor_exp
    2533    19172623 :     move32();
    2534    19172623 :     matInv[1][0] = Mpy_32_32( L_negate( tmpDot1[1] ), invFactor ); // q=22+invFactor_exp
    2535    19172623 :     move32();
    2536    19172623 :     matInv[1][1] = Mpy_32_32( tmpDot1[0], invFactor ); // q=22+invFactor_exp
    2537    19172623 :     move32();
    2538    19172623 :     S[0] = W_mac_32_32( W_mult_32_32( matInv[0][0], P_minus_A[0] ), matInv[0][1], P_minus_A[1] ); // Q22+invFactor_exp +Q22 + 1
    2539    19172623 :     move64();
    2540    19172623 :     S[0] = W_shr( S[0], invFactor_exp ); // q45
    2541    19172623 :     move64();
    2542    19172623 :     S[1] = W_mac_32_32( W_mult_32_32( matInv[1][0], P_minus_A[0] ), matInv[1][1], P_minus_A[1] ); // Q22+invFactor_exp +Q22 + 1
    2543    19172623 :     move64();
    2544    19172623 :     S[1] = W_shr( S[1], invFactor_exp ); // q45
    2545    19172623 :     move64();
    2546             : 
    2547    19172623 :     test();
    2548    19172623 :     test();
    2549    19172623 :     IF( LT_64( S[0], -thresh_int ) || LT_64( S[1], -thresh_int ) || GT_64( W_add( S[0], S[1] ), W_add( ONE_IN_Q45, thresh_int ) ) )
    2550             :     {
    2551    14998355 :         return 0;
    2552             :     }
    2553             :     ELSE
    2554             :     {
    2555     4174268 :         return 1;
    2556             :     }
    2557             : }
    2558             : 
    2559             : /*-------------------------------------------------------------------------*
    2560             :  * sph2cart_fx()
    2561             :  *
    2562             :  * Converts a vertex position to cartesian coordinates
    2563             :  *-------------------------------------------------------------------------*/
    2564             : 
    2565     6286912 : static void sph2cart_fx(
    2566             :     const Word32 azi, /* i  : Azimuth in degrees Q22                     */
    2567             :     const Word32 ele, /* i  : Elevation in degrees Q22                   */
    2568             :     Word32 *pos       /* o  : Cartesian coordinates vector (x, y, z) Q31 */
    2569             : )
    2570             : {
    2571             :     Word16 azi_temp, ele_temp;
    2572             : 
    2573     6286912 :     azi_temp = extract_l( L_shr( Mpy_32_32( azi, ONE_BY_360_Q31 ), Q7 ) ); /* Q15 */
    2574     6286912 :     ele_temp = extract_l( L_shr( Mpy_32_32( ele, ONE_BY_360_Q31 ), Q7 ) ); /* Q15 */
    2575             : 
    2576     6286912 :     pos[0] = Mpy_32_16( getCosWord16R2( azi_temp ), 0, getCosWord16R2( ele_temp ) ); /* Q31 */
    2577     6286912 :     move32();
    2578     6286912 :     pos[1] = Mpy_32_16( getSineWord16R2( azi_temp ), 0, getCosWord16R2( ele_temp ) ); /* Q31 */
    2579     6286912 :     move32();
    2580     6286912 :     pos[2] = L_shl( getSineWord16R2( ele_temp ), Q16 ); /* Q31 */
    2581     6286912 :     move32();
    2582             : 
    2583     6286912 :     return;
    2584             : }

Generated by: LCOV version 1.14