LCOV - code coverage report
Current view: top level - lib_com - ivas_pca_tools_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 530 773 68.6 %
Date: 2025-05-03 01:55:50 Functions: 19 26 73.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 "options.h"
      35             : #include "ivas_cnst.h"
      36             : #include <math.h>
      37             : #include <assert.h>
      38             : #include "ivas_rom_com.h"
      39             : #include "wmc_auto.h"
      40             : #include "prot_fx.h"
      41             : #include "ivas_prot_fx.h"
      42             : 
      43             : /*---------------------------------------------------------------------*
      44             :  * eye_matrix()
      45             :  *
      46             :  *---------------------------------------------------------------------*/
      47             : 
      48      848080 : static Word16 check_bound_fx( Word32 tmp )
      49             : {
      50      848080 :     IF( GT_32( tmp, MAX16B ) )
      51             :     {
      52          65 :         return MAX16B;
      53             :     }
      54      848015 :     ELSE IF( LT_32( tmp, MIN16B ) )
      55             :     {
      56           0 :         return MIN16B;
      57             :     }
      58             :     ELSE
      59             :     {
      60      848015 :         return extract_l( tmp );
      61             :     }
      62             : }
      63             : 
      64      607668 : void eye_matrix_fx(
      65             :     Word16 *mat, // Q
      66             :     const Word16 n,
      67             :     const Word16 d // Q
      68             : )
      69             : {
      70             :     Word16 i;
      71             : 
      72    10330356 :     FOR( i = 0; i < n * n; i++ )
      73             :     {
      74     9722688 :         mat[i] = 0;
      75     9722688 :         move16();
      76             :     }
      77     3038340 :     FOR( i = 0; i < n; i++ )
      78             :     {
      79     2430672 :         mat[i * n + i] = d; // Q
      80     2430672 :         move16();
      81             :     }
      82             : 
      83      607668 :     return;
      84             : }
      85             : 
      86       17500 : void eye_matrix_fx32(
      87             :     Word32 *mat, // Q
      88             :     const Word16 n,
      89             :     const Word32 d // Q
      90             : )
      91             : {
      92             :     Word16 i;
      93             : 
      94      297500 :     FOR( i = 0; i < n * n; i++ )
      95             :     {
      96      280000 :         mat[i] = 0;
      97      280000 :         move32();
      98             :     }
      99       87500 :     FOR( i = 0; i < n; i++ )
     100             :     {
     101       70000 :         mat[i * n + i] = d; // Q
     102       70000 :         move32();
     103             :     }
     104             : 
     105       17500 :     return;
     106             : }
     107             : /*---------------------------------------------------------------------*
     108             :  * cov()
     109             :  *
     110             :  * Compute covariance of input channels
     111             :  *---------------------------------------------------------------------*/
     112             : 
     113        3500 : void cov_subfr_fx(
     114             :     Word32 **ptr_sig_fx, // Q11
     115             :     Word64 *r_fx_64,     // Q11
     116             :     const Word16 n_channels,
     117             :     const Word16 len )
     118             : {
     119             :     Word64 s_fx;
     120             :     Word16 j, k, l;
     121             :     Word32 *t_fx, *tt_fx;
     122             : 
     123             :     /* Compute diagonal r[k][k] */
     124       17500 :     FOR( k = 0; k < n_channels; k++ )
     125             :     {
     126       14000 :         t_fx = &ptr_sig_fx[k][0];
     127       14000 :         s_fx = W_shr( W_mult0_32_32( t_fx[0], t_fx[0] ), 11 ); // Q11 + Q11 - Q11 -> Q11
     128     5760000 :         FOR( j = 1; j < len; j++ )
     129             :         {
     130     5746000 :             if ( s_fx != 0 )
     131             :             {
     132     5745771 :                 t_fx[j] = t_fx[j];
     133     5745771 :                 move32();
     134             :             }
     135     5746000 :             s_fx = W_add( s_fx, W_shr( W_mult0_32_32( t_fx[j], t_fx[j] ), 11 ) ); // Q11 + Q11 - Q11 -> Q11
     136             :         }
     137       14000 :         r_fx_64[k * n_channels + k] = s_fx; // Q11
     138       14000 :         move64();
     139             :     }
     140             : 
     141             :     /* Compute off-diagonal r[k][l] = r[l][k] */
     142       14000 :     FOR( k = 0; k < ( n_channels - 1 ); k++ )
     143             :     {
     144       10500 :         t_fx = &ptr_sig_fx[k][0];
     145       31500 :         FOR( l = k + 1; l < n_channels; l++ )
     146             :         {
     147       21000 :             tt_fx = &ptr_sig_fx[l][0];
     148       21000 :             s_fx = W_shr( W_mult0_32_32( t_fx[0], tt_fx[0] ), 11 ); // Q11 + Q11 - Q11 -> Q11
     149     8640000 :             FOR( j = 1; j < len; j++ )
     150             :             {
     151     8619000 :                 s_fx = W_add( s_fx, W_shr( W_mult0_32_32( t_fx[j], tt_fx[j] ), 11 ) );
     152             :             }
     153       21000 :             r_fx_64[k * n_channels + l] = s_fx; // Q11
     154       21000 :             r_fx_64[l * n_channels + k] = s_fx; // Q11
     155       21000 :             move64();
     156       21000 :             move64();
     157             :         }
     158             :     }
     159             : 
     160        3500 :     return;
     161             : }
     162             : 
     163       70000 : static void house_refl_fx(
     164             :     const Word32 *px_fx, // Q: px_q
     165             :     const Word16 px_q,
     166             :     const Word16 sizex,
     167             :     Word32 *pu_fx, // Q: pu_q
     168             :     Word16 *pu_fx_q,
     169             :     Word32 *normu_fx, // Q: q_normu
     170             :     Word16 *q_normu )
     171             : {
     172             :     Word16 i;
     173             :     Word16 exp, tmp, normu_q;
     174             :     Word32 L_tmp;
     175             : 
     176             :     Word16 pu_e[FOA_CHANNELS];
     177       70000 :     Copy32( px_fx, pu_fx, sizex );
     178       70000 :     set16_fx( pu_e, sub( 31, px_q ), sizex );
     179       70000 :     Word64 L64_sum = 1;
     180       70000 :     move64();
     181      245000 :     FOR( Word16 k = 0; k < sizex; k++ )
     182             :     {
     183      175000 :         L64_sum = W_mac_32_32( L64_sum, pu_fx[k], pu_fx[k] ); // pu_q
     184             :     }
     185       70000 :     Word16 norm = W_norm( L64_sum );
     186       70000 :     L64_sum = W_shl( L64_sum, norm );
     187       70000 :     *normu_fx = W_extract_h( L64_sum ); // ener_side_q
     188       70000 :     normu_q = sub( 31, sub( 31, sub( add( add( shl( px_q, 1 ), 1 ), norm ), 32 ) ) );
     189       70000 :     move32();
     190             : 
     191       70000 :     exp = sub( Q31, normu_q );
     192       70000 :     ( *normu_fx ) = Sqrt32( *normu_fx, &exp );
     193       70000 :     move32();
     194       70000 :     normu_q = sub( Q31, exp );
     195             : 
     196       70000 :     IF( ( *normu_fx ) == 0 )
     197             :     {
     198           0 :         pu_fx[0] = SQRT2_FIXED; // same q as other elements -> Q30
     199           0 :         pu_e[0] = 1;
     200           0 :         move32();
     201           0 :         move16();
     202             :     }
     203             :     ELSE
     204             :     {
     205       70000 :         tmp = BASOP_Util_Divide3232_Scale( ONE_IN_Q30, *normu_fx, &exp ); // Q30 + px_q, 1073741824 ->1 in Q30
     206       70000 :         exp = add( exp, sub( 1, sub( 31, normu_q ) ) );
     207             : 
     208       70000 :         Word32 rcp_fx = L_deposit_h( tmp ); // rcp_q
     209       70000 :         Word16 rcp_q = sub( Q31, exp );
     210             : 
     211      245000 :         FOR( i = 0; i < sizex; i++ )
     212             :         {
     213      175000 :             norm = norm_l( pu_fx[i] );
     214      175000 :             L_tmp = L_shl( pu_fx[i], norm );
     215      175000 :             pu_fx[i] = Mpy_32_32( L_tmp, rcp_fx ); // ( px_q + norm ) + rcp_q - 31  -> exp: 31 + 31 - (px_q + norm + rcp_q)
     216      175000 :             pu_e[i] = sub( 62, add( add( px_q, norm ), rcp_q ) );
     217      175000 :             move32();
     218      175000 :             move16();
     219             :         }
     220             : 
     221       70000 :         IF( pu_fx[0] >= 0 )
     222             :         {
     223       70000 :             pu_fx[0] = BASOP_Util_Add_Mant32Exp( pu_fx[0], pu_e[0], ONE_IN_Q30, 1, &pu_e[0] );
     224       70000 :             ( *normu_fx ) = L_negate( *normu_fx );
     225             : 
     226       70000 :             move32();
     227       70000 :             move32();
     228             :         }
     229             :         ELSE
     230             :         {
     231           0 :             pu_fx[0] = BASOP_Util_Add_Mant32Exp( pu_fx[0], pu_e[0], -ONE_IN_Q30, 1, &pu_e[0] );
     232           0 :             move32();
     233             :         }
     234             : 
     235       70000 :         Word16 exp2, exp1 = pu_e[0];
     236       70000 :         move16();
     237       70000 :         L_tmp = Sqrt32( L_abs( pu_fx[0] ), &exp1 );
     238       70000 :         tmp = BASOP_Util_Divide3232_Scale( 2147483647, L_add( L_tmp, EPSILON_FX ), &exp ); // 1 in Q31
     239       70000 :         exp = add( exp, sub( 0, exp1 ) );
     240       70000 :         L_tmp = L_deposit_h( tmp );
     241       70000 :         rcp_fx = BASOP_Util_Add_Mant32Exp( 0, 0, L_tmp, exp, &exp2 );
     242      245000 :         FOR( i = 0; i < sizex; i++ )
     243             :         {
     244      175000 :             pu_fx[i] = Mpy_32_32( pu_fx[i], rcp_fx ); // pu_e[i] + exp2
     245      175000 :             move32();
     246      175000 :             pu_e[i] = add( pu_e[i], exp2 );
     247      175000 :             move32();
     248             :         }
     249             : 
     250       70000 :         Word16 max_e = pu_e[0];
     251       70000 :         move16();
     252      245000 :         FOR( i = 0; i < sizex; i++ )
     253             :         {
     254      175000 :             IF( GT_16( pu_e[i], max_e ) )
     255             :             {
     256        6685 :                 max_e = pu_e[i];
     257        6685 :                 move16();
     258             :             }
     259             :         }
     260             : 
     261      245000 :         FOR( i = 0; i < sizex; i++ )
     262             :         {
     263      175000 :             pu_fx[i] = L_shr( pu_fx[i], sub( max_e, pu_e[i] ) ); // max_e
     264      175000 :             move32();
     265             :         }
     266       70000 :         *pu_fx_q = sub( 31, max_e );
     267       70000 :         *q_normu = normu_q;
     268       70000 :         move32();
     269       70000 :         move16();
     270             :     }
     271             : 
     272       70000 :     return;
     273             : }
     274             : 
     275       17500 : static void house_qr_fx(
     276             :     const Word32 *pA_fx, // Q: pA_q
     277             :     Word16 pA_q,
     278             :     Word32 *pQ_fx, // Q: Q31
     279             :     Word32 *pR_fx, // Q: pA_q
     280             :     const Word16 n )
     281             : {
     282       17500 :     Word16 n_rows = FOA_CHANNELS;
     283       17500 :     move16();
     284       17500 :     Word16 pu_fx_q = 0, pR_fx_q, exp2;
     285       17500 :     move16();
     286             :     Word16 i, j, k, c, s, r;
     287             :     Word32 A_fx[FOA_CHANNELS * FOA_CHANNELS];
     288             :     Word32 U_fx[FOA_CHANNELS * FOA_CHANNELS];
     289             :     Word16 U_e[FOA_CHANNELS * FOA_CHANNELS];
     290             :     Word32 pu_fx[FOA_CHANNELS];
     291             :     Word16 tmp_pu_e[FOA_CHANNELS];
     292             :     Word16 pv_exp[FOA_CHANNELS];
     293             :     Word32 pa_fx[FOA_CHANNELS];
     294             :     Word16 tmp_e;
     295             :     Word32 pv_fx[FOA_CHANNELS], L_tmp1;
     296             : 
     297             : 
     298       17500 :     Copy32( pA_fx, A_fx, FOA_CHANNELS * FOA_CHANNELS );
     299       17500 :     set_zero_fx( U_fx, FOA_CHANNELS * FOA_CHANNELS );
     300       17500 :     set16_fx( U_e, 0, FOA_CHANNELS * FOA_CHANNELS );
     301       17500 :     set_zero_fx( pR_fx, FOA_CHANNELS * FOA_CHANNELS );
     302       87500 :     FOR( k = 0; k < n_rows; k++ )
     303             :     {
     304      350000 :         FOR( i = 0; i < n_rows; i++ )
     305             :         {
     306      280000 :             pa_fx[i] = A_fx[i * n + k]; // pA_q
     307      280000 :             move32();
     308             :         }
     309             : 
     310       70000 :         house_refl_fx( &pa_fx[k], pA_q, sub( n_rows, k ), pu_fx, &pu_fx_q, &pR_fx[k * n_rows + k], &pR_fx_q );
     311       70000 :         pR_fx[k * n_rows + k] = L_shr( pR_fx[k * n_rows + k], sub( pR_fx_q, pA_q ) ); // pA_q
     312       70000 :         move32();
     313             : 
     314             : 
     315       70000 :         U_fx[k * n_rows + k] = pu_fx[0];          // pu_fx_q
     316       70000 :         U_e[k * n_rows + k] = sub( 31, pu_fx_q ); // pu_fx_q
     317       70000 :         move32();
     318       70000 :         move16();
     319      175000 :         FOR( c = k + 1; c < n_rows; c++ )
     320             :         {
     321      525000 :             FOR( i = 0; i < n_rows; i++ )
     322             :             {
     323      420000 :                 pa_fx[i] = A_fx[i * n + c]; // pA_q
     324      420000 :                 move32();
     325             :             }
     326             : 
     327      105000 :             Word64 L64_sum = 1;
     328      105000 :             move64();
     329             :             Word16 norm;
     330      455000 :             FOR( Word16 l = 0; l < n_rows - k; l++ )
     331             :             {
     332      350000 :                 L64_sum = W_mac_32_32( L64_sum, pa_fx[k + l], pu_fx[l] ); // pA_q + pu_fx_q
     333             :             }
     334      105000 :             norm = W_norm( L64_sum );
     335      105000 :             L64_sum = W_shl( L64_sum, norm );
     336      105000 :             pv_fx[c - k - 1] = W_extract_h( L64_sum ); // pv_exp
     337      105000 :             pv_exp[c - k - 1] = sub( 31, sub( add( add( add( pu_fx_q, pA_q ), 1 ), norm ), 32 ) );
     338      105000 :             U_fx[c * n_rows + k] = pu_fx[c - k];      // pu_fx_q
     339      105000 :             U_e[c * n_rows + k] = sub( 31, pu_fx_q ); // pu_fx_q
     340      105000 :             move32();
     341      105000 :             move32();
     342      105000 :             move16();
     343      105000 :             move16();
     344             :         }
     345             : 
     346       70000 :         i = 0;
     347       70000 :         move16();
     348      245000 :         FOR( s = k; s < n_rows; s++ )
     349             :         {
     350      175000 :             j = 0;
     351      175000 :             move16();
     352      525000 :             FOR( r = k + 1; r < n_rows; r++ )
     353             :             {
     354             : 
     355      350000 :                 A_fx[s * n_rows + r] = BASOP_Util_Add_Mant32Exp( A_fx[s * n_rows + r], sub( 31, pA_q ), L_negate( Mpy_32_32( pv_fx[j], pu_fx[i] ) ), add( sub( 31, pu_fx_q ), pv_exp[j] ), &exp2 ); // exp2
     356      350000 :                 A_fx[s * n_rows + r] = L_shr_sat( A_fx[s * n_rows + r], sub( sub( 31, exp2 ), pA_q ) );                                                                                             // pA_q
     357      350000 :                 move32();
     358      350000 :                 j = add( j, 1 );
     359             :             }
     360      175000 :             i = add( i, 1 );
     361             :         }
     362             : 
     363      175000 :         FOR( r = k + 1; r < n_rows; r++ )
     364             :         {
     365      105000 :             pR_fx[k * n_rows + r] = A_fx[k * n_rows + r]; // pA_q
     366      105000 :             move32();
     367             :         }
     368             :     }
     369             : 
     370       17500 :     eye_matrix_fx32( pQ_fx, FOA_CHANNELS, ONE_IN_Q31 ); // 1 in Q31
     371             : 
     372       87500 :     FOR( k = FOA_CHANNELS - 1; k >= 0; k-- )
     373             :     {
     374      350000 :         FOR( i = 0; i < n_rows; i++ )
     375             :         {
     376      280000 :             pu_fx[i] = U_fx[i * n + k];
     377      280000 :             move32();
     378      280000 :             tmp_pu_e[i] = U_e[i * n + k];
     379      280000 :             move16();
     380             :         }
     381             : 
     382      245000 :         FOR( s = k; s < n_rows; s++ )
     383             :         {
     384      875000 :             FOR( i = 0; i < n_rows; i++ )
     385             :             {
     386      700000 :                 pa_fx[i] = pQ_fx[i * n + s]; // Q31
     387      700000 :                 move32();
     388             :             }
     389             : 
     390             : 
     391      175000 :             pv_fx[s - k] = dotp_fixed( &pu_fx[k], &pa_fx[k], sub( n_rows, k ) ); // exp: tmp_pu_e[k]
     392      175000 :             pv_exp[s - k] = tmp_pu_e[k];
     393      175000 :             move32();
     394      175000 :             move16();
     395             :         }
     396      245000 :         FOR( s = k; s < n_rows; s++ )
     397             :         {
     398      700000 :             FOR( r = k; r < n_rows; r++ )
     399             :             {
     400      525000 :                 L_tmp1 = BASOP_Util_Add_Mant32Exp( pQ_fx[s * n_rows + r], 0, L_negate( Mpy_32_32( pv_fx[r - k], U_fx[s * n_rows + k] ) ), pv_exp[r - k] + U_e[s * n_rows + k], &tmp_e ); // Q31
     401      525000 :                 IF( tmp_e > 0 )
     402             :                 {
     403       24969 :                     pQ_fx[s * n_rows + r] = check_bounds_l( L_tmp1, L_negate( L_shr( MAX_32, tmp_e ) ), L_shr( MAX_32, tmp_e ) ); // Q31
     404       24969 :                     pQ_fx[s * n_rows + r] = L_shl( pQ_fx[s * n_rows + r], tmp_e );                                                // Q31
     405       24969 :                     move32();
     406       24969 :                     move32();
     407             :                 }
     408             :                 ELSE
     409             :                 {
     410      500031 :                     pQ_fx[s * n_rows + r] = L_shl( L_tmp1, tmp_e ); // Q31
     411      500031 :                     move32();
     412             :                 }
     413             :             }
     414             :         }
     415             :     }
     416             : 
     417       17500 :     return;
     418             : }
     419             : 
     420             : /*---------------------------------------------------------------------*
     421             :  * eig_qr()
     422             :  *
     423             :  * Compute eigenvalue decomposition by QR method
     424             :  *---------------------------------------------------------------------*/
     425             : 
     426        1750 : void eig_qr_fx(
     427             :     const Word32 *A_fx, // A_q
     428             :     Word16 A_q,
     429             :     const Word16 num_iter,
     430             :     Word32 *EV_fx,   // Q31
     431             :     Word32 *Vals_fx, // A_q
     432             :     const Word16 n )
     433             : {
     434             :     Word16 i;
     435             :     Word16 breakcnd, iter_num;
     436             : 
     437             :     Word32 Ak_fx[FOA_CHANNELS * FOA_CHANNELS], Qk_fx[FOA_CHANNELS * FOA_CHANNELS], Rk_fx[FOA_CHANNELS * FOA_CHANNELS], D_fx[FOA_CHANNELS * FOA_CHANNELS], d_fx;
     438             :     Word16 d_q, exp;
     439             : 
     440        1750 :     assert( n <= FOA_CHANNELS );
     441        1750 :     breakcnd = 1;
     442        1750 :     iter_num = 0;
     443        1750 :     move16();
     444        1750 :     move16();
     445             : 
     446             :     /* check zero matrix */
     447        1750 :     d_fx = dotp_fixed( A_fx, A_fx, n * n ); // A_q + A_q - Q31 -> d_q
     448        1750 :     d_q = sub( add( A_q, A_q ), 31 );
     449             : 
     450        1750 :     if ( d_fx != 0 )
     451             :     {
     452        1750 :         breakcnd = 0;
     453        1750 :         move16();
     454             :     }
     455             :     /* duplicate */
     456        1750 :     Copy32( A_fx, Ak_fx, n * n ); // A_q
     457             : 
     458             :     /* identity */
     459        1750 :     set_zero_fx( EV_fx, n * n );
     460             : 
     461        8750 :     FOR( i = 0; i < n; i++ )
     462             :     {
     463        7000 :         EV_fx[i * n + i] = ONE_IN_Q31; // 1 in Q31
     464        7000 :         move32();
     465             :     }
     466        1750 :     set_zero_fx( Vals_fx, n );
     467             : 
     468       19250 :     WHILE( breakcnd == 0 )
     469             :     {
     470       17500 :         iter_num = add( iter_num, 1 );
     471             : 
     472       17500 :         Copy32( Ak_fx, D_fx, n * n );
     473             : 
     474             :         /* set diagonal */
     475             : 
     476       87500 :         FOR( i = 0; i < n; i++ )
     477             :         {
     478       70000 :             D_fx[i * n + i] = Vals_fx[i]; // A_q
     479       70000 :             move32();
     480             :         }
     481             : 
     482             :         /* stop condition */
     483       17500 :         d_fx = dotp_fixed_guarded( D_fx, D_fx, n * n ); // ( A_q + A_q - 31 ) - find_guarded_bits_fx( n * n )
     484       17500 :         d_q = sub( sub( add( A_q, A_q ), 31 ), find_guarded_bits_fx( n * n ) );
     485       17500 :         exp = sub( 31, d_q );
     486       17500 :         d_fx = Sqrt32( d_fx, &exp );
     487             : 
     488       17500 :         test();
     489       17500 :         if ( ( d_fx < 0 ) || GE_16( iter_num, num_iter ) )
     490             :         {
     491        1750 :             breakcnd = 1;
     492        1750 :             move16();
     493             :         }
     494             : 
     495       17500 :         house_qr_fx( Ak_fx, A_q, Qk_fx, Rk_fx, n );
     496             : 
     497       17500 :         matrix_product_fx( Qk_fx, n, n, 0, Rk_fx, n, n, 0, Ak_fx );                     // A_q + Q31 - Q31 -> A_q
     498       17500 :         matrix_product_mant_exp_fx( Qk_fx, 0, n, n, 0, EV_fx, 0, n, n, 0, D_fx, &exp ); // Q31 + Q31 - Q31 -> Q31
     499       17500 :         Scale_sig32( D_fx, imult1616( n, n ), exp );                                    // Q31
     500             : 
     501       17500 :         Copy32( D_fx, EV_fx, imult1616( n, n ) ); // Q31
     502             :     }
     503             : 
     504             : 
     505             :     /* get diagonal */
     506        8750 :     FOR( i = 0; i < n; i++ )
     507             :     {
     508        7000 :         Vals_fx[i] = Ak_fx[i * n + i];
     509        7000 :         move32();
     510             :     }
     511        1750 :     return;
     512             : }
     513             : 
     514             : /*---------------------------------------------------------------------*
     515             :  * exhst_4x4()
     516             :  *
     517             :  * Find optimal permutation of eigenvectors
     518             :  *---------------------------------------------------------------------*/
     519             : 
     520           0 : void exhst_4x4_fx(
     521             :     Word16 *cost_mtx, // Q
     522             :     Word16 *path,
     523             :     const Word16 maximize )
     524             : {
     525             :     Word16 i, j, k, l;
     526             :     Word16 opt_val, cost;
     527             : 
     528           0 :     IF( maximize == 0 )
     529             :     {
     530           0 :         opt_val = MAX_16;
     531           0 :         move16();
     532             :     }
     533             :     ELSE
     534             :     {
     535           0 :         opt_val = -MAX_16;
     536           0 :         move16();
     537             :     }
     538             : 
     539           0 :     FOR( i = 0; i < 1; i++ )
     540             :     {
     541           0 :         FOR( j = 0; j < 4; j++ )
     542             :         {
     543           0 :             IF( NE_16( j, i ) )
     544             :             {
     545           0 :                 FOR( k = 0; k < 4; k++ )
     546             :                 {
     547           0 :                     test();
     548           0 :                     IF( NE_16( k, i ) && NE_16( k, j ) )
     549             :                     {
     550           0 :                         FOR( l = 0; l < 4; l++ )
     551             :                         {
     552           0 :                             test();
     553           0 :                             test();
     554           0 :                             IF( NE_16( l, i ) && NE_16( l, j ) && NE_16( l, k ) )
     555             :                             {
     556           0 :                                 cost = add( add( cost_mtx[0 * 4 + i], cost_mtx[1 * 4 + j] ), add( cost_mtx[2 * 4 + k], cost_mtx[3 * 4 + l] ) );
     557           0 :                                 test();
     558           0 :                                 test();
     559           0 :                                 test();
     560           0 :                                 IF( ( ( maximize == 0 ) && GT_16( opt_val, cost ) ) || ( ( maximize != 0 ) && LT_16( opt_val, cost ) ) )
     561             :                                 {
     562           0 :                                     opt_val = cost;
     563           0 :                                     path[0] = i;
     564           0 :                                     path[1] = j;
     565           0 :                                     path[2] = k;
     566           0 :                                     path[3] = l;
     567           0 :                                     move16();
     568           0 :                                     move16();
     569           0 :                                     move16();
     570           0 :                                     move16();
     571           0 :                                     move16();
     572             :                                 }
     573             :                             }
     574             :                         }
     575             :                     }
     576             :                 }
     577             :             }
     578             :         }
     579             :     }
     580             : 
     581           0 :     return;
     582             : }
     583             : 
     584             : 
     585             : /*---------------------------------------------------------------------*
     586             :  * mat2dquat()
     587             :  *
     588             :  * Convert 4D matrix -> double quaternion
     589             :  *---------------------------------------------------------------------*/
     590             : 
     591        1750 : void mat2dquat_fx(
     592             :     const Word16 *a, // Q15
     593             :     Word16 *ql,      // Q15
     594             :     Word16 *qr       // Q15
     595             : )
     596             : {
     597             :     Word16 AM[16], tmp_l, tmp_r, temp, ql_max, qr_max;
     598             :     Word16 i, j, k, i_ql, i_qr, tmp_l_e, tmp_r_e;
     599             :     Word32 M2_fx[16];
     600             : 
     601             : 
     602             :     /* compute associate matrix */
     603             : 
     604             :     /* Q: Q15*/
     605        1750 :     AM[0 * 4 + 0] = check_bound_fx( L_shr( L_add( L_add( L_add( a[0 * 4 + 0], a[1 * 4 + 1] ), a[2 * 4 + 2] ), a[3 * 4 + 3] ), 2 ) );
     606        1750 :     AM[1 * 4 + 0] = check_bound_fx( L_shr( L_sub( L_add( L_sub( a[1 * 4 + 0], a[0 * 4 + 1] ), a[3 * 4 + 2] ), a[2 * 4 + 3] ), 2 ) );
     607        1750 :     AM[2 * 4 + 0] = check_bound_fx( L_shr( L_add( L_sub( L_sub( a[2 * 4 + 0], a[3 * 4 + 1] ), a[0 * 4 + 2] ), a[1 * 4 + 3] ), 2 ) );
     608        1750 :     AM[3 * 4 + 0] = check_bound_fx( L_shr( L_sub( L_sub( L_add( a[3 * 4 + 0], a[2 * 4 + 1] ), a[1 * 4 + 2] ), a[0 * 4 + 3] ), 2 ) );
     609        1750 :     AM[0 * 4 + 1] = check_bound_fx( L_shr( L_add( L_sub( L_sub( a[1 * 4 + 0], a[0 * 4 + 1] ), a[3 * 4 + 2] ), a[2 * 4 + 3] ), 2 ) );
     610        1750 :     AM[1 * 4 + 1] = check_bound_fx( L_shr( L_add( L_add( L_sub( -a[0 * 4 + 0], a[1 * 4 + 1] ), a[2 * 4 + 2] ), a[3 * 4 + 3] ), 2 ) );
     611        1750 :     AM[2 * 4 + 1] = check_bound_fx( L_shr( L_sub( L_sub( L_sub( -a[3 * 4 + 0], a[2 * 4 + 1] ), a[1 * 4 + 2] ), a[0 * 4 + 3] ), 2 ) );
     612        1750 :     AM[3 * 4 + 1] = check_bound_fx( L_shr( L_sub( L_add( L_sub( a[2 * 4 + 0], a[3 * 4 + 1] ), a[0 * 4 + 2] ), a[1 * 4 + 3] ), 2 ) );
     613        1750 :     AM[0 * 4 + 2] = check_bound_fx( L_shr( L_sub( L_sub( L_add( a[2 * 4 + 0], a[3 * 4 + 1] ), a[0 * 4 + 2] ), a[1 * 4 + 3] ), 2 ) );
     614        1750 :     AM[1 * 4 + 2] = check_bound_fx( L_shr( L_add( L_sub( L_sub( a[3 * 4 + 0], a[2 * 4 + 1] ), a[1 * 4 + 2] ), a[0 * 4 + 3] ), 2 ) );
     615        1750 :     AM[2 * 4 + 2] = check_bound_fx( L_shr( L_add( L_sub( L_add( -a[0 * 4 + 0], a[1 * 4 + 1] ), a[2 * 4 + 2] ), a[3 * 4 + 3] ), 2 ) );
     616        1750 :     AM[3 * 4 + 2] = check_bound_fx( L_shr( L_sub( L_sub( L_sub( -a[1 * 4 + 0], a[0 * 4 + 1] ), a[3 * 4 + 2] ), a[2 * 4 + 3] ), 2 ) );
     617        1750 :     AM[0 * 4 + 3] = check_bound_fx( L_shr( L_sub( L_add( L_sub( a[3 * 4 + 0], a[2 * 4 + 1] ), a[1 * 4 + 2] ), a[0 * 4 + 3] ), 2 ) );
     618        1750 :     AM[1 * 4 + 3] = check_bound_fx( L_shr( L_sub( L_sub( L_sub( -a[2 * 4 + 0], a[3 * 4 + 1] ), a[0 * 4 + 2] ), a[1 * 4 + 3] ), 2 ) );
     619        1750 :     AM[2 * 4 + 3] = check_bound_fx( L_shr( L_sub( L_sub( L_add( a[1 * 4 + 0], a[0 * 4 + 1] ), a[3 * 4 + 2] ), a[2 * 4 + 3] ), 2 ) );
     620        1750 :     AM[3 * 4 + 3] = check_bound_fx( L_shr( L_sub( L_add( L_add( -a[0 * 4 + 0], a[1 * 4 + 1] ), a[2 * 4 + 2] ), a[3 * 4 + 3] ), 2 ) );
     621             : 
     622        1750 :     move16();
     623        1750 :     move16();
     624        1750 :     move16();
     625        1750 :     move16();
     626        1750 :     move16();
     627        1750 :     move16();
     628        1750 :     move16();
     629        1750 :     move16();
     630        1750 :     move16();
     631        1750 :     move16();
     632        1750 :     move16();
     633        1750 :     move16();
     634        1750 :     move16();
     635        1750 :     move16();
     636        1750 :     move16();
     637        1750 :     move16();
     638        1750 :     move16();
     639             : 
     640             :     /* compute squared matrix */
     641       29750 :     FOR( i = 0; i < 16; i++ )
     642             :     {
     643       28000 :         M2_fx[i] = L_shr( L_mult0( AM[i], AM[i] ), 15 ); // Q15
     644       28000 :         move16();
     645             :     }
     646             : 
     647             :     /* determine (absolute) left and right terms */
     648        1750 :     i_ql = 0;
     649        1750 :     i_qr = 0;
     650        1750 :     ql_max = MIN_16; // Q15
     651        1750 :     qr_max = MIN_16; // Q15
     652        1750 :     move16();
     653        1750 :     move16();
     654        1750 :     move16();
     655        1750 :     move16();
     656             : 
     657        8750 :     FOR( i = 0; i < 4; i++ )
     658             :     {
     659        7000 :         tmp_l = 0;
     660        7000 :         tmp_r = 0;
     661        7000 :         move16();
     662        7000 :         move16();
     663        7000 :         tmp_r_e = 0;
     664        7000 :         tmp_l_e = 0;
     665        7000 :         move16();
     666        7000 :         move16();
     667       35000 :         FOR( j = 0; j < 4; j++ )
     668             :         {
     669             :             /* sum over row */
     670       28000 :             tmp_l_e = BASOP_Util_Add_MantExp( tmp_l, tmp_l_e, check_bound_fx( M2_fx[i * 4 + j] ), 0, &tmp_l );
     671             :             /* sum over column */
     672       28000 :             tmp_r_e = BASOP_Util_Add_MantExp( tmp_r, tmp_r_e, check_bound_fx( M2_fx[j * 4 + i] ), 0, &tmp_r );
     673             :         }
     674             : 
     675             : 
     676        7000 :         ql[i] = Sqrt16( tmp_l, &tmp_l_e );                 // tmp_l_e
     677        7000 :         ql[i] = check_bound_fx( L_shl( ql[i], tmp_l_e ) ); // Q15
     678        7000 :         move16();
     679        7000 :         move16();
     680        7000 :         IF( GT_16( ql[i], ql_max ) )
     681             :         {
     682        3626 :             ql_max = ql[i];
     683        3626 :             i_ql = i;
     684        3626 :             move16();
     685        3626 :             move16();
     686             :         }
     687             : 
     688        7000 :         qr[i] = Sqrt16( tmp_r, &tmp_r_e );                 // tmp_r_e
     689        7000 :         qr[i] = check_bound_fx( L_shl( qr[i], tmp_r_e ) ); // Q15
     690        7000 :         move16();
     691        7000 :         move16();
     692        7000 :         IF( GT_16( qr[i], qr_max ) )
     693             :         {
     694        3623 :             qr_max = qr[i]; // Q15
     695        3623 :             i_qr = i;
     696        3623 :             move16();
     697        3623 :             move16();
     698             :         }
     699             :     }
     700             : 
     701             :     /* set signs */
     702        8750 :     FOR( k = 0; k < 4; k++ )
     703             :     {
     704        7000 :         IF( AM[i_ql * 4 + k] < 0 )
     705             :         {
     706        3681 :             qr[k] = negate( qr[k] ); // Q15
     707        3681 :             move16();
     708             :         }
     709             :     }
     710             : 
     711        8750 :     FOR( k = 0; k < 4; k++ )
     712             :     {
     713        7000 :         temp = mult( AM[k * 4 + i_qr], mult( ql[k], qr[i_qr] ) ); // Q15
     714        7000 :         IF( temp < 0 )
     715             :         {
     716        2497 :             ql[k] = negate( ql[k] ); // Q15
     717        2497 :             move16();
     718             :         }
     719             :     }
     720             : 
     721        1750 :     return;
     722             : }
     723             : 
     724             : 
     725             : /*---------------------------------------------------------------------*
     726             :  * dquat2mat()
     727             :  *
     728             :  * Convert double quaternion -> 4D matrix
     729             :  *---------------------------------------------------------------------*/
     730             : 
     731       46880 : void dquat2mat_fx(
     732             :     const Word16 *ql, // Q15
     733             :     const Word16 *qr, // Q15
     734             :     Word16 *m         // Q15
     735             : )
     736             : {
     737             :     Word16 a, b, c, d;
     738             :     Word16 w, x, y, z;
     739             :     Word16 aw, ax, ay, az;
     740             :     Word16 bw, bx, by, bz;
     741             :     Word16 cw, cx, cy, cz;
     742             :     Word16 dw, dx, dy, dz;
     743             : 
     744       46880 :     a = ql[0];
     745       46880 :     move16();
     746       46880 :     b = ql[1];
     747       46880 :     move16();
     748       46880 :     c = ql[2];
     749       46880 :     move16();
     750       46880 :     d = ql[3];
     751       46880 :     move16();
     752       46880 :     w = qr[0];
     753       46880 :     move16();
     754       46880 :     x = qr[1];
     755       46880 :     move16();
     756       46880 :     y = qr[2];
     757       46880 :     move16();
     758       46880 :     z = qr[3];
     759       46880 :     move16();
     760       46880 :     aw = mult( a, w ); // Ql + Qr - 15
     761       46880 :     ax = mult( a, x );
     762       46880 :     ay = mult( a, y );
     763       46880 :     az = mult( a, z );
     764       46880 :     bw = mult( b, w );
     765       46880 :     bx = mult( b, x );
     766       46880 :     by = mult( b, y );
     767       46880 :     bz = mult( b, z );
     768       46880 :     cw = mult( c, w );
     769       46880 :     cx = mult( c, x );
     770       46880 :     cy = mult( c, y );
     771       46880 :     cz = mult( c, z );
     772       46880 :     dw = mult( d, w );
     773       46880 :     dx = mult( d, x );
     774       46880 :     dy = mult( d, y );
     775       46880 :     dz = mult( d, z );
     776             :     // Q15
     777       46880 :     m[0] = check_bound_fx( L_sub( L_sub( aw, bx ), L_add( cy, dz ) ) );
     778       46880 :     move16();
     779       46880 :     m[1] = check_bound_fx( L_sub( L_sub( cz, dy ), L_add( ax, bw ) ) );
     780       46880 :     move16();
     781       46880 :     m[2] = check_bound_fx( L_add( L_sub( L_sub( negate( ay ), bz ), cw ), dx ) );
     782       46880 :     move16();
     783       46880 :     m[3] = check_bound_fx( L_sub( L_sub( by, az ), L_add( cx, dw ) ) );
     784       46880 :     move16();
     785       46880 :     m[4] = check_bound_fx( L_add( L_sub( L_add( bw, ax ), dy ), cz ) );
     786       46880 :     move16();
     787       46880 :     m[5] = check_bound_fx( L_add( L_add( L_add( negate( bx ), aw ), dz ), cy ) );
     788       46880 :     move16();
     789       46880 :     m[6] = check_bound_fx( L_sub( L_sub( L_add( negate( by ), az ), dw ), cx ) );
     790       46880 :     move16();
     791       46880 :     m[7] = check_bound_fx( L_add( L_sub( L_sub( negate( bz ), ay ), dx ), cw ) );
     792       46880 :     move16();
     793       46880 :     m[8] = check_bound_fx( L_sub( L_add( L_add( cw, dx ), ay ), bz ) );
     794       46880 :     move16();
     795       46880 :     m[9] = check_bound_fx( L_sub( L_sub( L_add( negate( cx ), dw ), az ), by ) );
     796       46880 :     move16();
     797       46880 :     m[10] = check_bound_fx( L_add( L_add( L_add( negate( cy ), dz ), aw ), bx ) );
     798       46880 :     move16();
     799       46880 :     m[11] = check_bound_fx( L_sub( L_add( L_sub( negate( cz ), dy ), ax ), bw ) );
     800       46880 :     move16();
     801       46880 :     m[12] = check_bound_fx( L_add( L_add( L_sub( dw, cx ), by ), az ) );
     802       46880 :     move16();
     803       46880 :     m[13] = check_bound_fx( L_add( L_sub( L_sub( negate( dx ), cw ), bz ), ay ) );
     804       46880 :     move16();
     805       46880 :     m[14] = check_bound_fx( L_sub( L_add( L_sub( negate( dy ), cz ), bw ), ax ) );
     806       46880 :     move16();
     807       46880 :     m[15] = check_bound_fx( L_add( L_add( L_add( negate( dz ), cy ), bx ), aw ) );
     808       46880 :     move16();
     809             : 
     810       46880 :     return;
     811             : }
     812             : /*---------------------------------------------------------------------*
     813             :  * quat_shortestpath()
     814             :  *
     815             :  * Shortest path verification (prior to quaternion interpolation)
     816             :  *---------------------------------------------------------------------*/
     817             : 
     818             : // Not tested
     819        1172 : void quat_shortestpath_fx(
     820             :     const Word16 *q00,
     821             :     Word16 *q01,
     822             :     const Word16 *q10,
     823             :     Word16 *q11 )
     824             : {
     825             :     Word32 d0, d1;
     826             :     Word16 res, i;
     827             :     Word16 exp1, exp2;
     828        1172 :     exp1 = 0;
     829        1172 :     move16();
     830        1172 :     exp2 = 0;
     831        1172 :     move16();
     832             : 
     833        1172 :     d0 = dotp_fx( q00, q01, IVAS_PCA_INTERP, &exp1 );
     834        1172 :     d1 = dotp_fx( q10, q11, IVAS_PCA_INTERP, &exp2 );
     835             : 
     836        1172 :     res = 0;
     837        1172 :     move16();
     838        1172 :     test();
     839        1172 :     IF( d0 < 0 && d1 < 0 )
     840             :     {
     841           0 :         res = 1;
     842           0 :         move16();
     843             :     }
     844             :     ELSE
     845             :     {
     846        1172 :         IF( d0 < 0 )
     847             :         {
     848           0 :             if ( GT_32( L_negate( d0 ), d1 ) )
     849             :             {
     850           0 :                 res = 1;
     851           0 :                 move16();
     852             :             }
     853             :         }
     854             :         ELSE
     855             :         {
     856        1172 :             IF( d1 < 0 )
     857             :             {
     858           0 :                 if ( GT_32( L_negate( d1 ), d0 ) )
     859             :                 {
     860           0 :                     res = 1;
     861           0 :                     move16();
     862             :                 }
     863             :             }
     864             :         }
     865             :     }
     866             : 
     867        1172 :     IF( res )
     868             :     {
     869           0 :         FOR( i = 0; i < IVAS_PCA_INTERP; i++ )
     870             :         {
     871           0 :             q01[i] = negate( q01[i] );
     872           0 :             move16();
     873           0 :             q11[i] = negate( q11[i] );
     874           0 :             move16();
     875             :         }
     876             :     }
     877             : 
     878        1172 :     return;
     879             : }
     880             : /*---------------------------------------------------------------------*
     881             :  * mat_det4()
     882             :  *
     883             :  * Compute determinant of 4D matrix - brute-force version
     884             :  *---------------------------------------------------------------------*/
     885             : 
     886        1750 : Word16 mat_det4_fx(
     887             :     const Word16 *m // Q15
     888             : )
     889             : {
     890             :     Word16 d;
     891             : 
     892             : #define a11 m[0]
     893             : #define a12 m[1]
     894             : #define a13 m[2]
     895             : #define a14 m[3]
     896             : #define a21 m[4]
     897             : #define a22 m[5]
     898             : #define a23 m[6]
     899             : #define a24 m[7]
     900             : #define a31 m[8]
     901             : #define a32 m[9]
     902             : #define a33 m[10]
     903             : #define a34 m[11]
     904             : #define a41 m[12]
     905             : #define a42 m[13]
     906             : #define a43 m[14]
     907             : #define a44 m[15]
     908             : 
     909             :     /* 4! = 24 terms -> complexity = 24x(4 INDIRECT + 3 MULT) + 23 ADD */
     910        1750 :     d = add( add( add( sub( sub( sub( sub( sub( sub( add( add( add( add( add( add( sub( sub( sub( sub( sub( sub( add( add( mult( mult( a11, a22 ), mult( a33, a44 ) ), mult( mult( a11, a24 ), mult( a32, a43 ) ) ), mult( mult( a11, a23 ), mult( a34, a42 ) ) ), mult( mult( a11, a24 ), mult( a33, a42 ) ) ), mult( mult( a11, a22 ), mult( a34, a43 ) ) ),
     911        1750 :                                                                                                        mult( mult( a11, a23 ), mult( a32, a44 ) ) ),
     912        1750 :                                                                                                   mult( mult( a12, a21 ), mult( a33, a44 ) ) ),
     913        1750 :                                                                                              mult( mult( a12, a23 ), mult( a34, a41 ) ) ),
     914        1750 :                                                                                         mult( mult( a12, a24 ), mult( a31, a43 ) ) ),
     915        1750 :                                                                                    mult( mult( a12, a24 ), mult( a33, a41 ) ) ),
     916        1750 :                                                                               mult( mult( a12, a21 ), mult( a34, a43 ) ) ),
     917        1750 :                                                                          mult( mult( a12, a23 ), mult( a31, a44 ) ) ),
     918        1750 :                                                                     mult( mult( a13, a21 ), mult( a32, a44 ) ) ),
     919        1750 :                                                                mult( mult( a13, a22 ), mult( a34, a41 ) ) ),
     920        1750 :                                                           mult( mult( a13, a24 ), mult( a31, a42 ) ) ),
     921        1750 :                                                      mult( mult( a13, a24 ), mult( a32, a41 ) ) ),
     922        1750 :                                                 mult( mult( a13, a21 ), mult( a34, a42 ) ) ),
     923        1750 :                                            mult( mult( a13, a22 ), mult( a31, a44 ) ) ),
     924        1750 :                                       mult( mult( a14, a21 ), mult( a32, a43 ) ) ),
     925        1750 :                                  mult( mult( a14, a22 ), mult( a33, a41 ) ) ),
     926        1750 :                             mult( mult( a14, a23 ), mult( a31, a42 ) ) ),
     927        1750 :                        mult( mult( a14, a23 ), mult( a32, a41 ) ) ),
     928        1750 :                   mult( mult( a14, a21 ), mult( a33, a42 ) ) ),
     929        1750 :              mult( mult( a14, a22 ), mult( a31, a43 ) ) );
     930             : 
     931        1750 :     return d; // Q15
     932             : }
     933             : 
     934       93760 : static Word32 dotp16_fixed_guarded_fx( const Word16 x[], /* i  : vector x[]              Qx      */
     935             :                                        const Word16 y[], /* i  : vector y[]              Qy      */
     936             :                                        const Word16 n /* i  : vector length                      */ )
     937             : {
     938             :     Word16 i;
     939             :     Word32 suma;
     940       93760 :     Word16 guarded_bits = find_guarded_bits_fx( n );
     941       93760 :     suma = L_shr( L_mult( x[0], y[0] ), guarded_bits ); // Qx + Qy - guarded_bits
     942             : 
     943      375040 :     FOR( i = 1; i < n; i++ )
     944             :     {
     945      281280 :         suma = L_add( suma, L_shr( L_mult( x[i], y[i] ), guarded_bits ) ); // Qx + Qy - guarded_bits
     946             :     }
     947             : 
     948       93760 :     return suma;
     949             : }
     950             : 
     951       93760 : static void norm_quat_fx(
     952             :     Word16 *q // Q15
     953             : )
     954             : {
     955             :     Word32 norm_q;
     956             :     Word16 i, exp1;
     957       93760 :     exp1 = 0;
     958       93760 :     move16();
     959       93760 :     norm_q = dotp16_fixed_guarded_fx( q, q, IVAS_PCA_INTERP ); // (Q15 + Q15 - Q15) - exp1
     960       93760 :     exp1 = find_guarded_bits_fx( IVAS_PCA_INTERP );
     961       93760 :     norm_q = ISqrt32( norm_q, &exp1 ); /*Q(31 - exp)*/
     962             : 
     963      468800 :     FOR( i = 0; i < IVAS_PCA_INTERP; i++ )
     964             :     {
     965      375040 :         q[i] = round_fx( L_shl( Mpy_32_16_1( norm_q, q[i] ), exp1 ) ); /* Q(15) */
     966      375040 :         move16();
     967             :     }
     968             : 
     969       93760 :     return;
     970             : }
     971             : 
     972       93760 : static void quat_nlerp_preproc_fx(
     973             :     const Word16 *q0,   // Q15
     974             :     const Word16 *q1,   // Q15
     975             :     const Word16 alpha, // Q15
     976             :     Word16 *q_slerp     // Q15
     977             : )
     978             : {
     979             :     Word16 i;
     980             :     Word16 tmp1, tmp2;
     981             : 
     982      468800 :     FOR( i = 0; i < IVAS_PCA_INTERP; i++ )
     983             :     {
     984      375040 :         tmp1 = mult( sub( MAX_16, alpha ), q1[i] );
     985      375040 :         tmp2 = mult_r( alpha, q0[i] );
     986      375040 :         test();
     987      375040 :         if ( EQ_16( alpha, q0[i] ) && EQ_16( alpha, MAX_16 ) )
     988             :         {
     989        2332 :             tmp2 = MAX_16;
     990        2332 :             move16();
     991             :         }
     992      375040 :         q_slerp[i] = add( tmp1, tmp2 ); // Q15
     993      375040 :         move16();
     994             :     }
     995             : 
     996       93760 :     norm_quat_fx( q_slerp );
     997             : 
     998       93760 :     return;
     999             : }
    1000             : 
    1001        1172 : void pca_interp_preproc_fx(
    1002             :     const Word16 *prev_ql, // Q15
    1003             :     const Word16 *prev_qr, // Q15
    1004             :     const Word16 *ql,      // Q15
    1005             :     const Word16 *qr,      // Q15
    1006             :     const Word16 len,
    1007             :     Word16 *ql_interp, // Q15
    1008             :     Word16 *qr_interp  // Q15
    1009             : )
    1010             : {
    1011             :     Word16 alpha;
    1012             :     Word16 j;
    1013             :     Word16 tmp, tmp2, tmp3, tmp_e;
    1014       48052 :     FOR( j = 0; j < len; j++ )
    1015             :     {
    1016       46880 :         tmp = sub( len, 1 );
    1017       46880 :         IF( j == 0 )
    1018             :         {
    1019        1172 :             alpha = 0;
    1020        1172 :             move16();
    1021             :         }
    1022             :         ELSE
    1023             :         {
    1024       45708 :             alpha = BASOP_Util_Divide1616_Scale( j, tmp, &tmp_e ); // the increment can be updated by simple delta
    1025       45708 :             alpha = shl_sat( alpha, tmp_e );                       /* Q15 */
    1026             :         }
    1027       46880 :         tmp2 = mult( EVS_PI_FX, alpha );     /* Q13 */
    1028       46880 :         tmp3 = getCosWord16( tmp2 );         /* Q14 */
    1029       46880 :         alpha = sub_sat( ONE_IN_Q14, tmp3 ); /* Q15 */
    1030       46880 :         alpha = sub( MAX_16, alpha );        // Q15
    1031       46880 :         quat_nlerp_preproc_fx( prev_ql, ql, alpha, &ql_interp[j * IVAS_PCA_INTERP] );
    1032       46880 :         quat_nlerp_preproc_fx( prev_qr, qr, alpha, &qr_interp[j * IVAS_PCA_INTERP] );
    1033             :     }
    1034             : 
    1035        1172 :     return;
    1036             : }
    1037             : 
    1038           0 : static Word16 acos_clip_fx(
    1039             :     Word16 v_fx // Q15
    1040             : )
    1041             : {
    1042             :     Word16 ph_fx;
    1043             : 
    1044           0 :     v_fx = check_bounds_s_fx( v_fx, -32767, 32767 ); // Q15
    1045             : 
    1046             :     Word32 tmp1_fx, tmp2_fx;
    1047             :     Word16 tmp1_e, tmp2_e;
    1048           0 :     tmp1_fx = L_sub( ONE_IN_Q31, L_deposit_h( mult( v_fx, v_fx ) ) ); // Q31
    1049           0 :     tmp1_e = 0;
    1050           0 :     tmp2_e = 0;
    1051           0 :     move16();
    1052           0 :     move16();
    1053           0 :     tmp1_fx = Sqrt32( tmp1_fx, &tmp1_e ); // Q31 - tmp1_e
    1054           0 :     tmp2_fx = L_deposit_h( v_fx );        // Q31
    1055             : 
    1056           0 :     ph_fx = BASOP_util_atan2( tmp1_fx, tmp2_fx, sub( tmp1_e, tmp2_e ) ); // Q13
    1057             : 
    1058             : 
    1059           0 :     return ph_fx; // Q13
    1060             : }
    1061             : 
    1062          12 : static void sp2cart_fx(
    1063             :     const Word16 ph1, // Q12
    1064             :     const Word16 ph2, // Q12
    1065             :     const Word16 ph3, // Q12
    1066             :     Word16 *q         // Q15
    1067             : )
    1068             : {
    1069             :     Word16 s1, s2, s1s2;
    1070             :     Word16 sin_ph3, cos_ph3;
    1071             : 
    1072          12 :     sin_ph3 = cos_ph3 = ph3; // Q12
    1073          12 :     move16();
    1074          12 :     move16();
    1075             : 
    1076          12 :     IF( GT_16( ph3, 12868 /* PI in Q12 */ ) )
    1077             :     {
    1078           6 :         sin_ph3 = sub( 12868, ph3 ); /* sin(x) = sin(PI - x) */
    1079           6 :         cos_ph3 = sub( 25736, ph3 ); /* cos(x) = cos(2*PI - x) */
    1080             :     }
    1081          12 :     sin_ph3 = shl( sin_ph3, 1 ); /* Q12 -> Q13 */
    1082          12 :     cos_ph3 = shl( cos_ph3, 1 ); /* Q12 -> Q13 */
    1083             : 
    1084          12 :     s1 = getSinWord16( ph1 );                     /* Q15 */
    1085          12 :     s2 = getSinWord16( ph2 );                     /* Q15 */
    1086          12 :     s1s2 = mult( s1, s2 );                        /* Q15 */
    1087          12 :     q[3] = mult( getSinWord16( sin_ph3 ), s1s2 ); /* Q15 */
    1088          12 :     move16();
    1089          12 :     q[2] = shl_sat( mult( getCosWord16( cos_ph3 ), s1s2 ), 1 ); /* Q15 */
    1090          12 :     move16();
    1091          12 :     q[1] = shl_sat( mult( getCosWord16( ph2 ), s1 ), 1 ); /* Q15 */
    1092          12 :     move16();
    1093          12 :     q[0] = shl_sat( getCosWord16( ph1 ), 1 ); /* Q15 */
    1094          12 :     move16();
    1095             : 
    1096          12 :     return;
    1097             : }
    1098             : 
    1099           0 : static Word16 calc_n2_fx(
    1100             :     const Word16 ph1 // Q15
    1101             : )
    1102             : {
    1103             :     Word16 n2;
    1104             : 
    1105           0 :     n2 = extract_l( L_shr( L_mult0( 90, getSinWord16( ph1 ) ), 15 ) ); // Q15 + Q0 - Q15 -> Q0
    1106             : 
    1107           0 :     if ( n2 % 2 == 0 )
    1108             :     {
    1109           0 :         n2 = add( n2, 1 );
    1110             :     }
    1111             : 
    1112           0 :     return n2; // Q0
    1113             : }
    1114             : 
    1115             : 
    1116          12 : static Word16 calc_n3_fx(
    1117             :     const Word16 ph1,
    1118             :     const Word16 ph2 )
    1119             : {
    1120             :     Word16 n3;
    1121          12 :     Word16 temp1 = mult( getSinWord16( ph2 ), getSinWord16( ph1 ) ); /* Q15 */
    1122          12 :     n3 = round_fx( L_mult( temp1, 23040 /* 180.0f in Q7 */ ) );      /* Q15 + Q7 + Q1 - Q16 -> Q7*/
    1123             : 
    1124          12 :     n3 = shr( n3, 7 );
    1125             : 
    1126          12 :     IF( n3 == 0 )
    1127             :     {
    1128           0 :         n3 = 1;
    1129           0 :         move16();
    1130             :     }
    1131             :     ELSE
    1132             :     {
    1133          12 :         IF( EQ_16( s_and( n3, 1 ), 1 ) )
    1134             :         {
    1135          10 :             n3 = add( n3, 1 );
    1136             :         }
    1137             :     }
    1138             : 
    1139          12 :     return n3;
    1140             : }
    1141             : 
    1142           0 : static void q_ang_2surv_fx(
    1143             :     const Word16 a_fx, // Q13
    1144             :     const Word16 N,
    1145             :     Word16 *a_q_fx, // Q15
    1146             :     Word16 *index )
    1147             : {
    1148             :     Word16 d_fx, v_fx, d_e, v_e;
    1149             :     Word16 temp;
    1150             : 
    1151           0 :     IF( EQ_16( N, 1 ) )
    1152             :     {
    1153           0 :         index[0] = 0;
    1154           0 :         index[1] = 0;
    1155             : 
    1156           0 :         a_q_fx[0] = 0;
    1157           0 :         a_q_fx[1] = 0;
    1158           0 :         move16();
    1159           0 :         move16();
    1160           0 :         move16();
    1161           0 :         move16();
    1162           0 :         return;
    1163             :     }
    1164             : 
    1165           0 :     d_fx = BASOP_Util_Divide1616_Scale( EVS_PI_FX, sub( N, 1 ), &d_e );
    1166           0 :     d_e = add( d_e, ( 2 - 15 ) );
    1167           0 :     IF( GE_16( a_fx, EVS_PI_FX ) )
    1168             :     {
    1169           0 :         index[0] = sub( N, 1 );
    1170           0 :         index[1] = sub( N, 2 );
    1171           0 :         move16();
    1172           0 :         move16();
    1173             :     }
    1174             :     ELSE
    1175             :     {
    1176           0 :         IF( a_fx <= 0 )
    1177             :         {
    1178           0 :             index[0] = 0;
    1179           0 :             index[1] = 1;
    1180           0 :             move16();
    1181           0 :             move16();
    1182             :         }
    1183             :         ELSE
    1184             :         {
    1185           0 :             v_fx = BASOP_Util_Divide1616_Scale( a_fx, d_fx, &v_e );
    1186           0 :             v_e = add( v_e, sub( 2, d_e ) );
    1187             : 
    1188           0 :             index[0] = shr( v_fx, sub( Q15, v_e ) );
    1189           0 :             index[1] = add( shr( v_fx, sub( Q15, v_e ) ), 1 );
    1190           0 :             move16();
    1191           0 :             move16();
    1192             : 
    1193           0 :             IF( EQ_16( index[0], index[1] ) )
    1194             :             {
    1195             :                 /*printf("warning: identical indices\n"); */
    1196             :             }
    1197             :             ELSE
    1198             :             {
    1199           0 :                 IF( LT_16( sub( shr( v_fx, sub( Q15, v_e ) ), index[0] ), sub( index[1], shr( v_fx, sub( Q15, v_e ) ) ) ) )
    1200             :                 {
    1201           0 :                     temp = index[1];
    1202           0 :                     index[1] = index[0];
    1203           0 :                     index[0] = temp;
    1204           0 :                     move16();
    1205           0 :                     move16();
    1206           0 :                     move16();
    1207             :                 }
    1208             :             }
    1209             :         }
    1210             :     }
    1211             : 
    1212           0 :     a_q_fx[0] = extract_l( L_shr( L_mult0( index[0], d_fx ), 2 - d_e ) ); // Q13
    1213           0 :     a_q_fx[1] = extract_l( L_shr( L_mult0( index[1], d_fx ), 2 - d_e ) ); // Q13
    1214           0 :     move16();
    1215           0 :     move16();
    1216             : 
    1217           0 :     return;
    1218             : }
    1219             : 
    1220           0 : static void q_ang_circ_fx(
    1221             :     const Word16 a_fx, // Q13
    1222             :     const Word16 N,
    1223             :     Word16 *a_q_fx, // Q12
    1224             :     Word16 *index )
    1225             : {
    1226             :     Word16 d_fx, d_e, scale;
    1227           0 :     IF( EQ_16( N, 1 ) )
    1228             :     {
    1229           0 :         *a_q_fx = 0;
    1230           0 :         *index = 0;
    1231           0 :         move16();
    1232           0 :         move16();
    1233           0 :         return;
    1234             :     }
    1235             : 
    1236           0 :     d_fx = BASOP_Util_Divide1616_Scale( EVS_PI_FX, N, &d_e ); // Q14
    1237           0 :     d_e = add( d_e, ( 3 - 15 ) );
    1238             : 
    1239           0 :     IF( GE_16( a_fx, EVS_PI_FX ) )
    1240             :     {
    1241           0 :         *index = N;
    1242           0 :         move16();
    1243             :     }
    1244             :     ELSE
    1245             :     {
    1246           0 :         IF( a_fx <= 0 )
    1247             :         {
    1248           0 :             *index = 0;
    1249           0 :             move16();
    1250             :         }
    1251             :         ELSE
    1252             :         {
    1253           0 :             *index = BASOP_Util_Divide1616_Scale( a_fx, d_fx, &scale );
    1254           0 :             scale = add( scale, sub( 3, d_e ) );
    1255           0 :             *index = shr( *index, sub( 15, scale ) );
    1256           0 :             move16();
    1257           0 :             move16();
    1258             :         }
    1259             :     }
    1260             : 
    1261           0 :     if ( EQ_16( *index, N ) )
    1262             :     {
    1263           0 :         *index = 0;
    1264           0 :         move16();
    1265             :     }
    1266             : 
    1267           0 :     assert( ( *index >= 0 ) && ( *index <= ( N - 1 ) ) );
    1268           0 :     d_fx = shl( d_fx, sub( 12, sub( 15, d_e ) ) );  // Q12
    1269           0 :     *a_q_fx = extract_l( L_mult0( *index, d_fx ) ); // Q12
    1270           0 :     move16();
    1271             : 
    1272           0 :     return;
    1273             : }
    1274             : 
    1275           0 : static Word16 sel_q_fx(
    1276             :     const Word16 *q,      // Q12
    1277             :     const Word16 *q_cand, // Q12
    1278             :     const Word16 n )
    1279             : {
    1280             :     Word16 i, i_min, j, temp;
    1281             :     Word32 d, d_min;
    1282             :     const Word16 *p;
    1283             : 
    1284           0 :     i_min = -1;
    1285           0 :     move16();
    1286           0 :     d_min = MAX_32;
    1287           0 :     move32();
    1288           0 :     p = q_cand;
    1289             : 
    1290           0 :     FOR( i = 0; i < n; i++ )
    1291             :     {
    1292           0 :         d = 0;
    1293           0 :         move16();
    1294           0 :         FOR( j = 0; j < 4; j++ )
    1295             :         {
    1296           0 :             temp = sub( q[j], p[j] );
    1297           0 :             d = L_add( d, L_mult0( temp, temp ) );
    1298             :         }
    1299             : 
    1300           0 :         IF( LT_32( d, d_min ) )
    1301             :         {
    1302           0 :             d_min = d;
    1303           0 :             i_min = i;
    1304           0 :             move16();
    1305           0 :             move16();
    1306             :         }
    1307           0 :         p += 4;
    1308             :     }
    1309           0 :     assert( i_min >= 0 );
    1310             : 
    1311           0 :     return i_min;
    1312             : }
    1313             : 
    1314         316 : static Word16 get_pca_offset_n2_fx(
    1315             :     const Word16 index1 )
    1316             : {
    1317             :     Word16 index2;
    1318         316 :     IF( LE_16( index1, IVAS_PCA_N1_EQ ) )
    1319             :     {
    1320         316 :         index2 = ivas_pca_offset_n2[index1];
    1321         316 :         move16();
    1322             :     }
    1323             :     ELSE
    1324             :     {
    1325           0 :         index2 = ivas_pca_offset_n2[IVAS_PCA_N1 - 1 - index1];
    1326           0 :         move16();
    1327             :     }
    1328             : 
    1329         316 :     return index2;
    1330             : }
    1331             : 
    1332             : /*---------------------------------------------------------------------*
    1333             :  * pca_enc_s3()
    1334             :  *
    1335             :  *
    1336             :  *---------------------------------------------------------------------*/
    1337             : 
    1338           0 : void pca_enc_s3_fx(
    1339             :     Word16 *q_fx, // Q15
    1340             :     Word32 *index )
    1341             : {
    1342             :     Word16 n1, n2[2], n3[4];
    1343             :     Word16 ind1[2], ind2[4], ind3[4], index1, index2, index3;
    1344             :     Word16 i, j;
    1345             :     Word16 ph1_fx, ph2_fx, ph3_fx, r_fx, v_fx, tmp, r_e;
    1346             :     Word16 ph1_q_fx[2], ph2_q_fx[4], ph3_q_fx[4], v_e;
    1347             :     Word16 q_cand_fx[4 * 4];
    1348             : 
    1349           0 :     n1 = IVAS_PCA_N1;
    1350           0 :     move16();
    1351           0 :     ph1_fx = acos_clip_fx( q_fx[0] ); // Q13
    1352             : 
    1353           0 :     IF( LT_16( abs_s( sub( abs_s( q_fx[0] ), 32767 ) ), IVAS_PCA_QUAT_EPS_FX ) )
    1354             :     {
    1355           0 :         IF( q_fx[0] > 0 )
    1356             :         {
    1357           0 :             index1 = 0;
    1358           0 :             *ph1_q_fx = 0;
    1359           0 :             move16();
    1360           0 :             move16();
    1361             :         }
    1362             :         ELSE
    1363             :         {
    1364           0 :             index1 = sub( n1, 1 );
    1365           0 :             *ph1_q_fx = EVS_PI_FX; // Q13
    1366           0 :             move16();
    1367           0 :             move16();
    1368             :         }
    1369             : 
    1370           0 :         sp2cart_fx( *ph1_q_fx, 0, 0, q_fx );
    1371             : 
    1372           0 :         *index = ivas_pca_offset_index1[index1];
    1373           0 :         move32();
    1374             : 
    1375           0 :         return;
    1376             :     }
    1377             : 
    1378           0 :     q_ang_2surv_fx( ph1_fx, n1, ph1_q_fx, ind1 );
    1379             : 
    1380           0 :     tmp = add( add( mult( q_fx[1], q_fx[1] ), mult( q_fx[2], q_fx[2] ) ), mult( q_fx[3], q_fx[3] ) ); // Q15 + Q15 - Q15 -> Q15
    1381           0 :     r_e = 0;
    1382           0 :     move16();
    1383           0 :     r_fx = Sqrt16( tmp, &r_e );
    1384           0 :     v_fx = BASOP_Util_Divide1616_Scale( q_fx[1], r_fx, &v_e );
    1385           0 :     v_e = sub( v_e, sub( 0, r_e ) );
    1386           0 :     v_fx = shr( v_fx, sub( 0, v_e ) );
    1387           0 :     ph2_fx = acos_clip_fx( v_fx ); // Q13
    1388             : 
    1389           0 :     IF( LT_16( sub( abs_s( v_fx ), MAX_16 ), IVAS_PCA_QUAT_EPS_FX ) )
    1390             :     {
    1391           0 :         FOR( i = 0; i < 2; i++ )
    1392             :         {
    1393           0 :             IF( v_fx > 0 )
    1394             :             {
    1395           0 :                 ph2_q_fx[i] = 0;
    1396           0 :                 ind2[i] = 0;
    1397           0 :                 move16();
    1398           0 :                 move16();
    1399             :             }
    1400             :             ELSE
    1401             :             {
    1402           0 :                 ph2_q_fx[i] = EVS_PI_FX;
    1403           0 :                 ind2[i] = sub( n2[i], 1 );
    1404           0 :                 move16();
    1405           0 :                 move16();
    1406             :             }
    1407             : 
    1408           0 :             sp2cart_fx( ph1_q_fx[i], ph2_q_fx[i], 0, &q_cand_fx[4 * i] );
    1409             :         }
    1410             : 
    1411           0 :         j = sel_q_fx( q_fx, q_cand_fx, 2 );
    1412             : 
    1413           0 :         Copy( q_cand_fx + 4 * j, q_fx, 4 );
    1414           0 :         index1 = ind1[j];
    1415           0 :         index2 = ind2[j];
    1416           0 :         move16();
    1417           0 :         move16();
    1418             : 
    1419           0 :         index2 = add( index2, get_pca_offset_n2_fx( index1 ) );
    1420             : 
    1421           0 :         *index = L_add( ivas_pca_offset_index1[index1], ivas_pca_offset_index2[index2] );
    1422           0 :         move32();
    1423             : 
    1424           0 :         return;
    1425             :     }
    1426             : 
    1427           0 :     FOR( i = 0; i < 2; i++ )
    1428             :     {
    1429           0 :         n2[i] = calc_n2_fx( ph1_q_fx[i] );
    1430           0 :         move16();
    1431           0 :         q_ang_2surv_fx( ph2_fx, n2[i], ph2_q_fx + 2 * i, ind2 + 2 * i );
    1432             :     }
    1433             : 
    1434           0 :     r_fx = Sqrt16( add( mult( q_fx[2], q_fx[2] ), mult( q_fx[3], q_fx[3] ) ), &r_e );
    1435             : 
    1436             : 
    1437           0 :     v_fx = BASOP_Util_Divide1616_Scale( q_fx[2], r_fx, &v_e );
    1438           0 :     v_e = add( v_e, sub( 0, r_e ) );
    1439           0 :     v_fx = shr( v_fx, sub( 0, v_e ) ); // Q15
    1440           0 :     ph3_fx = acos_clip_fx( v_fx );     // Q13
    1441             : 
    1442           0 :     IF( q_fx[3] < 0 )
    1443             :     {
    1444           0 :         ph3_fx = sub( EVS_PI_FX, shr( ph3_fx, 1 ) ); // Q12
    1445             :     }
    1446             : 
    1447           0 :     FOR( i = 0; i < 4; i++ )
    1448             :     {
    1449           0 :         n3[i] = calc_n3_fx( ph1_q_fx[i >> 1], ph2_q_fx[i] );
    1450           0 :         move16();
    1451           0 :         q_ang_circ_fx( ph3_fx, n3[i], ph3_q_fx + i, ind3 + i );
    1452           0 :         sp2cart_fx( ph1_q_fx[i >> 1], ph2_q_fx[i], ph3_q_fx[i], q_cand_fx + ( 4 * i ) );
    1453             :     }
    1454             : 
    1455           0 :     j = sel_q_fx( q_fx, q_cand_fx, 4 );
    1456             : 
    1457           0 :     Copy( q_cand_fx + 4 * j, q_fx, 4 );
    1458             : 
    1459           0 :     index1 = ind1[j >> 1];
    1460           0 :     index2 = ind2[j];
    1461           0 :     index3 = ind3[j];
    1462           0 :     move16();
    1463           0 :     move16();
    1464           0 :     move16();
    1465           0 :     index2 = add( index2, get_pca_offset_n2_fx( index1 ) );
    1466             : 
    1467           0 :     *index = L_add( L_add( ivas_pca_offset_index1[index1], ivas_pca_offset_index2[index2] ), index3 );
    1468           0 :     move32();
    1469             : 
    1470           0 :     return;
    1471             : }
    1472             : 
    1473             : /*---------------------------------------------------------------------*
    1474             :  * pca_dec_s3()
    1475             :  *
    1476             :  *
    1477             :  *---------------------------------------------------------------------*/
    1478             : 
    1479             : 
    1480             : // Not tested
    1481          12 : void pca_dec_s3_fx(
    1482             :     const Word32 index,
    1483             :     Word16 *q_fx )
    1484             : {
    1485             :     Word16 ph1_q_fx, ph2_q_fx, ph3_q_fx, num_fx;
    1486             : 
    1487             :     Word32 j;
    1488             :     Word16 i;
    1489             :     Word16 n2, n3;
    1490             : 
    1491             :     Word16 index1, index2, index3;
    1492             :     Word16 d_fx, exp;
    1493             : 
    1494          12 :     j = index;
    1495          12 :     move16();
    1496          12 :     index1 = -1;
    1497          12 :     move16();
    1498         215 :     FOR( i = 0; i < IVAS_PCA_N1; i++ )
    1499             :     {
    1500         215 :         IF( LT_32( j, ivas_pca_offset_index1[i + 1] ) )
    1501             :         {
    1502          12 :             index1 = i;
    1503          12 :             move16();
    1504          12 :             BREAK;
    1505             :         }
    1506             :     }
    1507             : 
    1508          12 :     assert( index1 > -1 );
    1509             : 
    1510          12 :     ph1_q_fx = ph1_q_n2_tbl[index1][0]; // Q13
    1511          12 :     move16();
    1512          12 :     n2 = ph1_q_n2_tbl[index1][1]; // Q0
    1513          12 :     move16();
    1514             : 
    1515          12 :     j = L_sub( j, ivas_pca_offset_index1[index1] );
    1516          12 :     index2 = -1;
    1517          12 :     move16();
    1518         304 :     FOR( i = 0; i < n2; i++ )
    1519             :     {
    1520         304 :         IF( LT_32( j, L_deposit_l( ivas_pca_offset_index2[add( add( i, get_pca_offset_n2_fx( index1 ) ), 1 )] ) ) )
    1521             :         {
    1522          12 :             index2 = i;
    1523          12 :             move16();
    1524          12 :             BREAK;
    1525             :         }
    1526             :     }
    1527             : 
    1528          12 :     assert( index2 > -1 );
    1529             : 
    1530          12 :     IF( EQ_16( n2, 1 ) )
    1531             :     {
    1532           0 :         ph2_q_fx = 0;
    1533           0 :         move16();
    1534             :     }
    1535             :     ELSE
    1536             :     {
    1537             : 
    1538          12 :         num_fx = 12868; // EVS_PI in Q12
    1539          12 :         move16();
    1540             : 
    1541          12 :         d_fx = BASOP_Util_Divide1616_Scale( num_fx, sub( n2, 1 ), &exp ); /* Q12 */
    1542          12 :         exp = add( 3 - 15, exp );
    1543          12 :         d_fx = shl( d_fx, sub( exp, 3 ) ); /* Q12 */
    1544             : 
    1545          12 :         ph2_q_fx = i_mult( index2, d_fx ); // Q12
    1546          12 :         ph2_q_fx = shl( ph2_q_fx, 1 );     /* Q12 -> Q13 */
    1547             :     }
    1548             : 
    1549          12 :     j = L_sub( j, ivas_pca_offset_index2[add( index2, get_pca_offset_n2_fx( index1 ) )] );
    1550             : 
    1551          12 :     index3 = extract_l( j );
    1552             : 
    1553          12 :     n3 = calc_n3_fx( ph1_q_fx, ph2_q_fx );
    1554             : 
    1555          12 :     IF( EQ_16( n3, 1 ) )
    1556             :     {
    1557           0 :         ph3_q_fx = 0;
    1558           0 :         move16();
    1559             :     }
    1560             :     ELSE
    1561             :     {
    1562          12 :         num_fx = 25736; /* PI2 in Q12 */
    1563          12 :         move16();
    1564          12 :         d_fx = BASOP_Util_Divide1616_Scale( num_fx, n3, &exp ); /* Q12 */
    1565          12 :         exp = add( 3 - 15, exp );
    1566          12 :         d_fx = shl( d_fx, sub( exp, 3 ) ); /* Q12 */
    1567          12 :         ph3_q_fx = i_mult( index3, d_fx ); /* Q12 */
    1568             :     }
    1569          12 :     sp2cart_fx( ph1_q_fx, ph2_q_fx, ph3_q_fx, q_fx );
    1570             : 
    1571          12 :     return;
    1572             : }

Generated by: LCOV version 1.14