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

Generated by: LCOV version 1.14