LCOV - code coverage report
Current view: top level - lib_rend - ivas_rotation_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 1068 1162 91.9 %
Date: 2025-08-23 01:22:27 Functions: 28 28 100.0 %

          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 <assert.h>
      34             : #include <stdint.h>
      35             : #include "basop_util.h"
      36             : #include "ivas_cnst.h"
      37             : #include "options.h"
      38             : #include <math.h>
      39             : #include "cnst.h"
      40             : #include "prot_fx.h"
      41             : #include "ivas_prot_rend_fx.h"
      42             : #include "wmc_auto.h"
      43             : #include <stdio.h>
      44             : #include "ivas_prot_fx.h"
      45             : #include "debug.h"
      46             : #include "ivas_rom_binaural_crend_head.h"
      47             : 
      48             : 
      49             : /*-----------------------------------------------------------------------*
      50             :  * Local ROM tables
      51             :  *-----------------------------------------------------------------------*/
      52             : 
      53             : static Word16 square_root16_table[] = { 0, 0x4000, 0x5A82 }; // Q14
      54             : 
      55             : static Word16 square_root30_q12[31] = {
      56             :     // Q12
      57             :     0,
      58             :     4096,
      59             :     5793,
      60             :     7094,
      61             :     8192,
      62             :     9159,
      63             :     10033,
      64             :     10837,
      65             :     11585,
      66             :     12288,
      67             :     12953,
      68             :     13585,
      69             :     14189,
      70             :     14768,
      71             :     15326,
      72             :     15864,
      73             :     16384,
      74             :     16888,
      75             :     17378,
      76             :     17854,
      77             :     18318,
      78             :     18770,
      79             :     19212,
      80             :     19644,
      81             :     20066,
      82             :     20480,
      83             :     20886,
      84             :     21283,
      85             :     21674,
      86             :     22058,
      87             :     22435,
      88             : };
      89             : 
      90             : /*-----------------------------------------------------------------------*
      91             :  * Local function declarations
      92             :  *-----------------------------------------------------------------------*/
      93             : 
      94             : static ivas_error combine_external_and_head_orientations( IVAS_QUATERNION *headRotQuaternions, IVAS_VECTOR3 *listenerPos, ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis, EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, COMBINED_ORIENTATION_HANDLE hCombinedOrientationData );
      95             : 
      96             : static void external_target_interpolation_fx( EXTERNAL_ORIENTATION_HANDLE hExtOrientationData, COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, const Word16 i );
      97             : 
      98             : static bool are_orientations_same_fx( const IVAS_QUATERNION *orientation1, const IVAS_QUATERNION *orientation2 );
      99             : 
     100             : 
     101             : /*-----------------------------------------------------------------------*
     102             :  * ivas_headTrack_open()
     103             :  *
     104             :  * Allocate and initialize Head-Tracking handle
     105             :  *-----------------------------------------------------------------------*/
     106             : 
     107          82 : ivas_error ivas_headTrack_open_fx(
     108             :     HEAD_TRACK_DATA_HANDLE *hHeadTrackData /* o  : head track handle    */
     109             : )
     110             : {
     111             :     Word16 i;
     112             :     ivas_error error;
     113             : 
     114             :     /* Allocate Head-Tracking handle */
     115          82 :     IF( ( *hHeadTrackData = (HEAD_TRACK_DATA_HANDLE) malloc( sizeof( HEAD_TRACK_DATA ) ) ) == NULL )
     116             :     {
     117           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for head-tracking memory\n" ) );
     118             :     }
     119             : 
     120             :     /* Initialization */
     121          82 :     ( *hHeadTrackData )->lrSwitchInterpVal_fx = 0; // Q30
     122          82 :     move32();
     123          82 :     ( *hHeadTrackData )->lrSwitchedCurrent = 0;
     124          82 :     move32();
     125          82 :     ( *hHeadTrackData )->lrSwitchedNext = 0;
     126          82 :     move32();
     127          82 :     IF( ( ( *hHeadTrackData )->OrientationTracker = (ivas_orient_trk_state_t *) malloc( sizeof( ivas_orient_trk_state_t ) ) ) == NULL )
     128             :     {
     129           0 :         return IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for Orientation tracking" );
     130             :     }
     131             : 
     132          82 :     IF( NE_32( ( error = ivas_orient_trk_Init_fx( ( *hHeadTrackData )->OrientationTracker ) ), IVAS_ERR_OK ) )
     133             :     {
     134           0 :         return error;
     135             :     }
     136             : 
     137             :     /* Initialise Rmat_prev to I, Rmat will be computed later */
     138         328 :     FOR( i = 0; i < 3; i++ )
     139             :     {
     140         246 :         set32_fx( ( *hHeadTrackData )->Rmat_prev_fx[i], 0, 3 );
     141         246 :         ( *hHeadTrackData )->Rmat_prev_fx[i][i] = ONE_IN_Q31; // Q31
     142         246 :         move32();
     143             :     }
     144             : 
     145          82 :     ( *hHeadTrackData )->sr_pose_pred_axis = DEFAULT_AXIS;
     146          82 :     move32();
     147             : 
     148          82 :     set32_fx( ( *hHeadTrackData )->chEneIIR_fx[0], 0, MASA_FREQUENCY_BANDS );
     149          82 :     set32_fx( ( *hHeadTrackData )->chEneIIR_fx[1], 0, MASA_FREQUENCY_BANDS );
     150          82 :     set32_fx( ( *hHeadTrackData )->procChEneIIR_fx[0], 0, MASA_FREQUENCY_BANDS );
     151          82 :     set32_fx( ( *hHeadTrackData )->procChEneIIR_fx[1], 0, MASA_FREQUENCY_BANDS );
     152             : 
     153          82 :     return IVAS_ERR_OK;
     154             : }
     155             : 
     156             : 
     157             : /*-----------------------------------------------------------------------*
     158             :  * ivas_headTrack_close()
     159             :  *
     160             :  * Deallocate Head-Tracking handle
     161             :  *-----------------------------------------------------------------------*/
     162         613 : void ivas_headTrack_close_fx(
     163             :     HEAD_TRACK_DATA_HANDLE *hHeadTrackData /* i/o: head track handle    */
     164             : )
     165             : {
     166         613 :     test();
     167         613 :     IF( hHeadTrackData == NULL || *hHeadTrackData == NULL )
     168             :     {
     169         531 :         return;
     170             :     }
     171             : 
     172          82 :     IF( ( *hHeadTrackData )->OrientationTracker != NULL )
     173             :     {
     174          82 :         free( ( *hHeadTrackData )->OrientationTracker );
     175          82 :         ( *hHeadTrackData )->OrientationTracker = NULL;
     176             :     }
     177             : 
     178          82 :     free( ( *hHeadTrackData ) );
     179          82 :     *hHeadTrackData = NULL;
     180             : 
     181          82 :     return;
     182             : }
     183             : 
     184             : /*----------------------------------------------------------------------------------
     185             :  * QuatToRotMat()
     186             :  *
     187             :  * Quaternion handling: calculate rotation matrices in real-space and SHD
     188             :  *---------------------------------------------------------------------------------*/
     189             : 
     190      921170 : void QuatToRotMat_fx(
     191             :     const IVAS_QUATERNION quat, /* i  : quaternion describing the rotation            Qx      */
     192             :     Word32 Rmat[3][3]           /* o  : real-space rotation matrix for this rotation  2*Qx-32 */
     193             : )
     194             : {
     195             : 
     196      921170 :     IF( EQ_32( quat.w_fx, L_negate( 12582912 ) ) )
     197             :     {
     198           0 :         assert( 0 );
     199             :         // IVAS_QUATERNION quat_local;
     200             :         // Euler2Quat_fx( deg2rad( quat.x_fx ), deg2rad( quat.y_fx ), deg2rad( quat.z_fx ), &quat_local );
     201             :         // QuatToRotMat_fx( quat_local, Rmat );
     202             :     }
     203             :     else
     204             :     {
     205      921170 :         Word32 w = quat.w_fx; // Qx
     206      921170 :         move32();
     207      921170 :         Word32 x = quat.x_fx;
     208      921170 :         move32();
     209      921170 :         Word32 y = quat.y_fx;
     210      921170 :         move32();
     211      921170 :         Word32 z = quat.z_fx;
     212      921170 :         move32();
     213             : 
     214             :         // Adding a guard bit to squared terms since 2*x is not being done in those
     215             :         // statements (R[0][0], R[1][1], R[2][2]). This is done to avoid L_shl.
     216      921170 :         Word32 ww = L_shr( Mpy_32_32( w, w ), 1 ); // 2 * Qx - 31 - 1 = 2*Qx-32
     217      921170 :         Word32 xx = L_shr( Mpy_32_32( x, x ), 1 );
     218      921170 :         Word32 yy = L_shr( Mpy_32_32( y, y ), 1 );
     219      921170 :         Word32 zz = L_shr( Mpy_32_32( z, z ), 1 );
     220             : 
     221      921170 :         Word32 wx = Mpy_32_32( w, x ); // 2 * Qx - 31
     222      921170 :         Word32 wz = Mpy_32_32( w, z );
     223      921170 :         Word32 wy = Mpy_32_32( w, y );
     224             : 
     225      921170 :         Word32 xy = Mpy_32_32( x, y );
     226      921170 :         Word32 xz = Mpy_32_32( x, z );
     227             : 
     228      921170 :         Word32 yz = Mpy_32_32( y, z );
     229             : 
     230      921170 :         Rmat[0][0] = L_sub( L_sub( L_add( ww, xx ), yy ), zz ); // 2 * Qx - 31 - 1 = 2*Qx-32
     231      921170 :         move32();
     232      921170 :         Rmat[0][1] = L_sub( xy, wz );
     233      921170 :         move32();
     234      921170 :         Rmat[0][2] = L_add( xz, wy );
     235      921170 :         move32();
     236             : 
     237      921170 :         Rmat[1][0] = L_add( xy, wz ); // 2 * Qx - 32
     238      921170 :         move32();
     239      921170 :         Rmat[1][1] = L_sub( L_add( L_sub( ww, xx ), yy ), zz );
     240      921170 :         move32();
     241      921170 :         Rmat[1][2] = L_sub( yz, wx );
     242      921170 :         move32();
     243             : 
     244      921170 :         Rmat[2][0] = L_sub( xz, wy ); // 2 * Qx - 32
     245      921170 :         move32();
     246      921170 :         Rmat[2][1] = L_add( yz, wx );
     247      921170 :         move32();
     248      921170 :         Rmat[2][2] = L_add( L_sub( L_sub( ww, xx ), yy ), zz );
     249      921170 :         move32();
     250             :     }
     251      921170 :     return;
     252             : }
     253             : 
     254             : 
     255             : /*-------------------------------------------------------------------------
     256             :  * rad2deg()
     257             :  *
     258             :  * Converts normalized radians to degrees
     259             :  *------------------------------------------------------------------------*/
     260             : 
     261         456 : Word32 rad2deg_fx(
     262             :     Word32 radians // Q13
     263             : )
     264             : {
     265             : 
     266         460 :     WHILE( GE_32( radians, EVS_PI_FX ) )
     267             :     {
     268           4 :         radians = L_sub( radians, EVS_PI_FX );
     269             :     }
     270         456 :     WHILE( LE_32( radians, -EVS_PI_FX ) )
     271             :     {
     272           0 :         radians = L_add( radians, EVS_PI_FX );
     273             :     }
     274             : 
     275         456 :     return W_extract_l( W_mult0_32_32( radians, _180_OVER_PI_FX ) ); // Q23
     276             : }
     277             : 
     278             : 
     279             : /*-------------------------------------------------------------------------
     280             :  * rotateAziEle()
     281             :  *
     282             :  * Apply rotation to direction parameters azimuth and elevation
     283             :  *------------------------------------------------------------------------*/
     284             : 
     285     3521804 : void rotateAziEle_fx(
     286             :     Word16 azi_in,        /* i  : output elevation                           Q0 */
     287             :     Word16 ele_in,        /* i  : input elevation                            Q0 */
     288             :     Word16 *azi,          /* o  : rotated azimuth                            Q0 */
     289             :     Word16 *ele,          /* o  : rotated elevation                          Q0 */
     290             :     Word32 Rmat_fx[3][3], /* i  : real-space rotation matrix                 Q30*/
     291             :     const Word16 isPlanar /* i  : is rotation planar and elevation meaningless? Q0*/
     292             : )
     293             : {
     294             :     Word16 n;
     295             :     Word32 dv_fx[3], dv_r_fx[3];
     296             :     Word32 w_fx;
     297             :     Word32 temp;
     298             :     Word16 temp_16;
     299             :     Word32 y, x, sqrt_fx;
     300             :     Word16 radian, angle;
     301             :     /*Conversion spherical to cartesian coordinates*/
     302     3521804 :     IF( GT_16( abs_s( azi_in ), 180 ) )
     303             :     {
     304     1075881 :         IF( azi_in > 0 )
     305             :         {
     306     1075881 :             azi_in = sub( azi_in, 360 );
     307             :         }
     308             :         ELSE
     309             :         {
     310           0 :             azi_in = add( azi_in, 360 );
     311             :         }
     312             :     }
     313     3521804 :     temp_16 = ele_in;
     314     3521804 :     move16();
     315     3521804 :     w_fx = cosine_table_Q31[abs_s( temp_16 )]; // Q31
     316     3521804 :     move32();
     317     3521804 :     temp_16 = azi_in;
     318     3521804 :     move16();
     319     3521804 :     dv_fx[0] = Mpy_32_32( w_fx, cosine_table_Q31[abs_s( temp_16 )] ); // Q31
     320     3521804 :     move32();
     321     3521804 :     temp_16 = azi_in;
     322     3521804 :     move16();
     323     3521804 :     dv_fx[1] = Mpy_32_32( w_fx, sine_table_Q31[add( temp_16, 180 )] ); // Q31
     324     3521804 :     move32();
     325     3521804 :     temp_16 = ele_in;
     326     3521804 :     move16();
     327     3521804 :     dv_fx[2] = sine_table_Q31[add( temp_16, 180 )]; // Q31
     328     3521804 :     move32();
     329             :     /*Rotation mtx multiplication*/
     330    14087216 :     FOR( n = 0; n < 3; n++ )
     331             :     {
     332    10565412 :         temp = L_add( Mpy_32_32( dv_fx[0], Rmat_fx[n][0] ), Mpy_32_32( dv_fx[1], Rmat_fx[n][1] ) ); // Q30
     333    10565412 :         dv_r_fx[n] = L_add( Mpy_32_32( dv_fx[2], Rmat_fx[n][2] ), temp );                           // Q30
     334    10565412 :         move32();
     335             :     }
     336             : 
     337             :     /*Conversion cartesian to spherical coordinates*/
     338     3521804 :     y = dv_r_fx[1];
     339     3521804 :     move32();
     340     3521804 :     x = dv_r_fx[0];
     341     3521804 :     move32();
     342     3521804 :     radian = atan2_fx( L_abs( L_shr( y, 15 ) ), L_abs( L_shr( x, 15 ) ) ); // Q14
     343             : 
     344     3521804 :     if ( y <= 0 )
     345             :     {
     346     1768861 :         radian = negate( radian );
     347             :     }
     348             : 
     349     3521804 :     IF( x < 0 )
     350             :     {
     351     1269895 :         IF( radian < 0 )
     352             :         {
     353      601098 :             angle = negate( add( 180, extract_l( L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), ( 24 ) ) ) ) ); // Q0
     354             :         }
     355             :         ELSE
     356             :         {
     357      668797 :             angle = sub( 180, extract_l( L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), ( 24 ) ) ) ); // Q0
     358             :         }
     359     1269895 :         IF( radian == 0 )
     360             :         {
     361         997 :             if ( y < 0 )
     362             :             {
     363           3 :                 angle = negate( angle );
     364             :             }
     365             :         }
     366             :     }
     367             :     ELSE
     368             :     {
     369     2251909 :         angle = extract_l( L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), 24 ) ); // Q0
     370             :     }
     371             : 
     372     3521804 :     *azi = s_max( -180, s_min( 180, angle ) );
     373     3521804 :     move16();
     374             : 
     375     3521804 :     IF( isPlanar == 0 )
     376             :     {
     377     3321804 :         sqrt_fx = L_Frac_sqrtQ31( L_add( Mpy_32_32( dv_r_fx[0], dv_r_fx[0] ), Mpy_32_32( dv_r_fx[1], dv_r_fx[1] ) ) );
     378     3321804 :         y = dv_r_fx[2];
     379     3321804 :         move32();
     380     3321804 :         x = sqrt_fx;
     381     3321804 :         move32();
     382     3321804 :         radian = atan2_fx( L_abs( L_shr( y, 15 ) ), L_abs( L_shr( x, 15 ) ) ); // Q14
     383     3321804 :         if ( y <= 0 )
     384             :         {
     385     1946623 :             radian = negate( radian );
     386             :         }
     387             : 
     388     3321804 :         IF( x < 0 )
     389             :         {
     390           0 :             IF( radian < 0 )
     391             :             {
     392           0 :                 angle = negate( add( 180, extract_l( L_shr( Mpy_32_16_r( _180_OVER_PI_Q25, radian ), ( 24 ) ) ) ) ); // Q0
     393             :             }
     394             :             ELSE
     395             :             {
     396           0 :                 angle = sub( 180, extract_l( L_shr( Mpy_32_16_r( _180_OVER_PI_Q25, radian ), ( 24 ) ) ) ); // Q0
     397             :             }
     398           0 :             IF( radian == 0 )
     399             :             {
     400           0 :                 if ( y < 0 )
     401             :                 {
     402           0 :                     angle = negate( angle );
     403             :                 }
     404             :             }
     405             :         }
     406             :         ELSE
     407             :         {
     408     3321804 :             angle = extract_l( L_shr( Mpy_32_16_r( _180_OVER_PI_Q25, radian ), ( 24 ) ) ); // Q0
     409             :         }
     410             : 
     411     3321804 :         *ele = s_max( -90, s_min( 90, angle ) ); // Q0
     412     3321804 :         move16();
     413             :     }
     414             :     ELSE
     415             :     {
     416      200000 :         *ele = 0;
     417      200000 :         move16();
     418             :     }
     419             : 
     420     3521804 :     return;
     421             : }
     422             : 
     423             : /*-------------------------------------------------------------------------
     424             :  * rotateAziEle_fx_frac_az_el()
     425             :  *
     426             :  * Apply rotation to direction parameters azimuth and elevation
     427             :  *------------------------------------------------------------------------*/
     428      150000 : void rotateAziEle_fx_frac_az_el(
     429             :     Word32 azi_in,        /* i  : output elevation                          Q22 */
     430             :     Word32 ele_in,        /* i  : input elevation                           Q22 */
     431             :     Word32 *azi,          /* o  : rotated azimuth                           Q22 */
     432             :     Word32 *ele,          /* o  : rotated elevation                         Q22 */
     433             :     Word32 Rmat_fx[3][3], /* i  : real-space rotation matrix                Q30 */
     434             :     const Word16 isPlanar /* i  : is rotation planar and elevation meaningless? Q0*/
     435             : )
     436             : {
     437             :     Word16 n, radian; // temp_16;
     438             :     Word32 dv_fx[3], dv_r_fx[3];
     439             :     Word16 w_fx;
     440             :     Word32 temp;
     441             :     Word32 y, x, sqrt_fx;
     442             :     Word32 angle;
     443             :     Word16 azi_in_q13, ele_in_q13;
     444             :     /*Conversion spherical to cartesian coordinates*/
     445      150000 :     IF( GT_32( L_abs( azi_in ), _180_IN_Q22 ) )
     446             :     {
     447       71744 :         IF( azi_in > 0 )
     448             :         {
     449       71744 :             azi_in = L_sub( azi_in, _360_IN_Q22 );
     450             :         }
     451             :         ELSE
     452             :         {
     453           0 :             azi_in = L_add( azi_in, _360_IN_Q22 );
     454             :         }
     455             :     }
     456      150000 :     azi_in_q13 = extract_l( L_shr( Mpy_32_32( azi_in, PI_OVER_180_FX ), Q9 ) );
     457      150000 :     ele_in_q13 = extract_l( L_shr( Mpy_32_32( ele_in, PI_OVER_180_FX ), Q9 ) );
     458      150000 :     w_fx = getCosWord16( ele_in_q13 );                     // Q14
     459      150000 :     dv_fx[0] = L_mult( w_fx, getCosWord16( azi_in_q13 ) ); // Q28
     460      150000 :     move32();
     461      150000 :     IF( EQ_32( dv_fx[0], ONE_IN_Q29 ) )
     462             :     {
     463        2414 :         move32();
     464        2414 :         dv_fx[0] = ONE_IN_Q31;
     465             :     }
     466             :     ELSE
     467             :     {
     468      147586 :         dv_fx[0] = L_shl( dv_fx[0], 2 );
     469      147586 :         move32();
     470             :     }
     471      150000 :     dv_fx[1] = L_mult( w_fx, getSinWord16( azi_in_q13 ) ); // Q28
     472      150000 :     move32();
     473      150000 :     IF( EQ_32( dv_fx[1], ONE_IN_Q30 ) )
     474             :     {
     475           0 :         move32();
     476           0 :         dv_fx[1] = ONE_IN_Q31;
     477             :     }
     478             :     ELSE
     479             :     {
     480      150000 :         dv_fx[1] = L_shl( dv_fx[1], 1 );
     481      150000 :         move32();
     482             :     }
     483      150000 :     dv_fx[2] = L_deposit_l( getSinWord16( ele_in_q13 ) ); // Q14
     484      150000 :     move32();
     485      150000 :     IF( EQ_32( dv_fx[2], ONE_IN_Q15 ) )
     486             :     {
     487           0 :         move32();
     488           0 :         dv_fx[2] = ONE_IN_Q31;
     489             :     }
     490             :     ELSE
     491             :     {
     492      150000 :         dv_fx[2] = L_shl( dv_fx[2], 16 );
     493      150000 :         move32();
     494             :     }
     495             : 
     496             :     /*Rotation mtx multiplication*/
     497      600000 :     FOR( n = 0; n < 3; n++ )
     498             :     {
     499      450000 :         temp = L_add( Mpy_32_32( dv_fx[0], Rmat_fx[n][0] ), Mpy_32_32( dv_fx[1], Rmat_fx[n][1] ) );
     500      450000 :         dv_r_fx[n] = L_add( Mpy_32_32( dv_fx[2], Rmat_fx[n][2] ), temp ); // Q30
     501      450000 :         move32();
     502             :     }
     503             : 
     504             :     /*Conversion cartesian to spherical coordinates*/
     505      150000 :     move32();
     506      150000 :     y = dv_r_fx[1];
     507      150000 :     move32();
     508      150000 :     x = dv_r_fx[0];
     509      150000 :     radian = BASOP_util_atan2( y, x, 0 ); // Q13
     510             : 
     511      150000 :     angle = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), 1 ); // Q22
     512             : 
     513             : 
     514      150000 :     *azi = L_max( L_shl( -180, 22 ), L_min( L_shl( 180, 22 ), angle ) ); // Q22
     515      150000 :     move32();
     516      150000 :     *azi = L_shl( L_shr( L_add( *azi, ONE_IN_Q21 ), Q22 ), Q22 );
     517      150000 :     move32();
     518      150000 :     if ( LT_32( L_abs( *azi ), ONE_IN_Q22 ) )
     519             :     {
     520         532 :         move32();
     521         532 :         *azi = 0;
     522             :     }
     523      150000 :     IF( isPlanar == 0 )
     524             :     {
     525      150000 :         sqrt_fx = L_Frac_sqrtQ31( L_add( Mpy_32_32( dv_r_fx[0], dv_r_fx[0] ), Mpy_32_32( dv_r_fx[1], dv_r_fx[1] ) ) );
     526      150000 :         y = dv_r_fx[2];
     527      150000 :         move32();
     528      150000 :         x = sqrt_fx;
     529      150000 :         move32();
     530      150000 :         radian = BASOP_util_atan2( y, x, 0 ); // Q13
     531             : 
     532      150000 :         angle = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), 1 ); // Q22
     533             : 
     534             : 
     535      150000 :         *ele = L_max( L_shl( -90, 22 ), L_min( L_shl( 90, 22 ), angle ) ); // Q22
     536      150000 :         move32();
     537      150000 :         *ele = L_shl( L_shr( L_add( *ele, ONE_IN_Q21 ), Q22 ), Q22 );
     538      150000 :         move32();
     539      150000 :         if ( LT_32( L_abs( *ele ), ONE_IN_Q22 ) )
     540             :         {
     541       18942 :             *ele = 0;
     542       18942 :             move32();
     543             :         }
     544             :     }
     545             :     ELSE
     546             :     {
     547           0 :         *ele = 0;
     548           0 :         move32();
     549             :     }
     550             : 
     551      150000 :     return;
     552             : }
     553             : 
     554             : /*-------------------------------------------------------------------------
     555             :  * rotateAziEle()
     556             :  *
     557             :  * Apply rotation to direction parameters azimuth and elevation
     558             :  *------------------------------------------------------------------------*/
     559             : 
     560      449760 : void rotateAziEle_fixed(
     561             :     Word16 azi_in,        /* i  : output elevation                         Q0   */
     562             :     Word16 ele_in,        /* i  : input elevation                          Q0   */
     563             :     Word32 *azi,          /* o  : rotated azimuth                          Q22  */
     564             :     Word32 *ele,          /* o  : rotated elevation                        Q22  */
     565             :     Word32 Rmat_fx[3][3], /* i  : real-space rotation matrix               Q30  */
     566             :     const Word16 isPlanar /* i  : is rotation planar and elevation meaningless? Q0*/
     567             : )
     568             : {
     569             :     Word16 n, radian, temp_16;
     570             :     Word32 dv_fx[3], dv_r_fx[3];
     571             :     Word32 w_fx;
     572             :     Word32 temp;
     573             :     Word32 y, x, sqrt_fx;
     574             :     Word32 angle;
     575             :     /*Conversion spherical to cartesian coordinates*/
     576      449760 :     IF( GT_16( abs_s( azi_in ), 180 ) )
     577             :     {
     578           0 :         IF( azi_in > 0 )
     579             :         {
     580           0 :             azi_in = sub( azi_in, 360 );
     581             :         }
     582             :         ELSE
     583             :         {
     584           0 :             azi_in = add( azi_in, 360 );
     585             :         }
     586             :     }
     587      449760 :     temp_16 = ele_in;
     588      449760 :     move16();
     589      449760 :     w_fx = cosine_table_Q31[abs( temp_16 )];
     590      449760 :     move32();
     591      449760 :     temp_16 = azi_in;
     592      449760 :     move16();
     593      449760 :     dv_fx[0] = Mpy_32_32( w_fx, cosine_table_Q31[abs( temp_16 )] );
     594      449760 :     move32();
     595      449760 :     temp_16 = azi_in;
     596      449760 :     move16();
     597      449760 :     dv_fx[1] = Mpy_32_32( w_fx, sine_table_Q31[temp_16 + 180] );
     598      449760 :     move32();
     599      449760 :     temp_16 = ele_in;
     600      449760 :     move16();
     601      449760 :     dv_fx[2] = sine_table_Q31[temp_16 + 180];
     602      449760 :     move32();
     603             :     /*Rotation mtx multiplication*/
     604     1799040 :     FOR( n = 0; n < 3; n++ )
     605             :     {
     606     1349280 :         temp = L_add( Mpy_32_32( dv_fx[0], Rmat_fx[n][0] ), Mpy_32_32( dv_fx[1], Rmat_fx[n][1] ) );
     607     1349280 :         dv_r_fx[n] = L_add( Mpy_32_32( dv_fx[2], Rmat_fx[n][2] ), temp ); // Q30
     608     1349280 :         move32();
     609             :     }
     610             : 
     611             :     /*Conversion cartesian to spherical coordinates*/
     612      449760 :     y = dv_r_fx[1];
     613      449760 :     move32();
     614      449760 :     x = dv_r_fx[0];
     615      449760 :     move32();
     616      449760 :     radian = BASOP_util_atan2( y, x, 0 ); // Q13
     617             : 
     618      449760 :     angle = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), 1 ); // Q22
     619             :     /* Handeled roudning off operation*/
     620      449760 :     IF( angle > 0 )
     621             :     {
     622      242804 :         temp = L_add( angle, ONE_IN_Q21 /* 0.5 in Q22*/ );
     623      242804 :         temp_16 = extract_l( L_shr( temp, Q22 ) );
     624      242804 :         angle = L_shl( temp_16, Q22 ); // Q22
     625             :     }
     626             :     ELSE
     627             :     {
     628      206956 :         temp = L_sub( angle, ONE_IN_Q21 /* 0.5 in Q22*/ );
     629      206956 :         temp_16 = add( extract_l( L_shr( temp, Q22 ) ), 1 );
     630      206956 :         angle = L_shl( temp_16, Q22 ); // Q22
     631             :     }
     632      449760 :     *azi = L_max( L_shl( -180, 22 ), L_min( L_shl( 180, 22 ), angle ) ); // Q22
     633      449760 :     move32();
     634      449760 :     if ( LE_32( L_abs( *azi ), ONE_IN_Q22 ) )
     635             :     {
     636        4142 :         *azi = 0;
     637        4142 :         move32();
     638             :     }
     639      449760 :     IF( isPlanar == 0 )
     640             :     {
     641      401360 :         sqrt_fx = L_Frac_sqrtQ31( L_add( Mpy_32_32( dv_r_fx[0], dv_r_fx[0] ), Mpy_32_32( dv_r_fx[1], dv_r_fx[1] ) ) );
     642      401360 :         y = dv_r_fx[2];
     643      401360 :         move32();
     644      401360 :         x = sqrt_fx;
     645      401360 :         move32();
     646      401360 :         radian = BASOP_util_atan2( y, x, 0 ); // Q13
     647             : 
     648      401360 :         angle = L_shr( Mpy_32_16_1( _180_OVER_PI_Q25, radian ), 1 ); // Q22
     649             : 
     650      401360 :         *ele = L_max( L_shl( -90, 22 ), L_min( L_shl( 90, 22 ), angle ) ); // Q22
     651      401360 :         move32();
     652      401360 :         if ( LT_32( L_abs( *ele ), ONE_IN_Q22 ) )
     653             :         {
     654      208480 :             *ele = 0;
     655      208480 :             move32();
     656             :         }
     657             :     }
     658             :     ELSE
     659             :     {
     660       48400 :         *ele = 0;
     661       48400 :         move32();
     662             :     }
     663             : 
     664      449760 :     return;
     665             : }
     666             : 
     667             : /*-------------------------------------------------------------------------
     668             :  * rotateFrame_shd()
     669             :  *
     670             :  * Apply rotation to signals in Spherical Harmonic Domain
     671             :  *------------------------------------------------------------------------*/
     672             : 
     673         600 : void rotateFrame_shd(
     674             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i  : head and external orientation combined handle */
     675             :     Word32 *output[],                                     /* i/o: unrotated HOA3 signal buffer in TD        Q11 */
     676             :     const Word16 subframe_len,                            /* i  : subframe length per channel               Q0   */
     677             :     const IVAS_OUTPUT_SETUP hTransSetup,                  /* i  : format for rotation                           */
     678             :     const Word16 subframe_idx                             /* i  : subframe index                            Q0    */
     679             : )
     680             : {
     681             :     Word16 i, l, n, m, offset;
     682             :     Word16 m1, m2;
     683             :     Word16 shd_rot_max_order;
     684             : 
     685         600 :     Word32 tmp = Q31_BY_SUB_FRAME_240;
     686         600 :     move32();
     687             :     Word32 tmpRot[2 * HEADROT_ORDER + 1];
     688             :     Word16 SHrotmat_prev[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
     689             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
     690             :     Word32 cross_fade[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
     691         600 :     shd_rot_max_order = hTransSetup.ambisonics_order;
     692         600 :     move16();
     693         600 :     offset = imult1616( subframe_idx, subframe_len );
     694             : 
     695         600 :     SWITCH( subframe_len )
     696             :     {
     697         600 :         case L_SUBFRAME_48k:
     698         600 :             tmp = Q31_BY_SUB_FRAME_240; // Q31
     699         600 :             move32();
     700         600 :             BREAK;
     701           0 :         case L_SUBFRAME_32k:
     702           0 :             tmp = Q31_BY_NUM_SAMPLES_160;
     703           0 :             move32();
     704           0 :             BREAK;
     705           0 :         case L_SUBFRAME_16k:
     706           0 :             tmp = Q31_BY_SUB_FRAME_80;
     707           0 :             move32();
     708           0 :             BREAK;
     709           0 :         case L_SUBFRAME_8k:
     710           0 :             tmp = Q31_BY_SUB_FRAME_40;
     711           0 :             move32();
     712           0 :             BREAK;
     713           0 :         default:
     714           0 :             BREAK;
     715             :     }
     716      144600 :     FOR( i = 0; i < subframe_len; i++ )
     717             :     {
     718      144000 :         cross_fade[i] = UL_Mpy_32_32( i, tmp ); // Q31
     719      144000 :         move32();
     720             :     }
     721             :     /* initialize rotation matrices with zeros */
     722       10200 :     FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
     723             :     {
     724        9600 :         set16_fx( SHrotmat_prev[i], 0, HEADROT_SHMAT_DIM );
     725        9600 :         set16_fx( SHrotmat[i], 0, HEADROT_SHMAT_DIM );
     726             :     }
     727             : 
     728             :     /* calculate ambisonics rotation matrices for the previous and current frames */
     729         600 :     SHrotmatgen_fx( SHrotmat_prev, hCombinedOrientationData->Rmat_prev_fx[0], shd_rot_max_order );
     730         600 :     SHrotmatgen_fx( SHrotmat /*Q14*/, hCombinedOrientationData->Rmat_fx[hCombinedOrientationData->subframe_idx], shd_rot_max_order );
     731             : 
     732      144600 :     FOR( i = 0; i < subframe_len; i++ )
     733             :     {
     734             :         /*As the rotation matrix becomes block diagonal in a SH basis, we can
     735             :           apply each angular-momentum block individually to save complexity. */
     736             : 
     737             :         /* loop over l blocks */
     738      144000 :         m1 = 1;
     739      144000 :         move16();
     740      144000 :         m2 = 4;
     741      144000 :         move16();
     742      576000 :         FOR( l = 1; l <= shd_rot_max_order; l++ )
     743             :         {
     744             :             /* compute mtx-vector product for this l */
     745     2592000 :             FOR( n = m1; n < m2; n++ )
     746             :             {
     747     2160000 :                 tmpRot[n - m1] = 0;
     748     2160000 :                 move32();
     749    14112000 :                 FOR( m = m1; m < m2; m++ )
     750             :                 {
     751             :                     /* crossfade with previous rotation gains */
     752    11952000 :                     tmp = L_add( Mpy_32_32( Mpy_32_16_r( cross_fade[i], SHrotmat[n][m] ) /*Q30*/, output[m][offset + i] /*Q11*/ ), Mpy_32_32( Mpy_32_16_r( L_sub( ONE_IN_Q31, cross_fade[i] ), SHrotmat_prev[n][m] ) /*Q30*/, output[m][offset + i] /*Q11*/ ) );
     753    11952000 :                     tmpRot[n - m1] = L_add( L_shl( tmp, 1 ), tmpRot[n - m1] ); // Q11
     754             :                 }
     755             :             }
     756             : 
     757             :             /* write back the result */
     758     2592000 :             FOR( n = m1; n < m2; n++ )
     759             :             {
     760     2160000 :                 output[n][offset + i] = tmpRot[n - m1]; // Q11
     761     2160000 :                 move32();
     762             :             }
     763      432000 :             m1 = m2;
     764      432000 :             move16();
     765      432000 :             m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
     766             :         }
     767             : 
     768             :         /* unoptimized code for reference (full matrix multiplication)
     769             :         for ( n = 0; n < nchan; n++ )
     770             :         {
     771             :             tmpRot[n] = 0.f;
     772             : 
     773             :             for ( m = 0; m < nchan; m++ )
     774             :             {
     775             :                 tmpRot[n] += SHrotmat[n][m] * output[m][i];
     776             :             }
     777             :         }
     778             :         for ( n = 0; n < nchan; n++ )
     779             :         {
     780             :             output[n][i] = tmpRot[n];
     781             :         }
     782             :         */
     783             :     }
     784             : 
     785             :     /* move Rmat to Rmat_prev */
     786        2400 :     FOR( i = 0; i < 3; i++ )
     787             :     {
     788        1800 :         Copy32(
     789        1800 :             hCombinedOrientationData->Rmat_fx[subframe_idx][i],
     790        1800 :             hCombinedOrientationData->Rmat_prev_fx[0][i],
     791             :             3 ); // Q14
     792             :     }
     793             : 
     794         600 :     return;
     795             : }
     796             : 
     797             : /*-------------------------------------------------------------------------
     798             :  * rotateFrame_sd()
     799             :  *
     800             :  * Apply rotation to signals in Spatial Domain
     801             :  *------------------------------------------------------------------------*/
     802       16000 : void rotateFrame_sd(
     803             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i  : head and external orientation combined handle */
     804             :     Word32 *output[],                                     /* i/o: unrotated SD signal buffer in TD          Q11 */
     805             :     const Word16 subframe_len,                            /* i  : subframe length per channel                   */
     806             :     const IVAS_OUTPUT_SETUP hTransSetup,                  /* i  : format for rotation                           */
     807             :     const EFAP_HANDLE hEFAPdata,                          /* i  : EFAP structure                                */
     808             :     const Word16 subframe_idx                             /* i  : subframe index                                */
     809             : )
     810             : {
     811             :     Word16 i, j, offset;
     812             :     Word16 nchan, index_lfe;
     813             :     Word16 ch_in, ch_in_woLFE, ch_out, ch_out_woLFE;
     814             :     Word16 azimuth, elevation;
     815             :     Word32 azimuth_fx, elevation_fx;
     816       16000 :     Word32 tmp = Q31_BY_SUB_FRAME_240; // Q31
     817             :     Word32 out_temp;
     818             :     Word32 tmp_gains_fx[MAX_CICP_CHANNELS - 1];
     819             :     Word32 gains_fx[MAX_CICP_CHANNELS][MAX_CICP_CHANNELS];
     820             :     Word32 gains_prev_fx[MAX_CICP_CHANNELS][MAX_CICP_CHANNELS];
     821             :     Word32 output_tmp_fx[MAX_CICP_CHANNELS][L_FRAME48k];
     822             :     Word32 cross_fade_fx[L_FRAME48k / MAX_PARAM_SPATIAL_SUBFRAMES];
     823             : 
     824       16000 :     push_wmops( "rotateFrame_sd" );
     825             : 
     826       16000 :     move32();
     827             : 
     828       16000 :     nchan = add( hTransSetup.nchan_out_woLFE, hTransSetup.num_lfe );
     829       16000 :     index_lfe = hTransSetup.index_lfe[0];
     830       16000 :     move16();
     831       16000 :     offset = imult1616( subframe_idx, subframe_len );
     832       16000 :     SWITCH( subframe_len )
     833             :     {
     834       16000 :         case L_SUBFRAME_48k:
     835       16000 :             tmp = Q31_BY_SUB_FRAME_240;
     836       16000 :             move32();
     837       16000 :             BREAK;
     838           0 :         case L_SUBFRAME_32k:
     839           0 :             tmp = Q31_BY_NUM_SAMPLES_160;
     840           0 :             move32();
     841           0 :             BREAK;
     842           0 :         case L_SUBFRAME_16k:
     843           0 :             tmp = Q31_BY_SUB_FRAME_80;
     844           0 :             move32();
     845           0 :             BREAK;
     846           0 :         case L_SUBFRAME_8k:
     847           0 :             tmp = Q31_BY_SUB_FRAME_40;
     848           0 :             move32();
     849           0 :             BREAK;
     850           0 :         default:
     851           0 :             BREAK;
     852             :     }
     853             : 
     854     3856000 :     FOR( i = 0; i < subframe_len; i++ )
     855             :     {
     856     3840000 :         cross_fade_fx[i] = UL_Mpy_32_32( i, tmp ); // Q31
     857     3840000 :         move32();
     858             :     }
     859             : 
     860      112000 :     FOR( ch_in = 0; ch_in < nchan; ch_in++ )
     861             :     {
     862             :         /* zero output and gain buffers */
     863       96000 :         set32_fx( &output_tmp_fx[ch_in][offset], 0, subframe_len );
     864       96000 :         set32_fx( gains_prev_fx[ch_in], 0, nchan );
     865       96000 :         set32_fx( gains_fx[ch_in], 0, nchan );
     866             :         /* set gains to passthrough by default */
     867       96000 :         gains_prev_fx[ch_in][ch_in] = ONE_IN_Q30;
     868       96000 :         move32();
     869       96000 :         gains_fx[ch_in][ch_in] = ONE_IN_Q30;
     870       96000 :         move32();
     871             :         /* skip LFE */
     872       96000 :         IF( EQ_16( ch_in, index_lfe ) )
     873             :         {
     874       16000 :             CONTINUE;
     875             :         }
     876             : 
     877             :         /* input channel index without LFE */
     878       80000 :         IF( GE_16( ch_in, index_lfe ) )
     879             :         {
     880       32000 :             ch_in_woLFE = sub( ch_in, 1 );
     881             :         }
     882             :         ELSE
     883             :         {
     884       48000 :             ch_in_woLFE = ch_in;
     885       48000 :             move16();
     886             :         }
     887             : 
     888             :         /* gains for previous subframe rotation */
     889       80000 :         rotateAziEle_fx( extract_l( L_shr( hTransSetup.ls_azimuth_fx[ch_in_woLFE], Q22 ) ), extract_l( L_shr( hTransSetup.ls_elevation_fx[ch_in_woLFE], Q22 ) ), &azimuth, &elevation, hCombinedOrientationData->Rmat_prev_fx[0], hTransSetup.is_planar_setup );
     890       80000 :         test();
     891       80000 :         test();
     892       80000 :         IF( hEFAPdata != NULL && ( NE_16( extract_l( L_shr( hTransSetup.ls_azimuth_fx[ch_in_woLFE], Q22 ) ), azimuth ) || NE_16( extract_l( L_shr( hTransSetup.ls_elevation_fx[ch_in_woLFE], Q22 ) ), elevation ) ) )
     893             :         {
     894       76747 :             azimuth_fx = L_shl( L_deposit_l( azimuth ), Q22 );     // Q0->Q22
     895       76747 :             elevation_fx = L_shl( L_deposit_l( elevation ), Q22 ); // Q0->Q22
     896       76747 :             efap_determine_gains_fx( hEFAPdata, tmp_gains_fx, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
     897             : 
     898             : 
     899      537229 :             FOR( ch_out = 0; ch_out < nchan; ch_out++ )
     900             :             {
     901             :                 /* skip LFE */
     902      460482 :                 IF( EQ_16( ch_out, index_lfe ) )
     903             :                 {
     904       76747 :                     CONTINUE;
     905             :                 }
     906             : 
     907             :                 /* output channel index without LFE */
     908      383735 :                 IF( GE_16( ch_out, index_lfe ) )
     909             :                 {
     910      153494 :                     ch_out_woLFE = sub( ch_out, 1 );
     911             :                 }
     912             :                 ELSE
     913             :                 {
     914      230241 :                     ch_out_woLFE = ch_out;
     915      230241 :                     move16();
     916             :                 }
     917      383735 :                 gains_prev_fx[ch_in][ch_out] = tmp_gains_fx[ch_out_woLFE]; // Q30
     918      383735 :                 move32();
     919             :             }
     920             :         }
     921             : 
     922             :         /* gains for current subframe rotation */
     923       80000 :         rotateAziEle_fx( extract_l( L_shr( hTransSetup.ls_azimuth_fx[ch_in_woLFE], Q22 ) ), extract_l( L_shr( hTransSetup.ls_elevation_fx[ch_in_woLFE], Q22 ) ), &azimuth, &elevation, hCombinedOrientationData->Rmat_fx[hCombinedOrientationData->subframe_idx], hTransSetup.is_planar_setup );
     924       80000 :         test();
     925       80000 :         test();
     926       80000 :         IF( hEFAPdata != NULL && ( NE_16( extract_l( L_shr( hTransSetup.ls_azimuth_fx[ch_in_woLFE], Q22 ) ), azimuth ) || NE_16( extract_l( L_shr( hTransSetup.ls_elevation_fx[ch_in_woLFE], Q22 ) ), elevation ) ) )
     927             :         {
     928             : 
     929       76763 :             azimuth_fx = L_shl( L_deposit_l( azimuth ), Q22 );     // Q0->Q22
     930       76763 :             elevation_fx = L_shl( L_deposit_l( elevation ), Q22 ); // Q0->Q22
     931       76763 :             efap_determine_gains_fx( hEFAPdata, tmp_gains_fx, azimuth_fx, elevation_fx, EFAP_MODE_EFAP );
     932             : 
     933      537341 :             FOR( ch_out = 0; ch_out < nchan; ch_out++ )
     934             :             {
     935             :                 /* skip LFE */
     936      460578 :                 IF( EQ_16( ch_out, index_lfe ) )
     937             :                 {
     938       76763 :                     CONTINUE;
     939             :                 }
     940             : 
     941             :                 /* output channel index without LFE */
     942      383815 :                 IF( GE_16( ch_out, index_lfe ) )
     943             :                 {
     944      153526 :                     ch_out_woLFE = sub( ch_out, 1 );
     945             :                 }
     946             :                 ELSE
     947             :                 {
     948      230289 :                     ch_out_woLFE = ch_out;
     949      230289 :                     move16();
     950             :                 }
     951             : 
     952      383815 :                 gains_fx[ch_in][ch_out] = tmp_gains_fx[ch_out_woLFE]; // Q30
     953      383815 :                 move32();
     954             :             }
     955             :         }
     956             :     }
     957             : 
     958             :     /* apply panning gains by mtx multiplication */
     959      112000 :     FOR( ch_out = 0; ch_out < nchan; ch_out++ )
     960             :     {
     961      672000 :         FOR( ch_in = 0; ch_in < nchan; ch_in++ )
     962             :         {
     963      576000 :             j = 0;
     964             :             /* crossfade with previous rotation gains */
     965   138816000 :             FOR( i = subframe_idx * subframe_len; j < subframe_len; i++ )
     966             :             {
     967   138240000 :                 out_temp = output[ch_in][i];
     968   138240000 :                 move32();
     969   138240000 :                 Word32 temp = Mpy_32_32( Mpy_32_32( ( cross_fade_fx[j] ), gains_fx[ch_in][ch_out] ), out_temp );                        // Q10
     970   138240000 :                 Word32 temp1 = Mpy_32_32( Mpy_32_32( L_sub( ONE_IN_Q31, cross_fade_fx[j] ), gains_prev_fx[ch_in][ch_out] ), out_temp ); // Q10
     971   138240000 :                 output_tmp_fx[ch_out][i] = L_add( L_shl( L_add( temp, temp1 ), 1 ), output_tmp_fx[ch_out][i] );                         // Q11
     972   138240000 :                 move32();
     973   138240000 :                 j = add( j, 1 );
     974             :             }
     975             :         }
     976             :     }
     977             : 
     978             :     /* move Rmat to Rmat_prev */
     979       64000 :     FOR( i = 0; i < 3; i++ )
     980             :     {
     981       48000 :         Copy32(
     982       48000 :             hCombinedOrientationData->Rmat_fx[hCombinedOrientationData->subframe_idx][i], // Q30
     983       48000 :             hCombinedOrientationData->Rmat_prev_fx[0][i],
     984             :             3 );
     985             :     }
     986             :     /* copy to output */
     987      112000 :     FOR( ch_out = 0; ch_out < nchan; ch_out++ )
     988             :     {
     989       96000 :         Copy32( &output_tmp_fx[ch_out][offset], &output[ch_out][offset], subframe_len ); // Q11
     990             :     }
     991             : 
     992       16000 :     pop_wmops();
     993       16000 :     return;
     994             : }
     995             : /*-------------------------------------------------------------------------
     996             :  * rotateFrame_shd_cldfb()
     997             :  *
     998             :  * Apply rotation to signals in Spherical Harmonic Domain and in CLDFB
     999             :  *------------------------------------------------------------------------*/
    1000       19311 : void rotateFrame_shd_cldfb(
    1001             :     Word32 Cldfb_RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain real part Qx -> Qx-1  */
    1002             :     Word32 Cldfb_ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain imag part Qx -> Qx-1  */
    1003             :     Word32 Rmat[3][3],                                                             /* i  : real-space rotation matrix                             Q30         */
    1004             :     const Word16 nInChannels,                                                      /* i  : number of channels                                                 */
    1005             :     const Word16 numTimeSlots,                                                     /* i  : number of time slots to process                                    */
    1006             :     const Word16 shd_rot_max_order                                                 /* i  : split-order rotation method                                        */
    1007             : )
    1008             : {
    1009       19311 :     Word16 n = 0;
    1010       19311 :     Word16 m = 0;
    1011       19311 :     Word16 i = 0, j = 0, k = 0;
    1012       19311 :     Word16 iBand = 0;
    1013       19311 :     Word16 l = 0, m1 = 0, m2 = 0;
    1014             :     Word32 realRot[2 * HEADROT_ORDER + 1], imagRot[2 * HEADROT_ORDER + 1];
    1015             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
    1016       19311 :     move16();
    1017       19311 :     move16();
    1018       19311 :     move16();
    1019       19311 :     move16();
    1020       19311 :     move16();
    1021       19311 :     move16();
    1022       19311 :     move16();
    1023       19311 :     move16();
    1024       19311 :     move16();
    1025       19311 :     assert( nInChannels == HEADROT_SHMAT_DIM && "Number of channels must be 16!" );
    1026             : 
    1027             :     /* initialize rotation matrices with zeros */
    1028      328287 :     FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
    1029             :     {
    1030      308976 :         set16_fx( SHrotmat[i], 0, HEADROT_SHMAT_DIM );
    1031             :     }
    1032             : 
    1033             :     /* calculate Ambisonics rotation matrix from the quaternion */
    1034       19311 :     SHrotmatgen_fx( SHrotmat, Rmat, shd_rot_max_order );
    1035             : 
    1036             : #ifdef DEBUGGING
    1037             :     dbgwrite_txt( (const float *) SHrotmat[0], HEADROT_SHMAT_DIM * HEADROT_SHMAT_DIM, "Fixed_SHrotmat.txt", NULL );
    1038             : #endif
    1039             : 
    1040             :     /* rotation by mtx multiplication */
    1041       96434 :     FOR( i = 0; i < numTimeSlots; i++ )
    1042             :     {
    1043     4704503 :         FOR( iBand = 0; iBand < CLDFB_NO_CHANNELS_MAX; iBand++ )
    1044             :         {
    1045             :             /*As the rotation matrix becomes block diagonal in a SH basis, we can
    1046             :             apply each angular-momentum block individually to save complexity. */
    1047             : 
    1048             :             /* loop over l blocks */
    1049     4627380 :             m1 = 1;
    1050     4627380 :             move16();
    1051     4627380 :             m2 = 4;
    1052     4627380 :             move16();
    1053    18509520 :             FOR( l = 1; l <= shd_rot_max_order; l++ )
    1054             :             {
    1055             :                 /* compute mtx-vector product for this l */
    1056    83292840 :                 FOR( n = m1; n < m2; n++ )
    1057             :                 {
    1058    69410700 :                     realRot[n - m1] = 0;
    1059    69410700 :                     move32();
    1060    69410700 :                     imagRot[n - m1] = 0;
    1061    69410700 :                     move32();
    1062   453483240 :                     FOR( m = m1; m < m2; m++ )
    1063             :                     {
    1064   384072540 :                         realRot[n - m1] = Madd_32_16_r( realRot[n - m1], Cldfb_RealBuffer[m][i][iBand], SHrotmat[n][m] ); // Q(x + 14 - 15)
    1065   384072540 :                         move32();
    1066   384072540 :                         imagRot[n - m1] = Madd_32_16_r( imagRot[n - m1], Cldfb_ImagBuffer[m][i][iBand], SHrotmat[n][m] ); // Q(x + 14 - 15)
    1067   384072540 :                         move32();
    1068             :                     }
    1069             :                 }
    1070             :                 /* write back the result */
    1071    83292840 :                 FOR( n = m1; n < m2; n++ )
    1072             :                 {
    1073    69410700 :                     Cldfb_RealBuffer[n][i][iBand] = realRot[n - m1]; // Qx - 1
    1074    69410700 :                     move32();
    1075    69410700 :                     Cldfb_ImagBuffer[n][i][iBand] = imagRot[n - m1]; // Qx - 1
    1076    69410700 :                     move32();
    1077             :                 }
    1078    13882140 :                 m1 = m2;
    1079    13882140 :                 move16();
    1080    13882140 :                 m2 = add( m2, add( shl( add( l, 1 ), 1 ), 1 ) );
    1081             :             }
    1082             : 
    1083             :             /* unoptimized code for reference (full matrix multiplication)
    1084             :             for (n = 0; n < nInChannels; n++)
    1085             :             {
    1086             :                 realRot[n] = 0.f;
    1087             :                 imagRot[n] = 0.f;
    1088             : 
    1089             :                 for (m = 0; m < nInChannels; m++)
    1090             :                 {
    1091             :                     realRot[n] += SHrotmat[n][m] * Cldfb_RealBuffer[m][i][iBand];
    1092             :                     imagRot[n] += SHrotmat[n][m] * Cldfb_ImagBuffer[m][i][iBand];
    1093             :                 }
    1094             :             }
    1095             :             for (n = 0; n < nInChannels; n++)
    1096             :             {
    1097             :                 Cldfb_RealBuffer[n][i][iBand] = realRot[n];
    1098             :                 Cldfb_ImagBuffer[n][i][iBand] = imagRot[n];
    1099             :             }
    1100             :             */
    1101             :         }
    1102             :     }
    1103             :     // To make the Q factor same as tha of the remaining vector values
    1104       96555 :     FOR( j = 0; j < MAX_PARAM_SPATIAL_SUBFRAMES; j++ )
    1105             :     {
    1106     4711884 :         FOR( k = 0; k < CLDFB_NO_CHANNELS_MAX; k++ )
    1107             :         {
    1108     4634640 :             Cldfb_RealBuffer[0][j][k] = L_shr( Cldfb_RealBuffer[0][j][k], 1 ); // Qx - 1
    1109     4634640 :             move32();
    1110     4634640 :             Cldfb_ImagBuffer[0][j][k] = L_shr( Cldfb_ImagBuffer[0][j][k], 1 ); // Qx - 1
    1111     4634640 :             move32();
    1112             :         }
    1113             :     }
    1114       19311 :     return;
    1115             : }
    1116             : /*-------------------------------------------------------------------------
    1117             :  * rotateFrame_sd_cldfb()
    1118             :  *
    1119             :  * Apply rotation to signals in Spatial Domain and in CLDFB
    1120             :  *------------------------------------------------------------------------*/
    1121             : 
    1122        8000 : void rotateFrame_sd_cldfb_fixed(
    1123             :     Word32 Rmat_fx[3][3],                                                          /* i  : real-space rotation matrix (Q30)                          */
    1124             :     Word32 Cldfb_RealBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain real part Qx */
    1125             :     Word32 Cldfb_ImagBuffer[][MAX_PARAM_SPATIAL_SUBFRAMES][CLDFB_NO_CHANNELS_MAX], /* i/o: unrotated HOA3 signal buffer in cldfb domain imag part Qx */
    1126             :     const IVAS_OUTPUT_SETUP_HANDLE hOutputSetup,                                   /* i  : output format setup number of channels                    */
    1127             :     const EFAP_HANDLE hEFAPdata,                                                   /* i  : EFAP structure                                            */
    1128             :     const Word16 numTimeSlots,                                                     /* i  : number of time slots to process                           */
    1129             :     const Word16 nb_band                                                           /* i  : number of CLDFB bands to process                          */
    1130             : )
    1131             : {
    1132             :     Word16 iBlock, iBand, m, n;
    1133             :     Word32 gains_fx[MAX_CICP_CHANNELS - 1][MAX_CICP_CHANNELS - 1];
    1134             :     Word16 azimuth, elevation;
    1135             :     Word32 g1_fx;
    1136             :     Word32 realRot_fx[MAX_CICP_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
    1137             :     Word32 imagRot_fx[MAX_CICP_CHANNELS - 1][MAX_PARAM_SPATIAL_SUBFRAMES * CLDFB_NO_CHANNELS_MAX];
    1138             :     Word32 *p_realRot_fx, *p_imagRot_fx;
    1139             :     Word32 *p_real_fx, *p_imag_fx;
    1140             :     Word16 nInChannels;
    1141             :     Word16 isPlanar;
    1142        8000 :     push_wmops( "rotateFrame_sd_cldfb" );
    1143             : 
    1144        8000 :     nInChannels = hOutputSetup->nchan_out_woLFE;
    1145        8000 :     move16();
    1146        8000 :     isPlanar = 1;
    1147        8000 :     move16();
    1148       48000 :     FOR( n = 0; n < nInChannels; n++ )
    1149             :     {
    1150       40000 :         IF( hOutputSetup->ls_elevation_fx[n] != 0 )
    1151             :         {
    1152           0 :             isPlanar = 0;
    1153           0 :             move16();
    1154           0 :             BREAK;
    1155             :         }
    1156             :     }
    1157             : 
    1158             :     /* rotation of Euler angles */
    1159       48000 :     FOR( n = 0; n < nInChannels; n++ )
    1160             :     {
    1161       40000 :         rotateAziEle_fx( extract_l( L_shr( hOutputSetup->ls_azimuth_fx[n], Q22 ) ), extract_l( L_shr( hOutputSetup->ls_elevation_fx[n], Q22 ) ), &azimuth, &elevation, Rmat_fx, isPlanar );
    1162       40000 :         test();
    1163       40000 :         test();
    1164       40000 :         IF( hEFAPdata != NULL && ( NE_16( extract_l( L_shr( hOutputSetup->ls_azimuth_fx[n], Q22 ) ), azimuth ) || NE_16( extract_l( L_shr( hOutputSetup->ls_elevation_fx[n], Q22 ) ), elevation ) ) )
    1165             :         {
    1166       36781 :             efap_determine_gains_fx( hEFAPdata, gains_fx[n], L_shl( azimuth, Q22 ), L_shl( elevation, Q22 ), EFAP_MODE_EFAP );
    1167       36781 :             scale_sig32( gains_fx[n], hEFAPdata->numSpk, Q1 ); // gains_fx: Q31
    1168             :         }
    1169             :         ELSE
    1170             :         {
    1171        3219 :             set32_fx( gains_fx[n], 0, nInChannels );
    1172        3219 :             gains_fx[n][n] = 0x7fffffff; // 1 in Q31
    1173        3219 :             move32();
    1174             :         }
    1175             :     }
    1176             : 
    1177             :     /* Apply panning gains by mtx multiplication*/
    1178       48000 :     FOR( n = 0; n < nInChannels; n++ )
    1179             :     {
    1180       40000 :         set32_fx( realRot_fx[n], 0, shl( nb_band, 2 ) );
    1181       40000 :         set32_fx( imagRot_fx[n], 0, shl( nb_band, 2 ) );
    1182      240000 :         FOR( m = 0; m < nInChannels; m++ )
    1183             :         {
    1184      200000 :             g1_fx = gains_fx[m][n]; // Q31
    1185      200000 :             move32();
    1186      200000 :             p_realRot_fx = realRot_fx[n];
    1187      200000 :             p_imagRot_fx = imagRot_fx[n];
    1188             : 
    1189      200000 :             IF( g1_fx > 0 )
    1190             :             {
    1191      382375 :                 FOR( iBlock = 0; iBlock < numTimeSlots; iBlock++ )
    1192             :                 {
    1193      305900 :                     p_real_fx = Cldfb_RealBuffer[m][iBlock];
    1194      305900 :                     p_imag_fx = Cldfb_ImagBuffer[m][iBlock];
    1195             : 
    1196    15600900 :                     FOR( iBand = 0; iBand < nb_band; iBand++ )
    1197             :                     {
    1198    15295000 :                         *( p_realRot_fx ) = L_add( *p_realRot_fx, Mpy_32_32( g1_fx, *( p_real_fx++ ) ) ); // Qx
    1199    15295000 :                         move32();
    1200    15295000 :                         *( p_imagRot_fx ) = L_add( *p_imagRot_fx, Mpy_32_32( g1_fx, *( p_imag_fx++ ) ) ); // Qx
    1201    15295000 :                         move32();
    1202    15295000 :                         p_realRot_fx++;
    1203    15295000 :                         p_imagRot_fx++;
    1204             :                     }
    1205             :                 }
    1206             :             }
    1207             :         }
    1208             :     }
    1209             : 
    1210       48000 :     FOR( n = 0; n < nInChannels; n++ )
    1211             :     {
    1212       40000 :         p_realRot_fx = realRot_fx[n];
    1213       40000 :         p_imagRot_fx = imagRot_fx[n];
    1214             : 
    1215      200000 :         FOR( iBlock = 0; iBlock < numTimeSlots; iBlock++ )
    1216             :         {
    1217      160000 :             p_real_fx = Cldfb_RealBuffer[n][iBlock];
    1218      160000 :             p_imag_fx = Cldfb_ImagBuffer[n][iBlock];
    1219             : 
    1220     8160000 :             FOR( iBand = 0; iBand < nb_band; iBand++ )
    1221             :             {
    1222     8000000 :                 *( p_real_fx++ ) = *( p_realRot_fx++ );
    1223     8000000 :                 move32();
    1224     8000000 :                 *( p_imag_fx++ ) = *( p_imagRot_fx++ );
    1225     8000000 :                 move32();
    1226             :             }
    1227     1760000 :             FOR( ; iBand < CLDFB_NO_CHANNELS_MAX; iBand++ )
    1228             :             {
    1229     1600000 :                 *( p_real_fx++ ) = 0;
    1230     1600000 :                 move32();
    1231     1600000 :                 *( p_imag_fx++ ) = 0;
    1232     1600000 :                 move32();
    1233             :             }
    1234             :         }
    1235             :     }
    1236        8000 :     pop_wmops();
    1237             : 
    1238        8000 :     return;
    1239             : }
    1240             : 
    1241             : /*-----------------------------------------------------------------------*
    1242             :  * ivas_external_orientation_open()
    1243             :  *
    1244             :  * Allocate and initialize external orientation handle
    1245             :  *-----------------------------------------------------------------------*/
    1246          31 : ivas_error ivas_external_orientation_open(
    1247             :     EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData, /* o  : external orientation handle    */
    1248             :     const Word16 num_subframes                        /* i  : number of subframes            */
    1249             : )
    1250             : {
    1251             : 
    1252             :     Word16 i;
    1253             :     IVAS_QUATERNION identity;
    1254          31 :     identity.w_fx = ONE_IN_Q31;
    1255          31 :     move32();
    1256          31 :     identity.x_fx = 0;
    1257          31 :     move32();
    1258          31 :     identity.y_fx = 0;
    1259          31 :     move32();
    1260          31 :     identity.z_fx = 0;
    1261          31 :     move32();
    1262          31 :     identity.q_fact = 31;
    1263          31 :     move16();
    1264             :     /* Allocate handle */
    1265          31 :     IF( ( *hExtOrientationData = (EXTERNAL_ORIENTATION_HANDLE) malloc( sizeof( EXTERNAL_ORIENTATION_DATA ) ) ) == NULL )
    1266             :     {
    1267           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for external orientation memory\n" ) );
    1268             :     }
    1269          31 :     ( *hExtOrientationData )->num_subframes = num_subframes;
    1270          31 :     move16();
    1271             :     /* Enable head rotation and disable external orientation as default */
    1272         155 :     FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1273             :     {
    1274         124 :         ( *hExtOrientationData )->enableHeadRotation[i] = 1;
    1275         124 :         move16();
    1276         124 :         ( *hExtOrientationData )->enableExternalOrientation[i] = 0;
    1277         124 :         move16();
    1278         124 :         ( *hExtOrientationData )->enableRotationInterpolation[i] = 0;
    1279         124 :         move16();
    1280         124 :         ( *hExtOrientationData )->numFramesToTargetOrientation[i] = 0;
    1281         124 :         move16();
    1282             : 
    1283         124 :         ( *hExtOrientationData )->Quaternions[i] = identity;
    1284             :     }
    1285          31 :     return IVAS_ERR_OK;
    1286             : }
    1287             : 
    1288             : /*-----------------------------------------------------------------------*
    1289             :  * ivas_external_orientation_close()
    1290             :  *
    1291             :  * Deallocate external orientation handle
    1292             :  *-----------------------------------------------------------------------*/
    1293        1279 : void ivas_external_orientation_close_fx(
    1294             :     EXTERNAL_ORIENTATION_HANDLE *hExtOrientationData /* i/o: external orientation handle    */
    1295             : )
    1296             : {
    1297        1279 :     test();
    1298        1279 :     IF( hExtOrientationData == NULL || *hExtOrientationData == NULL )
    1299             :     {
    1300        1248 :         return;
    1301             :     }
    1302             : 
    1303          31 :     free( ( *hExtOrientationData ) );
    1304          31 :     *hExtOrientationData = NULL;
    1305             : 
    1306          31 :     return;
    1307             : }
    1308             : 
    1309             : 
    1310             : /*-----------------------------------------------------------------------*
    1311             :  * ivas_combined_orientation_open()
    1312             :  *
    1313             :  * Allocate and initialize combined orientation handle
    1314             :  *-----------------------------------------------------------------------*/
    1315         176 : ivas_error ivas_combined_orientation_open(
    1316             :     COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData, /* o  : combined orientation handle   */
    1317             :     const Word32 fs,                                       /* i  : sampling rate                 */
    1318             :     const Word16 num_subframes                             /* i  : number of subframes           */
    1319             : )
    1320             : {
    1321             :     Word16 i;
    1322             :     Word16 j;
    1323             :     IVAS_QUATERNION identity;
    1324             :     IVAS_VECTOR3 origo;
    1325             :     Word16 pos_idx;
    1326         176 :     identity.w_fx = ONE_IN_Q31;
    1327         176 :     move32();
    1328         176 :     identity.x_fx = 0;
    1329         176 :     move32();
    1330         176 :     identity.y_fx = 0;
    1331         176 :     move32();
    1332         176 :     identity.z_fx = 0;
    1333         176 :     move32();
    1334         176 :     identity.q_fact = 31;
    1335         176 :     move16();
    1336         176 :     origo.x_fx = 0;
    1337         176 :     move32();
    1338         176 :     origo.y_fx = 0;
    1339         176 :     move32();
    1340         176 :     origo.z_fx = 0;
    1341         176 :     move32();
    1342         176 :     origo.q_fact = 31;
    1343         176 :     move16();
    1344             :     /* Allocate handle */
    1345         176 :     IF( ( *hCombinedOrientationData = (COMBINED_ORIENTATION_HANDLE) malloc( sizeof( COMBINED_ORIENTATION_DATA ) ) ) == NULL )
    1346             :     {
    1347           0 :         return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for combined orientation memory\n" ) );
    1348             :     }
    1349             : 
    1350             :     /* Initialization */
    1351         176 :     ( *hCombinedOrientationData )->num_subframes = num_subframes;
    1352         176 :     move16();
    1353         176 :     ( *hCombinedOrientationData )->interpolationCoefficient_fx = ONE_IN_Q30; // Q30
    1354         176 :     move32();
    1355         176 :     ( *hCombinedOrientationData )->interpolationIncrement_fx = ONE_IN_Q30; // Q30
    1356         176 :     move32();
    1357         176 :     ( *hCombinedOrientationData )->maximumFramesToTargetOrientation = 500;
    1358         176 :     move16();
    1359         176 :     ( *hCombinedOrientationData )->lrSwitchedNext = 0;
    1360         176 :     move16();
    1361         176 :     ( *hCombinedOrientationData )->lrSwitchedCurrent = 0;
    1362         176 :     move16();
    1363             : 
    1364         176 :     ( *hCombinedOrientationData )->lrSwitchInterpVal_fx = 0;
    1365         176 :     move32();
    1366         176 :     ( *hCombinedOrientationData )->isInterpolationOngoing = FALSE;
    1367         176 :     move16();
    1368         176 :     ( *hCombinedOrientationData )->Quaternions_ext_interpolation_start = identity;
    1369         176 :     ( *hCombinedOrientationData )->Quaternions_ext_interpolation_target = identity;
    1370             : 
    1371             :     /* Initialise orientations to identity */
    1372         880 :     FOR( i = 0; i < MAX_PARAM_SPATIAL_SUBFRAMES; i++ )
    1373             :     {
    1374         704 :         ( *hCombinedOrientationData )->enableCombinedOrientation[i] = 0;
    1375         704 :         move16();
    1376         704 :         ( *hCombinedOrientationData )->Quaternions[i] = identity;
    1377         704 :         ( *hCombinedOrientationData )->listenerPos[i] = origo;
    1378             : 
    1379        2816 :         FOR( j = 0; j < 3; j++ )
    1380             :         {
    1381        2112 :             set32_fx( ( *hCombinedOrientationData )->Rmat_fx[i][j], 0, 3 );
    1382        2112 :             ( *hCombinedOrientationData )->Rmat_fx[i][j][j] = ONE_IN_Q30; // Q30
    1383        2112 :             move32();
    1384             :         }
    1385             :     }
    1386             : 
    1387        1584 :     FOR( pos_idx = 0; pos_idx < MAX_HEAD_ROT_POSES; pos_idx++ )
    1388             :     {
    1389        5632 :         FOR( j = 0; j < 3; j++ )
    1390             :         {
    1391        4224 :             set32_fx( ( *hCombinedOrientationData )->Rmat_prev_fx[pos_idx][j], 0, 3 );
    1392        4224 :             ( *hCombinedOrientationData )->Rmat_prev_fx[pos_idx][j][j] = ONE_IN_Q30;
    1393        4224 :             move32();
    1394             :         }
    1395             :     }
    1396         176 :     ( *hCombinedOrientationData )->sr_pose_pred_axis = DEFAULT_AXIS;
    1397         176 :     ( *hCombinedOrientationData )->sr_low_res_flag = 0;
    1398         176 :     move32();
    1399         176 :     move16();
    1400             : 
    1401         176 :     ( *hCombinedOrientationData )
    1402         176 :         ->Quaternion_prev_extOrientation = identity;
    1403         176 :     ( *hCombinedOrientationData )->Quaternion_frozen_ext = identity;
    1404         176 :     ( *hCombinedOrientationData )->Quaternion_frozen_head = identity;
    1405         176 :     set_zero_fx( ( *hCombinedOrientationData )->chEneIIR_fx[0], MASA_FREQUENCY_BANDS );
    1406         176 :     set_zero_fx( ( *hCombinedOrientationData )->chEneIIR_fx[1], MASA_FREQUENCY_BANDS );
    1407         176 :     set_zero_fx( ( *hCombinedOrientationData )->procChEneIIR_fx[0], MASA_FREQUENCY_BANDS );
    1408         176 :     set_zero_fx( ( *hCombinedOrientationData )->procChEneIIR_fx[1], MASA_FREQUENCY_BANDS );
    1409         176 :     set16_fx( ( *hCombinedOrientationData )->q_chEneIIR[0], Q31, MASA_FREQUENCY_BANDS );
    1410         176 :     set16_fx( ( *hCombinedOrientationData )->q_chEneIIR[1], Q31, MASA_FREQUENCY_BANDS );
    1411         176 :     set16_fx( ( *hCombinedOrientationData )->q_procChEneIIR[0], Q31, MASA_FREQUENCY_BANDS );
    1412         176 :     set16_fx( ( *hCombinedOrientationData )->q_procChEneIIR[1], Q31, MASA_FREQUENCY_BANDS );
    1413             : 
    1414         176 :     ( *hCombinedOrientationData )->isExtOrientationFrozen = 0;
    1415         176 :     move16();
    1416         176 :     ( *hCombinedOrientationData )->isHeadRotationFrozen = 0;
    1417         176 :     move16();
    1418             : 
    1419         176 :     ( *hCombinedOrientationData )->subframe_idx = 0;
    1420         176 :     move16();
    1421             :     /* ( *hCombinedOrientationData )->subframe_size = (int16_t) ( fs / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) ); */
    1422         176 :     ( *hCombinedOrientationData )->subframe_size = extract_l( Mpy_32_32_r( fs, 10737418 /* 1 / ( FRAMES_PER_SEC * MAX_PARAM_SPATIAL_SUBFRAMES ) in Q31 */ ) );
    1423         176 :     move16();
    1424         176 :     ( *hCombinedOrientationData )->cur_subframe_samples_rendered = 0;
    1425         176 :     move16();
    1426             : 
    1427         176 :     return IVAS_ERR_OK;
    1428             : }
    1429             : /*-----------------------------------------------------------------------*
    1430             :  * ivas_combined_orientation_close()
    1431             :  *
    1432             :  * Deallocate combined orientation handle
    1433             :  *-----------------------------------------------------------------------*/
    1434             : 
    1435        1279 : void ivas_combined_orientation_close_fx(
    1436             :     COMBINED_ORIENTATION_HANDLE *hCombinedOrientationData /* i/o: combined orientation handle   */
    1437             : )
    1438             : {
    1439        1279 :     test();
    1440        1279 :     IF( hCombinedOrientationData == NULL || *hCombinedOrientationData == NULL )
    1441             :     {
    1442        1103 :         return;
    1443             :     }
    1444             : 
    1445         176 :     free( ( *hCombinedOrientationData ) );
    1446         176 :     *hCombinedOrientationData = NULL;
    1447             : 
    1448         176 :     return;
    1449             : }
    1450             : 
    1451             : 
    1452             : /*-------------------------------------------------------------------------
    1453             :  * combine_external_and_head_orientations_dec()
    1454             :  *
    1455             :  *
    1456             :  *------------------------------------------------------------------------*/
    1457             : 
    1458       69653 : ivas_error combine_external_and_head_orientations_dec(
    1459             :     HEAD_TRACK_DATA_HANDLE hHeadTrackData,               /* i  : head track handle              */
    1460             :     EXTERNAL_ORIENTATION_HANDLE hExtOrientationData,     /* i  : external orientation handle    */
    1461             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle    */
    1462             : )
    1463             : {
    1464             :     ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis;
    1465       69653 :     IVAS_QUATERNION *pHeadRotQuaternion = NULL;
    1466       69653 :     IVAS_VECTOR3 *listenerPos = NULL;
    1467             : 
    1468       69653 :     IF( hHeadTrackData != NULL )
    1469             :     {
    1470       69653 :         pHeadRotQuaternion = hHeadTrackData->Quaternions;
    1471       69653 :         listenerPos = hHeadTrackData->Pos;
    1472       69653 :         sr_pose_pred_axis = hHeadTrackData->sr_pose_pred_axis;
    1473             :     }
    1474             :     ELSE
    1475             :     {
    1476           0 :         sr_pose_pred_axis = DEFAULT_AXIS;
    1477             :     }
    1478             : 
    1479       69653 :     return combine_external_and_head_orientations( pHeadRotQuaternion, listenerPos, sr_pose_pred_axis, hExtOrientationData, hCombinedOrientationData );
    1480             : }
    1481             : 
    1482             : 
    1483             : /*-------------------------------------------------------------------------
    1484             :  * combine_external_and_head_orientations_rend()
    1485             :  *
    1486             :  *
    1487             :  *------------------------------------------------------------------------*/
    1488             : 
    1489     1126140 : ivas_error combine_external_and_head_orientations_rend(
    1490             :     IVAS_REND_HeadRotData *hHeadTrackData,               /* i  : head track handle              */
    1491             :     EXTERNAL_ORIENTATION_HANDLE hExtOrientationData,     /* i  : external orientation handle    */
    1492             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle    */
    1493             : )
    1494             : {
    1495             :     ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis;
    1496     1126140 :     IVAS_QUATERNION *headRotQuaternions = NULL;
    1497     1126140 :     IVAS_VECTOR3 *listenerPos = NULL;
    1498             :     Word16 i;
    1499             : 
    1500     1126140 :     sr_pose_pred_axis = DEFAULT_AXIS;
    1501             : 
    1502     1126140 :     IF( hHeadTrackData != NULL )
    1503             :     {
    1504     1126140 :         IF( hHeadTrackData->headRotEnabled )
    1505             :         {
    1506      180024 :             headRotQuaternions = hHeadTrackData->headPositions;
    1507      180024 :             listenerPos = hHeadTrackData->Pos;
    1508             :         }
    1509     1126140 :         sr_pose_pred_axis = hHeadTrackData->sr_pose_pred_axis;
    1510             :     }
    1511           0 :     ELSE IF( hExtOrientationData != NULL )
    1512             :     {
    1513             :         /* Head rotation data not available, use the freezed value or disable */
    1514           0 :         FOR( i = 0; i < hExtOrientationData->num_subframes; i++ )
    1515             :         {
    1516           0 :             IF( NE_16( hExtOrientationData->enableHeadRotation[i], 2 ) )
    1517             :             {
    1518           0 :                 hExtOrientationData->enableHeadRotation[i] = 0;
    1519           0 :                 move16();
    1520             :             }
    1521             :         }
    1522             :     }
    1523             : 
    1524     1126140 :     return combine_external_and_head_orientations( headRotQuaternions, listenerPos, sr_pose_pred_axis, hExtOrientationData, hCombinedOrientationData );
    1525             : }
    1526             : 
    1527             : 
    1528             : /*-------------------------------------------------------------------------
    1529             :  * combine_external_and_head_orientations()
    1530             :  *
    1531             :  * Combine the external orientations and the head orientation.
    1532             :  * NOTE that the external orientations are inversed.
    1533             :  *------------------------------------------------------------------------*/
    1534             : 
    1535     1195793 : ivas_error combine_external_and_head_orientations(
    1536             :     IVAS_QUATERNION *headRotQuaternions,                 /* i  : quaternions for head rotation                            */
    1537             :     IVAS_VECTOR3 *listenerPos,                           /* i  : listener position                                        */
    1538             :     ISAR_SPLIT_REND_ROT_AXIS sr_pose_pred_axis,          /* i  : split rend pose prediction axis                          */
    1539             :     EXTERNAL_ORIENTATION_HANDLE hExtOrientationData,     /* i  : external orientation handle                              */
    1540             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle                              */
    1541             : )
    1542             : {
    1543             :     Word16 i;
    1544             :     Word16 j;
    1545             :     IVAS_QUATERNION identity;
    1546             :     IVAS_VECTOR3 origo;
    1547     1195793 :     identity.w_fx = ONE_IN_Q31;
    1548     1195793 :     move32();
    1549     1195793 :     identity.x_fx = 0;
    1550     1195793 :     move32();
    1551     1195793 :     identity.y_fx = 0;
    1552     1195793 :     move32();
    1553     1195793 :     identity.z_fx = 0;
    1554     1195793 :     move32();
    1555     1195793 :     identity.q_fact = 31;
    1556     1195793 :     move16();
    1557     1195793 :     origo.x_fx = 0;
    1558     1195793 :     move32();
    1559     1195793 :     origo.y_fx = 0;
    1560     1195793 :     move32();
    1561     1195793 :     origo.z_fx = 0;
    1562     1195793 :     move32();
    1563     1195793 :     origo.q_fact = 31;
    1564     1195793 :     move16();
    1565             : 
    1566             :     /* Form combined orientations or return if no data available */
    1567     1195793 :     test();
    1568     1195793 :     test();
    1569     1195793 :     IF( hCombinedOrientationData == NULL )
    1570             :     {
    1571      946116 :         test();
    1572      946116 :         IF( headRotQuaternions != NULL || hExtOrientationData != NULL )
    1573             :         {
    1574           0 :             return IVAS_ERR_UNEXPECTED_NULL_POINTER;
    1575             :         }
    1576             :         ELSE
    1577             :         {
    1578      946116 :             return IVAS_ERR_OK;
    1579             :         }
    1580             :     }
    1581      249677 :     ELSE IF( headRotQuaternions == NULL && hExtOrientationData == NULL )
    1582             :     {
    1583             :         /* Reset the combined orientations and rotations */
    1584           0 :         hCombinedOrientationData->isInterpolationOngoing = FALSE;
    1585           0 :         move16();
    1586           0 :         hCombinedOrientationData->interpolationCoefficient_fx = ONE_IN_Q30;
    1587           0 :         move32();
    1588           0 :         hCombinedOrientationData->interpolationIncrement_fx = ONE_IN_Q30;
    1589           0 :         move32();
    1590           0 :         hCombinedOrientationData->Quaternions_ext_interpolation_start = identity;
    1591           0 :         hCombinedOrientationData->Quaternions_ext_interpolation_target = identity;
    1592           0 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1593             :         {
    1594           0 :             hCombinedOrientationData->enableCombinedOrientation[i] = 0;
    1595           0 :             move16();
    1596           0 :             hCombinedOrientationData->Quaternions[i] = identity;
    1597           0 :             hCombinedOrientationData->listenerPos[i] = origo;
    1598             : 
    1599           0 :             FOR( j = 0; j < 3; j++ )
    1600             :             {
    1601           0 :                 set_zero_fx( hCombinedOrientationData->Rmat_fx[i][j], 3 );
    1602           0 :                 hCombinedOrientationData->Rmat_fx[i][j][j] = ONE_IN_Q30;
    1603           0 :                 move32();
    1604             :             }
    1605             :         }
    1606             :     }
    1607      249677 :     ELSE IF( hExtOrientationData == NULL && headRotQuaternions != NULL )
    1608             :     {
    1609             :         /* Head rotation only */
    1610      670349 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1611             :         {
    1612      449872 :             hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i];
    1613             :         }
    1614             :     }
    1615             : 
    1616      249677 :     IF( hExtOrientationData != NULL )
    1617             :     {
    1618             :         /* External orientations */
    1619      146000 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1620             :         {
    1621             :             /* Check for frozen external orientation */
    1622      116800 :             IF( EQ_16( hExtOrientationData->enableExternalOrientation[i], 2 ) )
    1623             :             {
    1624       17391 :                 IF( NE_16( hCombinedOrientationData->isExtOrientationFrozen, 1 ) )
    1625             :                 {
    1626          31 :                     hCombinedOrientationData->Quaternion_frozen_ext = hExtOrientationData->Quaternions[i];
    1627          31 :                     hCombinedOrientationData->isExtOrientationFrozen = 1;
    1628          31 :                     move16();
    1629             :                 }
    1630             :             }
    1631             :             ELSE
    1632             :             {
    1633       99409 :                 hCombinedOrientationData->Quaternion_frozen_ext = identity;
    1634       99409 :                 hCombinedOrientationData->isExtOrientationFrozen = 0;
    1635       99409 :                 move16();
    1636             :             }
    1637      116800 :             test();
    1638      116800 :             IF( EQ_16( hExtOrientationData->enableRotationInterpolation[i], 1 ) && hExtOrientationData->enableExternalOrientation[i] > 0 )
    1639             :             {
    1640       60970 :                 test();
    1641       60970 :                 test();
    1642       60970 :                 IF( EQ_16( hCombinedOrientationData->isInterpolationOngoing, true ) && LE_32( hCombinedOrientationData->interpolationCoefficient_fx, ONE_IN_Q30 ) && EQ_16( are_orientations_same_fx( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ), true ) )
    1643             :                 {
    1644             :                     /* Continue interpolation */
    1645       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_start.w_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.w_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1646       50636 :                     move32();
    1647       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_start.x_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.x_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1648       50636 :                     move32();
    1649       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_start.y_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.y_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1650       50636 :                     move32();
    1651       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_start.z_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.z_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1652       50636 :                     move32();
    1653             : 
    1654       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_target.w_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.w_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1655       50636 :                     move32();
    1656       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_target.x_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.x_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1657       50636 :                     move32();
    1658       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_target.y_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.y_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1659       50636 :                     move32();
    1660       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_target.z_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.z_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1661       50636 :                     move32();
    1662             : 
    1663       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact = Q29;
    1664       50636 :                     move16();
    1665       50636 :                     hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact = Q29;
    1666       50636 :                     move16();
    1667       50636 :                     QuaternionSlerp_fx( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient_fx, &hCombinedOrientationData->Quaternions[i] );
    1668       50636 :                     hCombinedOrientationData->interpolationCoefficient_fx = L_add( hCombinedOrientationData->interpolationIncrement_fx, hCombinedOrientationData->interpolationCoefficient_fx );
    1669       50636 :                     move32();
    1670             :                 }
    1671             :                 ELSE
    1672             :                 {
    1673             :                     /* Stop interpolation or check for new interpolation */
    1674       10334 :                     hCombinedOrientationData->isInterpolationOngoing = FALSE;
    1675       10334 :                     move16();
    1676       10334 :                     hCombinedOrientationData->interpolationCoefficient_fx = ONE_IN_Q30;
    1677       10334 :                     move32();
    1678       10334 :                     hCombinedOrientationData->interpolationIncrement_fx = ONE_IN_Q30;
    1679       10334 :                     move32();
    1680       10334 :                     external_target_interpolation_fx( hExtOrientationData, hCombinedOrientationData, i );
    1681       10334 :                     Word16 l_shift = 0;
    1682       10334 :                     move16();
    1683       10334 :                     l_shift = s_min( s_min( Q_factor_L_32( hCombinedOrientationData->Quaternions[i].w_fx ), Q_factor_L_32( hCombinedOrientationData->Quaternions[i].x_fx ) ), s_min( Q_factor_L_32( hCombinedOrientationData->Quaternions[i].y_fx ), Q_factor_L_32( hCombinedOrientationData->Quaternions[i].z_fx ) ) );
    1684       10334 :                     hCombinedOrientationData->Quaternions[i].w_fx = L_shl( hCombinedOrientationData->Quaternions[i].w_fx, l_shift ); // q_fact+l_shift
    1685       10334 :                     move32();
    1686       10334 :                     hCombinedOrientationData->Quaternions[i].x_fx = L_shl( hCombinedOrientationData->Quaternions[i].x_fx, l_shift ); // q_fact+l_shift
    1687       10334 :                     move32();
    1688       10334 :                     hCombinedOrientationData->Quaternions[i].y_fx = L_shl( hCombinedOrientationData->Quaternions[i].y_fx, l_shift ); // q_fact+l_shift
    1689       10334 :                     move32();
    1690       10334 :                     hCombinedOrientationData->Quaternions[i].z_fx = L_shl( hCombinedOrientationData->Quaternions[i].z_fx, l_shift ); // q_fact+l_shift
    1691       10334 :                     move32();
    1692       10334 :                     hCombinedOrientationData->Quaternions[i].q_fact = add( hCombinedOrientationData->Quaternions[i].q_fact, l_shift );
    1693       10334 :                     move16();
    1694             :                 }
    1695             :             }
    1696             :             ELSE
    1697             :             {
    1698             :                 /* Interpolation disabled, use the current orientation values */
    1699             : 
    1700             :                 /* Use the most recent external orientation */
    1701       55830 :                 IF( EQ_16( hExtOrientationData->enableExternalOrientation[i], 1 ) )
    1702             :                 {
    1703       36393 :                     hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i];
    1704             :                 }
    1705             :                 /* Use the freezed external orientation */
    1706       19437 :                 ELSE IF( EQ_16( hExtOrientationData->enableExternalOrientation[i], 2 ) )
    1707             :                 {
    1708       12803 :                     hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_ext;
    1709             :                 }
    1710             :             }
    1711             :         }
    1712             :     }
    1713      249677 :     test();
    1714      249677 :     IF( hExtOrientationData != NULL && headRotQuaternions != NULL )
    1715             :     {
    1716             :         /* Combine head and external orientations */
    1717      146000 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1718             :         {
    1719             :             /* Check for frozen head rotation */
    1720      116800 :             IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 2 ) )
    1721             :             {
    1722       12400 :                 IF( NE_16( hCombinedOrientationData->isHeadRotationFrozen, 1 ) )
    1723             :                 {
    1724          62 :                     hCombinedOrientationData->Quaternion_frozen_head = headRotQuaternions[i];
    1725          62 :                     hCombinedOrientationData->isHeadRotationFrozen = 1;
    1726          62 :                     move16();
    1727             :                 }
    1728             :             }
    1729             :             ELSE
    1730             :             {
    1731      104400 :                 hCombinedOrientationData->Quaternion_frozen_head = identity;
    1732      104400 :                 hCombinedOrientationData->isHeadRotationFrozen = 0;
    1733      104400 :                 move16();
    1734             :             }
    1735             :             /* Use the most recent head rotation */
    1736      116800 :             IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 1 ) )
    1737             :             {
    1738       83595 :                 IF( hExtOrientationData->enableExternalOrientation[i] > 0 )
    1739             :                 {
    1740       76961 :                     QuaternionProduct_fx( hCombinedOrientationData->Quaternions[i], headRotQuaternions[i], &hCombinedOrientationData->Quaternions[i] );
    1741             :                 }
    1742             :                 ELSE
    1743             :                 {
    1744        6634 :                     hCombinedOrientationData->Quaternions[i] = headRotQuaternions[i];
    1745             :                 }
    1746             :             }
    1747             :             /* Use the freezed head rotation */
    1748       33205 :             ELSE IF( EQ_16( hExtOrientationData->enableHeadRotation[i], 2 ) )
    1749             :             {
    1750       12400 :                 IF( hExtOrientationData->enableExternalOrientation[i] > 0 )
    1751             :                 {
    1752       12400 :                     QuaternionProduct_fx( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Quaternion_frozen_head, &hCombinedOrientationData->Quaternions[i] );
    1753             :                 }
    1754             :                 ELSE
    1755             :                 {
    1756           0 :                     hCombinedOrientationData->Quaternions[i] = hCombinedOrientationData->Quaternion_frozen_head;
    1757             :                 }
    1758             :             }
    1759             :             /* Reset the combined orientations to identity */
    1760      116800 :             test();
    1761      116800 :             if ( hExtOrientationData->enableHeadRotation[i] == 0 && hExtOrientationData->enableExternalOrientation[i] == 0 )
    1762             :             {
    1763           0 :                 hCombinedOrientationData->Quaternions[i] = identity;
    1764             :             }
    1765             :         }
    1766             :     }
    1767      249677 :     test();
    1768      249677 :     IF( headRotQuaternions != NULL || hExtOrientationData != NULL )
    1769             :     {
    1770             :         /* Calculate the combined rotation matrix */
    1771      816349 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1772             :         {
    1773      566672 :             QuatToRotMat_fx( hCombinedOrientationData->Quaternions[i], hCombinedOrientationData->Rmat_fx[i] );
    1774             :         }
    1775             :     }
    1776             : 
    1777             :     /* Save the current orientations */
    1778      249677 :     IF( hExtOrientationData != NULL )
    1779             :     {
    1780       29200 :         IF( hExtOrientationData->enableExternalOrientation[hExtOrientationData->num_subframes - 1] > 0 )
    1781             :         {
    1782       27557 :             hCombinedOrientationData->Quaternion_prev_extOrientation = hExtOrientationData->Quaternions[hExtOrientationData->num_subframes - 1];
    1783             :         }
    1784             :         ELSE
    1785             :         {
    1786        1643 :             hCombinedOrientationData->Quaternion_prev_extOrientation = identity;
    1787             :         }
    1788             :     }
    1789      249677 :     IF( headRotQuaternions != NULL )
    1790             :     {
    1791      816349 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1792             :         {
    1793      566672 :             hCombinedOrientationData->listenerPos[i] = listenerPos[i];
    1794             :         }
    1795             :     }
    1796             :     /* Check if combined orientation is enabled */
    1797      249677 :     test();
    1798      249677 :     test();
    1799      249677 :     test();
    1800      249677 :     IF( headRotQuaternions != NULL && hExtOrientationData == NULL )
    1801             :     {
    1802      670349 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1803             :         {
    1804      449872 :             hCombinedOrientationData->enableCombinedOrientation[i] = 1;
    1805      449872 :             move16();
    1806             :         }
    1807             :     }
    1808       29200 :     ELSE IF( headRotQuaternions == NULL && hExtOrientationData != NULL )
    1809             :     {
    1810           0 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1811             :         {
    1812           0 :             IF( hExtOrientationData->enableExternalOrientation[i] > 0 )
    1813             :             {
    1814           0 :                 hCombinedOrientationData->enableCombinedOrientation[i] = 1;
    1815           0 :                 move16();
    1816             :             }
    1817             :             ELSE
    1818             :             {
    1819           0 :                 hCombinedOrientationData->enableCombinedOrientation[i] = 0;
    1820           0 :                 move16();
    1821             :             }
    1822             :         }
    1823             :     }
    1824       29200 :     ELSE IF( headRotQuaternions != NULL && hExtOrientationData != NULL )
    1825             :     {
    1826      146000 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1827             :         {
    1828      116800 :             test();
    1829      116800 :             IF( hExtOrientationData->enableExternalOrientation[i] > 0 || ( hExtOrientationData->enableHeadRotation[i] > 0 ) )
    1830             :             {
    1831      116800 :                 hCombinedOrientationData->enableCombinedOrientation[i] = 1;
    1832      116800 :                 move16();
    1833             :             }
    1834             :             ELSE
    1835             :             {
    1836           0 :                 hCombinedOrientationData->enableCombinedOrientation[i] = 0;
    1837           0 :                 move16();
    1838             :             }
    1839             :         }
    1840             :     }
    1841             :     ELSE
    1842             :     {
    1843           0 :         FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1844             :         {
    1845           0 :             hCombinedOrientationData->enableCombinedOrientation[i] = 0;
    1846           0 :             move16();
    1847             :         }
    1848             :     }
    1849             : 
    1850      249677 :     hCombinedOrientationData->subframe_idx = 0;
    1851      249677 :     move16();
    1852      249677 :     hCombinedOrientationData->cur_subframe_samples_rendered = 0;
    1853      249677 :     move16();
    1854      249677 :     hCombinedOrientationData->subframe_idx_start = 0;
    1855      249677 :     move16();
    1856      249677 :     hCombinedOrientationData->cur_subframe_samples_rendered_start = 0;
    1857      249677 :     move16();
    1858      816349 :     FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1859             :     {
    1860     2266688 :         FOR( j = 0; j < 3; j++ )
    1861             :         {
    1862     6800064 :             FOR( Word16 k = 0; k < 3; k++ )
    1863             :             {
    1864     5100048 :                 hCombinedOrientationData->Rmat_fx[i][j][k] = L_shl( hCombinedOrientationData->Rmat_fx[i][j][k], sub( 62, shl( hCombinedOrientationData->Quaternions[i].q_fact, 1 ) ) ); // Q30
    1865     5100048 :                 move32();
    1866             :             }
    1867             :         }
    1868             :     }
    1869             : 
    1870      249677 :     Word16 l_shift = 0;
    1871      249677 :     move16();
    1872      816349 :     FOR( i = 0; i < hCombinedOrientationData->num_subframes; i++ )
    1873             :     {
    1874      566672 :         l_shift = s_min( s_min( Q_factor_L_32( hCombinedOrientationData->Quaternions[i].w_fx ), Q_factor_L_32( hCombinedOrientationData->Quaternions[i].x_fx ) ), s_min( Q_factor_L_32( hCombinedOrientationData->Quaternions[i].y_fx ), Q_factor_L_32( hCombinedOrientationData->Quaternions[i].z_fx ) ) );
    1875      566672 :         hCombinedOrientationData->Quaternions[i].w_fx = L_shl( hCombinedOrientationData->Quaternions[i].w_fx, l_shift ); // q_fact+l_shift
    1876      566672 :         move32();
    1877      566672 :         hCombinedOrientationData->Quaternions[i].x_fx = L_shl( hCombinedOrientationData->Quaternions[i].x_fx, l_shift ); // q_fact+l_shift
    1878      566672 :         move32();
    1879      566672 :         hCombinedOrientationData->Quaternions[i].y_fx = L_shl( hCombinedOrientationData->Quaternions[i].y_fx, l_shift ); // q_fact+l_shift
    1880      566672 :         move32();
    1881      566672 :         hCombinedOrientationData->Quaternions[i].z_fx = L_shl( hCombinedOrientationData->Quaternions[i].z_fx, l_shift ); // q_fact+l_shift
    1882      566672 :         move32();
    1883      566672 :         hCombinedOrientationData->Quaternions[i].q_fact = add( hCombinedOrientationData->Quaternions[i].q_fact, l_shift );
    1884      566672 :         move16();
    1885             :     }
    1886             : 
    1887      249677 :     hCombinedOrientationData->sr_pose_pred_axis = sr_pose_pred_axis;
    1888      249677 :     return IVAS_ERR_OK;
    1889             : }
    1890             : 
    1891             : /*-------------------------------------------------------------------------
    1892             :  * external_target_interpolation()
    1893             :  *
    1894             :  *
    1895             :  *------------------------------------------------------------------------*/
    1896       10334 : static void external_target_interpolation_fx(
    1897             :     EXTERNAL_ORIENTATION_HANDLE hExtOrientationData,      /* i  : external orientation handle   */
    1898             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle   */
    1899             :     const Word16 i                                        /* i  : subframe index                */
    1900             : )
    1901             : {
    1902             :     /* Sanity check for number of frames */
    1903       10334 :     hExtOrientationData->numFramesToTargetOrientation[i] = s_min( hExtOrientationData->numFramesToTargetOrientation[i], hCombinedOrientationData->maximumFramesToTargetOrientation );
    1904       10334 :     move16();
    1905       10334 :     hExtOrientationData->numFramesToTargetOrientation[i] = s_max( hExtOrientationData->numFramesToTargetOrientation[i], 0 );
    1906       10334 :     move16();
    1907             : 
    1908             :     /* Interpolate from the current orientation to the target orientation */
    1909       10334 :     IF( hExtOrientationData->numFramesToTargetOrientation[i] > 0 )
    1910             :     {
    1911        3349 :         IF( EQ_16( are_orientations_same_fx( &hCombinedOrientationData->Quaternions_ext_interpolation_target, &hExtOrientationData->Quaternions[i] ), false ) )
    1912             :         {
    1913             :             /* Target orientation is different from the previous target, update the values */
    1914             : 
    1915             :             /* Set the received orientation as the target */
    1916         249 :             hCombinedOrientationData->Quaternions_ext_interpolation_target = hExtOrientationData->Quaternions[i];
    1917             : 
    1918             :             /* Use the most recent external orientation as the starting orientation */
    1919         249 :             IF( EQ_16( hExtOrientationData->enableExternalOrientation[i], 1 ) )
    1920             :             {
    1921         218 :                 IF( i > 0 )
    1922             :                 {
    1923         141 :                     IF( hExtOrientationData->enableExternalOrientation[i - 1] == 0 )
    1924             :                     {
    1925             :                         IVAS_QUATERNION identity;
    1926          31 :                         identity.w_fx = ONE_IN_Q31;
    1927          31 :                         move32();
    1928          31 :                         identity.x_fx = identity.y_fx = identity.z_fx = 0;
    1929          31 :                         move32();
    1930          31 :                         move32();
    1931          31 :                         move32();
    1932          31 :                         identity.q_fact = 31;
    1933          31 :                         move16();
    1934          31 :                         hCombinedOrientationData->Quaternions_ext_interpolation_start = identity;
    1935             :                     }
    1936         110 :                     ELSE IF( EQ_16( hExtOrientationData->enableExternalOrientation[i - 1], 2 ) )
    1937             :                     {
    1938           0 :                         hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_frozen_ext;
    1939             :                     }
    1940             :                     ELSE
    1941             :                     {
    1942         110 :                         hCombinedOrientationData->Quaternions_ext_interpolation_start = hExtOrientationData->Quaternions[i - 1];
    1943             :                     }
    1944             :                 }
    1945             :                 ELSE
    1946             :                 {
    1947          77 :                     hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_prev_extOrientation;
    1948             :                 }
    1949             :             }
    1950          31 :             ELSE IF( EQ_16( hExtOrientationData->enableExternalOrientation[i], 2 ) )
    1951             :             {
    1952          31 :                 hCombinedOrientationData->Quaternions_ext_interpolation_start = hCombinedOrientationData->Quaternion_frozen_ext;
    1953             :             }
    1954         249 :             Word16 tmp_e = 0;
    1955         249 :             move16();
    1956             :             Word32 tmp;
    1957             :             /* Calculate the interpolation increment and coefficient */
    1958         249 :             tmp = BASOP_Util_Divide3232_Scale_newton( ONE_IN_Q30, L_shl( L_deposit_l( hExtOrientationData->numFramesToTargetOrientation[i] ), 2 ), &tmp_e );
    1959         249 :             hCombinedOrientationData->interpolationIncrement_fx = L_shl( tmp, sub( tmp_e, 31 ) ); /* Q30 */
    1960         249 :             move32();
    1961         249 :             hCombinedOrientationData->interpolationCoefficient_fx = hCombinedOrientationData->interpolationIncrement_fx;
    1962         249 :             move32();
    1963             :         }
    1964             : 
    1965             :         /* Interpolate */
    1966        3349 :         hCombinedOrientationData->isInterpolationOngoing = TRUE;
    1967        3349 :         move16();
    1968        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_start.w_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.w_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1969        3349 :         move32();
    1970        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_start.x_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.x_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1971        3349 :         move32();
    1972        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_start.y_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.y_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1973        3349 :         move32();
    1974        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_start.z_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_start.z_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact, Q29 ) ); // Q29
    1975        3349 :         move32();
    1976             : 
    1977        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_target.w_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.w_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1978        3349 :         move32();
    1979        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_target.x_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.x_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1980        3349 :         move32();
    1981        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_target.y_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.y_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1982        3349 :         move32();
    1983        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_target.z_fx = L_shr( hCombinedOrientationData->Quaternions_ext_interpolation_target.z_fx, sub( hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact, Q29 ) ); // Q29
    1984        3349 :         move32();
    1985             : 
    1986        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_start.q_fact = Q29;
    1987        3349 :         move16();
    1988        3349 :         hCombinedOrientationData->Quaternions_ext_interpolation_target.q_fact = Q29;
    1989        3349 :         move16();
    1990        3349 :         QuaternionSlerp_fx( hCombinedOrientationData->Quaternions_ext_interpolation_start, hCombinedOrientationData->Quaternions_ext_interpolation_target, hCombinedOrientationData->interpolationCoefficient_fx, &hCombinedOrientationData->Quaternions[i] );
    1991        3349 :         hCombinedOrientationData->interpolationCoefficient_fx = L_add_sat( hCombinedOrientationData->interpolationCoefficient_fx, hCombinedOrientationData->interpolationIncrement_fx );
    1992        3349 :         move32();
    1993             :     }
    1994             :     ELSE
    1995             :     {
    1996             :         /* Use the target orientation immediately */
    1997        6985 :         hCombinedOrientationData->isInterpolationOngoing = FALSE;
    1998        6985 :         move16();
    1999        6985 :         hCombinedOrientationData->interpolationCoefficient_fx = ONE_IN_Q30;
    2000        6985 :         move32();
    2001        6985 :         hCombinedOrientationData->interpolationIncrement_fx = ONE_IN_Q30;
    2002        6985 :         move32();
    2003        6985 :         hCombinedOrientationData->Quaternions[i] = hExtOrientationData->Quaternions[i];
    2004             :     }
    2005             : 
    2006       10334 :     return;
    2007             : }
    2008             : 
    2009             : /*-------------------------------------------------------------------------
    2010             :  * are_orientations_same()
    2011             :  *
    2012             :  *
    2013             :  *------------------------------------------------------------------------*/
    2014       54203 : static bool are_orientations_same_fx(
    2015             :     const IVAS_QUATERNION *orientation1,
    2016             :     const IVAS_QUATERNION *orientation2 )
    2017             : {
    2018       54203 :     bool orientationsAreSame = true;
    2019       54203 :     move16();
    2020       54203 :     Word32 error_margin_fx = 107374182; // 0.05f in Q31
    2021       54203 :     move32();
    2022       54203 :     Word16 error_margin_e = 0;
    2023       54203 :     move16();
    2024       54203 :     Word16 w_e = 0, x_e = 0, y_e = 0, z_e = 0;
    2025       54203 :     move16();
    2026       54203 :     move16();
    2027       54203 :     move16();
    2028       54203 :     move16();
    2029       54203 :     Word32 w_result = 0, x_result = 0, y_result = 0, z_result = 0;
    2030       54203 :     move32();
    2031       54203 :     move32();
    2032       54203 :     move32();
    2033       54203 :     move32();
    2034       54203 :     w_result = L_abs( BASOP_Util_Add_Mant32Exp( orientation1->w_fx, sub( 31, orientation1->q_fact ), L_negate( orientation2->w_fx ), sub( 31, orientation2->q_fact ), &w_e ) );
    2035       54203 :     x_result = L_abs( BASOP_Util_Add_Mant32Exp( orientation1->x_fx, sub( 31, orientation1->q_fact ), L_negate( orientation2->x_fx ), sub( 31, orientation2->q_fact ), &x_e ) );
    2036       54203 :     y_result = L_abs( BASOP_Util_Add_Mant32Exp( orientation1->y_fx, sub( 31, orientation1->q_fact ), L_negate( orientation2->y_fx ), sub( 31, orientation2->q_fact ), &y_e ) );
    2037       54203 :     z_result = L_abs( BASOP_Util_Add_Mant32Exp( orientation1->z_fx, sub( 31, orientation1->q_fact ), L_negate( orientation2->z_fx ), sub( 31, orientation2->q_fact ), &z_e ) );
    2038       54203 :     Word16 Flag_1 = BASOP_Util_Cmp_Mant32Exp( w_result, w_e, error_margin_fx, error_margin_e );
    2039       54203 :     Word16 Flag_2 = BASOP_Util_Cmp_Mant32Exp( x_result, x_e, error_margin_fx, error_margin_e );
    2040       54203 :     Word16 Flag_3 = BASOP_Util_Cmp_Mant32Exp( y_result, y_e, error_margin_fx, error_margin_e );
    2041       54203 :     Word16 Flag_4 = BASOP_Util_Cmp_Mant32Exp( z_result, z_e, error_margin_fx, error_margin_e );
    2042             : 
    2043       54203 :     test();
    2044       54203 :     test();
    2045       54203 :     test();
    2046      108073 :     if ( EQ_16( Flag_1, 1 ) ||
    2047      107740 :          EQ_16( Flag_2, 1 ) ||
    2048      107740 :          EQ_16( Flag_3, 1 ) ||
    2049       53870 :          EQ_16( Flag_4, 1 ) )
    2050             :     {
    2051         467 :         orientationsAreSame = false;
    2052         467 :         move16();
    2053             :     }
    2054             : 
    2055       54203 :     return orientationsAreSame;
    2056             : }
    2057             : 
    2058             : 
    2059             : /*-----------------------------------------------------------------------*
    2060             :  * Local Function definitions
    2061             :  *-----------------------------------------------------------------------*/
    2062             : /*-------------------------------------------------------------------------
    2063             :  * Helper functions used by SHrotmatgen,
    2064             :  * an implementation of the algorithm in
    2065             :  * Ivanic, J. & Ruedenberg, K., J. Phys. Chem. 100, 6342 (1996)
    2066             :  *------------------------------------------------------------------------*/
    2067    11623851 : static Word32 SHrot_p_fx(
    2068             :     const Word16 i,
    2069             :     const Word16 l,
    2070             :     const Word16 a,
    2071             :     const Word16 b,
    2072             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], // Q14
    2073             :     Word16 R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM] )   // Q14
    2074             : {
    2075             : 
    2076    11623851 :     Word16 ri1 = 0, rim1 = 0, ri0 = 0, R_lm1_1 = 0, R_lm1_2 = 0;
    2077    11623851 :     move16();
    2078    11623851 :     move16();
    2079    11623851 :     move16();
    2080    11623851 :     move16();
    2081    11623851 :     move16();
    2082             : 
    2083    11623851 :     Word32 p = 0;
    2084    11623851 :     move32();
    2085             : 
    2086    11623851 :     ri1 = SHrotmat[i + 1 + 1][1 + 1 + 1]; // Q14
    2087    11623851 :     move16();
    2088    11623851 :     rim1 = SHrotmat[i + 1 + 1][-1 + 1 + 1]; // Q14
    2089    11623851 :     move16();
    2090    11623851 :     ri0 = SHrotmat[i + 1 + 1][0 + 1 + 1]; // Q14
    2091    11623851 :     move16();
    2092             : 
    2093    11623851 :     IF( EQ_16( b, -l ) )
    2094             :     {
    2095     1915131 :         R_lm1_1 = R_lm1[a + l - 1][0]; // Q14
    2096     1915131 :         move16();
    2097     1915131 :         R_lm1_2 = R_lm1[a + l - 1][2 * l - 2]; // Q14
    2098     1915131 :         move16();
    2099     1915131 :         p = L_mac0( L_mult0( ri1, R_lm1_1 ), rim1, R_lm1_2 ); // Q28
    2100             :     }
    2101             :     ELSE
    2102             :     {
    2103     9708720 :         IF( EQ_16( b, l ) )
    2104             :         {
    2105     1915131 :             R_lm1_1 = R_lm1[a + l - 1][2 * l - 2]; // Q14
    2106     1915131 :             move16();
    2107     1915131 :             R_lm1_2 = R_lm1[a + l - 1][0]; // Q14
    2108     1915131 :             move16();
    2109     1915131 :             p = L_msu0( L_mult0( ri1, R_lm1_1 ), rim1, R_lm1_2 ); // Q28
    2110             :         }
    2111             :         ELSE
    2112             :         {
    2113     7793589 :             R_lm1_1 = R_lm1[a + l - 1][b + l - 1];
    2114     7793589 :             move16();
    2115     7793589 :             p = L_mult0( ri0, R_lm1_1 ); // Q28
    2116             :         }
    2117             :     }
    2118             : 
    2119    11623851 :     return p; // Q28
    2120             : }
    2121             : 
    2122     2586525 : static Word32 SHrot_u_fx(
    2123             :     const Word16 l,
    2124             :     const Word16 m,
    2125             :     const Word16 n,
    2126             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], // Q14
    2127             :     Word16 R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]     // Q14
    2128             : )
    2129             : {
    2130     2586525 :     return SHrot_p_fx( 0, l, m, n, SHrotmat, R_lm1 );
    2131             : }
    2132             : 
    2133     3895299 : static Word32 SHrot_v_fx(
    2134             :     const Word16 l,
    2135             :     const Word16 m,
    2136             :     const Word16 n,
    2137             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], // Q14
    2138             :     Word16 R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]     // Q14
    2139             : )
    2140             : {
    2141             : 
    2142             :     Word32 result;
    2143             :     Word32 p0, p1;
    2144             :     Word16 d;
    2145             : 
    2146     3895299 :     IF( m == 0 )
    2147             :     {
    2148      654387 :         p0 = SHrot_p_fx( 1, l, 1, n, SHrotmat, R_lm1 );   // Q28
    2149      654387 :         p1 = SHrot_p_fx( -1, l, -1, n, SHrotmat, R_lm1 ); // Q28
    2150      654387 :         result = L_shr( L_add( p0, p1 ), 2 );             // converting to Q27
    2151             :     }
    2152             :     ELSE
    2153             :     {
    2154     3240912 :         IF( m > 0 )
    2155             :         {
    2156     1620456 :             d = 0;
    2157     1620456 :             move16();
    2158     1620456 :             if ( EQ_16( m, 1 ) )
    2159             :             {
    2160      654387 :                 d = 1;
    2161      654387 :                 move16();
    2162             :             }
    2163     1620456 :             p0 = SHrot_p_fx( 1, l, sub( m, 1 ), n, SHrotmat, R_lm1 );                                           // Q28
    2164     1620456 :             p1 = SHrot_p_fx( -1, l, add( negate( m ), 1 ), n, SHrotmat, R_lm1 );                                // Q28
    2165     1620456 :             result = Msub_32_16_r( Mpy_32_16_r( p0, square_root16_table[1 + d] ), p1, shl( sub( 1, d ), 14 ) ); // Q27
    2166             :         }
    2167             :         ELSE
    2168             :         {
    2169     1620456 :             d = 0;
    2170     1620456 :             move16();
    2171     1620456 :             if ( EQ_16( m, -1 ) )
    2172             :             {
    2173      654387 :                 d = 1;
    2174      654387 :                 move16();
    2175             :             }
    2176     1620456 :             p0 = SHrot_p_fx( 1, l, add( m, 1 ), n, SHrotmat, R_lm1 );
    2177     1620456 :             p1 = SHrot_p_fx( -1, l, negate( add( m, 1 ) ), n, SHrotmat, R_lm1 );
    2178     1620456 :             result = Madd_32_16_r( Mpy_32_16_r( p0, shl( sub( 1, d ), 14 ) ), p1, square_root16_table[1 + d] ); // Q27
    2179             :         }
    2180             :     }
    2181     3895299 :     return result; // Q27
    2182             : }
    2183             : 
    2184      623364 : static Word32 SHrot_w_fx(
    2185             :     const Word16 l,
    2186             :     const Word16 m,
    2187             :     const Word16 n,
    2188             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], // Q14
    2189             :     Word16 R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM]     // Q14
    2190             : )
    2191             : {
    2192             :     Word32 result, p0, p1;
    2193             : 
    2194      623364 :     IF( m == 0 )
    2195             :     {
    2196           0 :         assert( 0 && "ERROR should not be called\n" );
    2197             :         return 0;
    2198             :     }
    2199             :     ELSE
    2200             :     {
    2201      623364 :         IF( m > 0 )
    2202             :         {
    2203      311682 :             p0 = SHrot_p_fx( 1, l, add( m, 1 ), n, SHrotmat, R_lm1 );            // Q28
    2204      311682 :             p1 = SHrot_p_fx( -1, l, negate( add( m, 1 ) ), n, SHrotmat, R_lm1 ); // Q28
    2205      311682 :             result = L_add( p0, p1 );                                            // Q28
    2206             :         }
    2207             :         ELSE
    2208             :         {
    2209      311682 :             p0 = SHrot_p_fx( 1, l, sub( m, 1 ), n, SHrotmat, R_lm1 );  // Q28
    2210      311682 :             p1 = SHrot_p_fx( -1, l, sub( 1, m ), n, SHrotmat, R_lm1 ); // Q28
    2211      311682 :             result = L_sub( p0, p1 );                                  // Q28
    2212             :         }
    2213             :     }
    2214             : 
    2215      623364 :     return result; // Q28
    2216             : }
    2217             : 
    2218             : 
    2219             : /*-------------------------------------------------------------------------
    2220             :  * SHrotmatgen_fx()
    2221             :  *
    2222             :  *
    2223             :  *------------------------------------------------------------------------*/
    2224             : 
    2225       92556 : void SHrotmatgen_fx(
    2226             :     Word16 SHrotmat[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM], /* o  : rotation matrix in SHD     Q14 */
    2227             :     Word32 Rmat[3][3],                                     /* i  : real-space rotation matrix Q30 */
    2228             :     const Word16 order                                     /* i  : ambisonics order               */
    2229             : )
    2230             : {
    2231       92556 :     Word16 d = 0;
    2232       92556 :     move16();
    2233       92556 :     Word16 band_idx = 0;
    2234       92556 :     move16();
    2235             :     Word16 i, j;
    2236             :     Word16 l, m, n;
    2237             :     Word16 absm;
    2238       92556 :     Word16 sqdenom = 0, sql2mm2 = 0, sqdabsm = 0, sqlabsm = 0;
    2239       92556 :     Word16 u = 0, v = 0, w = 0;
    2240       92556 :     move16();
    2241       92556 :     move16();
    2242       92556 :     move16();
    2243       92556 :     move16();
    2244       92556 :     move16();
    2245       92556 :     move16();
    2246       92556 :     move16();
    2247             : 
    2248       92556 :     Word32 u32_fx = 0, v32_fx = 0, w32_fx = 0;
    2249       92556 :     move32();
    2250       92556 :     move32();
    2251       92556 :     move32();
    2252             : 
    2253             :     Word16 R_lm1[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
    2254             : 
    2255     1573452 :     FOR( i = 0; i < HEADROT_SHMAT_DIM; i++ )
    2256             :     {
    2257     1480896 :         set16_fx( R_lm1[i], 0, HEADROT_SHMAT_DIM );
    2258             :     }
    2259             :     Word16 R_l[HEADROT_SHMAT_DIM][HEADROT_SHMAT_DIM];
    2260             :     Word32 result;
    2261       92556 :     SHrotmat[0][0] = ONE_IN_Q14;
    2262       92556 :     move16();
    2263             : 
    2264       92556 :     SHrotmat[1][1] = extract_h( Rmat[1][1] ); // Q14
    2265       92556 :     move16();
    2266       92556 :     SHrotmat[1][2] = extract_h( Rmat[1][2] );
    2267       92556 :     move16();
    2268       92556 :     SHrotmat[1][3] = extract_h( Rmat[1][0] );
    2269       92556 :     move16();
    2270             : 
    2271       92556 :     SHrotmat[2][1] = extract_h( Rmat[2][1] ); // Q14
    2272       92556 :     move16();
    2273       92556 :     SHrotmat[2][2] = extract_h( Rmat[2][2] );
    2274       92556 :     move16();
    2275       92556 :     SHrotmat[2][3] = extract_h( Rmat[2][0] );
    2276       92556 :     move16();
    2277             : 
    2278       92556 :     SHrotmat[3][1] = extract_h( Rmat[0][1] ); // Q14
    2279       92556 :     move16();
    2280       92556 :     SHrotmat[3][2] = extract_h( Rmat[0][2] );
    2281       92556 :     move16();
    2282       92556 :     SHrotmat[3][3] = extract_h( Rmat[0][0] );
    2283       92556 :     move16();
    2284             : 
    2285      370224 :     FOR( i = 0; i < 2 * 1 + 1; i++ )
    2286             :     {
    2287     1110672 :         FOR( j = 0; j < 2 * 1 + 1; j++ )
    2288             :         {
    2289      833004 :             R_lm1[i][j] = SHrotmat[i + 1][j + 1]; // Q14
    2290      833004 :             move16();
    2291             :         }
    2292             :     }
    2293       92556 :     band_idx = 4;
    2294       92556 :     move16();
    2295      205623 :     FOR( l = 2; l <= order; l++ )
    2296             :     {
    2297      113067 :         set16_fx( &R_l[0][0], 0, HEADROT_SHMAT_DIM2 );
    2298      767454 :         FOR( m = -l; m <= l; m++ )
    2299             :         {
    2300      654387 :             d = 0;
    2301      654387 :             move16();
    2302      654387 :             if ( m == 0 )
    2303             :             {
    2304      113067 :                 d = 1;
    2305      113067 :                 move16();
    2306             :             }
    2307      654387 :             absm = extract_l( L_abs( m ) );
    2308             : 
    2309      654387 :             sql2mm2 = square_root30_q12[l * l - m * m]; // Q12
    2310      654387 :             move16();
    2311      654387 :             sqdabsm = square_root30_q12[( 1 + d ) * ( l + absm - 1 ) * ( l + absm )]; // Q12
    2312      654387 :             move16();
    2313      654387 :             sqlabsm = square_root30_q12[( ( l - ( absm + 1 ) ) * ( l - absm ) )]; // Q12
    2314      654387 :             move16();
    2315             : 
    2316     4549686 :             FOR( n = -l; n <= l; n++ )
    2317             :             {
    2318     3895299 :                 IF( EQ_16( abs_s( n ), l ) )
    2319             :                 {
    2320     1308774 :                     sqdenom = square_root30_q12[( ( 2 * l ) * ( 2 * l - 1 ) )]; // Q12
    2321     1308774 :                     move16();
    2322             :                 }
    2323             :                 ELSE
    2324             :                 {
    2325     2586525 :                     sqdenom = square_root30_q12[( l * l - n * n )]; // Q12
    2326     2586525 :                     move16();
    2327             :                 }
    2328             : 
    2329             : 
    2330     3895299 :                 u = div_l( L_shl( (Word32) sql2mm2, 15 ), sqdenom );                                     // Q14
    2331     3895299 :                 v = imult1616( div_l( L_shl( (Word32) sqdabsm, 14 ), sqdenom ), sub( 1, shl( d, 1 ) ) ); // Q14
    2332     3895299 :                 w = imult1616( div_l( L_shl( (Word32) sqlabsm, 14 ), sqdenom ), negate( sub( 1, d ) ) ); // Q14
    2333             : 
    2334     3895299 :                 IF( u != 0 )
    2335             :                 {
    2336     2586525 :                     result = SHrot_u_fx( l, m, n, SHrotmat, R_lm1 ); // Q28
    2337     2586525 :                     u32_fx = Mpy_32_16_r( result, u );               // Q27
    2338             :                 }
    2339     3895299 :                 IF( v != 0 )
    2340             :                 {
    2341     3895299 :                     result = SHrot_v_fx( l, m, n, SHrotmat, R_lm1 );
    2342     3895299 :                     v32_fx = Mpy_32_16_r( result, v ); // Q26
    2343             :                 }
    2344     3895299 :                 IF( w != 0 )
    2345             :                 {
    2346      623364 :                     result = SHrot_w_fx( l, m, n, SHrotmat, R_lm1 );
    2347      623364 :                     w32_fx = Mpy_32_16_r( result, w ); // Q27
    2348             :                 }
    2349             :                 // Addind and converting to 16 bit integer of Q14
    2350     3895299 :                 R_l[m + l][n + l] = extract_h( L_shl( L_add( L_add( L_shr( u32_fx, 1 ), v32_fx ), L_shr( w32_fx, 1 ) ), 4 ) ); // Q14
    2351     3895299 :                 move16();
    2352             :             }
    2353             :         }
    2354             : 
    2355      767454 :         FOR( i = 0; i < 2 * l + 1; i++ )
    2356             :         {
    2357     4549686 :             FOR( j = 0; j < 2 * l + 1; j++ )
    2358             :             {
    2359     3895299 :                 SHrotmat[band_idx + i][band_idx + j] = R_l[i][j]; // Q14
    2360     3895299 :                 move16();
    2361             :             }
    2362             :         }
    2363             : 
    2364      767454 :         FOR( i = 0; i < 2 * l + 1; i++ )
    2365             :         {
    2366     4549686 :             FOR( j = 0; j < 2 * l + 1; j++ )
    2367             :             {
    2368     3895299 :                 R_lm1[i][j] = R_l[i][j];
    2369     3895299 :                 move16();
    2370             :             }
    2371             :         }
    2372             : 
    2373      113067 :         band_idx = add( band_idx, add( shl( l, 1 ), 1 ) );
    2374             :     }
    2375             : 
    2376       92556 :     return;
    2377             : }
    2378             : 
    2379             : 
    2380             : /*-------------------------------------------------------------------------
    2381             :  * ivas_combined_orientation_update_index()
    2382             :  *
    2383             :  * update read index based on the number of rendered samples
    2384             :  *------------------------------------------------------------------------*/
    2385             : 
    2386     2165884 : void ivas_combined_orientation_update_index(
    2387             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle           */
    2388             :     const Word16 samples_rendered                         /* i  : samples rendered since the last call  */
    2389             : )
    2390             : {
    2391             :     Word16 exp, div_result;
    2392     2165884 :     IF( hCombinedOrientationData != NULL )
    2393             :     {
    2394      551081 :         IF( EQ_16( hCombinedOrientationData->num_subframes, 1 ) || hCombinedOrientationData->sr_low_res_flag )
    2395             :         {
    2396             :             /* only one orientation available anyway or split rendering with low resolution*/
    2397      135601 :             hCombinedOrientationData->subframe_idx = 0;
    2398      135601 :             move16();
    2399             :         }
    2400             :         ELSE
    2401             :         {
    2402      415480 :             hCombinedOrientationData->cur_subframe_samples_rendered = add( hCombinedOrientationData->cur_subframe_samples_rendered, samples_rendered );
    2403      415480 :             move16();
    2404      415480 :             div_result = BASOP_Util_Divide3216_Scale( hCombinedOrientationData->cur_subframe_samples_rendered, hCombinedOrientationData->subframe_size, &exp );
    2405      415480 :             hCombinedOrientationData->subframe_idx = add( hCombinedOrientationData->subframe_idx, shl( div_result, add( exp, 1 ) ) );
    2406      415480 :             move16();
    2407      415480 :             hCombinedOrientationData->cur_subframe_samples_rendered = hCombinedOrientationData->cur_subframe_samples_rendered % hCombinedOrientationData->subframe_size;
    2408      415480 :             move16();
    2409      415480 :             hCombinedOrientationData->subframe_idx = s_min( hCombinedOrientationData->subframe_idx, sub( hCombinedOrientationData->num_subframes, 1 ) );
    2410      415480 :             move16();
    2411             :         }
    2412             :     }
    2413             : 
    2414     2165884 :     return;
    2415             : }
    2416             : 
    2417             : 
    2418             : /*-------------------------------------------------------------------------
    2419             :  * ivas_combined_orientation_set_to_start_index()
    2420             :  *
    2421             :  * update read index based on the number of rendered samples
    2422             :  *------------------------------------------------------------------------*/
    2423             : 
    2424     1956292 : void ivas_combined_orientation_set_to_start_index(
    2425             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData /* i/o: combined orientation handle    */
    2426             : )
    2427             : {
    2428     1956292 :     IF( hCombinedOrientationData != NULL )
    2429             :     {
    2430      385062 :         hCombinedOrientationData->subframe_idx = hCombinedOrientationData->subframe_idx_start;
    2431      385062 :         move16();
    2432      385062 :         hCombinedOrientationData->cur_subframe_samples_rendered = hCombinedOrientationData->cur_subframe_samples_rendered_start;
    2433      385062 :         move16();
    2434             :     }
    2435             : 
    2436     1956292 :     return;
    2437             : }
    2438             : /*-------------------------------------------------------------------------
    2439             :  * ivas_combined_orientation_update_start_index()
    2440             :  *
    2441             :  * update start index based on the number of rendered samples
    2442             :  *------------------------------------------------------------------------*/
    2443             : 
    2444     1550596 : void ivas_combined_orientation_update_start_index(
    2445             :     COMBINED_ORIENTATION_HANDLE hCombinedOrientationData, /* i/o: combined orientation handle           */
    2446             :     const Word16 samples_rendered                         /* i  : samples rendered since the last call  */
    2447             : )
    2448             : {
    2449     1550596 :     IF( hCombinedOrientationData != NULL )
    2450             :     {
    2451      249762 :         IF( EQ_16( hCombinedOrientationData->num_subframes, 1 ) || hCombinedOrientationData->sr_low_res_flag )
    2452             :         {
    2453             :             /* only one orientation available anyway or split rendering with low resolution*/
    2454      144012 :             hCombinedOrientationData->subframe_idx = 0;
    2455      144012 :             move16();
    2456             :         }
    2457             :         ELSE
    2458             :         {
    2459      105750 :             hCombinedOrientationData->cur_subframe_samples_rendered_start = add( hCombinedOrientationData->cur_subframe_samples_rendered_start, samples_rendered );
    2460      105750 :             move16();
    2461      105750 :             hCombinedOrientationData->subframe_idx_start = add( hCombinedOrientationData->subframe_idx_start, mult( hCombinedOrientationData->cur_subframe_samples_rendered, div_s( 1, hCombinedOrientationData->subframe_size ) ) );
    2462      105750 :             move16();
    2463      105750 :             hCombinedOrientationData->cur_subframe_samples_rendered_start = hCombinedOrientationData->cur_subframe_samples_rendered % hCombinedOrientationData->subframe_size; /* No operator to calculate modulo*/
    2464      105750 :             move16();
    2465      105750 :             hCombinedOrientationData->subframe_idx_start = s_min( hCombinedOrientationData->subframe_idx, sub( hCombinedOrientationData->num_subframes, 1 ) );
    2466      105750 :             move16();
    2467             :         }
    2468             :     }
    2469             : 
    2470     1550596 :     return;
    2471             : }

Generated by: LCOV version 1.14