LCOV - code coverage report
Current view: top level - lib_rend - ivas_orient_trk_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 421 472 89.2 %
Date: 2025-08-23 01:22:27 Functions: 18 22 81.8 %

          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 "common_api_types.h"
      34             : #include <stdint.h>
      35             : #include "options.h"
      36             : #include "ivas_prot_fx.h"
      37             : #include "ivas_prot_rend_fx.h"
      38             : #include "ivas_cnst.h"
      39             : #include <math.h>
      40             : #include <assert.h>
      41             : #include "wmc_auto.h"
      42             : #include "prot_fx.h"
      43             : 
      44             : /*------------------------------------------------------------------------------------------*
      45             :  * Local constants
      46             :  *------------------------------------------------------------------------------------------*/
      47             : 
      48             : #define COS_ONE_TENTH_DEGREE_FX 2147480320 // Q31
      49             : 
      50             : 
      51             : /*------------------------------------------------------------------------------------------*
      52             :  * Local functions
      53             :  *------------------------------------------------------------------------------------------*/
      54             : 
      55             : /*------------------------------------------------------------------------------------------*
      56             :  * IdentityQuaternion()
      57             :  *
      58             :  *
      59             :  *------------------------------------------------------------------------------------------*/
      60             : 
      61           0 : static IVAS_QUATERNION IdentityQuaternion_fx(
      62             :     void )
      63             : {
      64             :     IVAS_QUATERNION q;
      65             : 
      66           0 :     q.w_fx = ONE_IN_Q31;
      67           0 :     move32();
      68           0 :     q.x_fx = q.y_fx = q.z_fx = 0;
      69           0 :     move32();
      70           0 :     move32();
      71           0 :     move32();
      72           0 :     q.q_fact = Q31;
      73           0 :     move16();
      74             : 
      75           0 :     return q;
      76             : }
      77             : 
      78             : /*------------------------------------------------------------------------------------------*
      79             :  * QuaternionProduct()
      80             :  *
      81             :  * Quaternion product
      82             :  *------------------------------------------------------------------------------------------*/
      83             : 
      84      192273 : void QuaternionProduct_fx(
      85             :     const IVAS_QUATERNION q1,
      86             :     const IVAS_QUATERNION q2,
      87             :     IVAS_QUATERNION *const r )
      88             : {
      89             :     IVAS_QUATERNION tmp;
      90             : 
      91             :     // once verify//
      92      192273 :     tmp.w_fx = L_sub( ( L_sub( Mpy_32_32( q1.w_fx, q2.w_fx ), Mpy_32_32( q1.x_fx, q2.x_fx ) ) ), ( L_add( Mpy_32_32( q1.y_fx, q2.y_fx ), Mpy_32_32( q1.z_fx, q2.z_fx ) ) ) ); // ( q1.q_fact + q2.q_fact ) - 31
      93      192273 :     move32();
      94      192273 :     tmp.x_fx = L_add( ( L_add( Mpy_32_32( q1.w_fx, q2.x_fx ), Mpy_32_32( q1.x_fx, q2.w_fx ) ) ), ( L_sub( Mpy_32_32( q1.y_fx, q2.z_fx ), Mpy_32_32( q1.z_fx, q2.y_fx ) ) ) ); // ( q1.q_fact + q2.q_fact ) - 31
      95      192273 :     move32();
      96      192273 :     tmp.y_fx = L_add( ( L_sub( Mpy_32_32( q1.w_fx, q2.y_fx ), Mpy_32_32( q1.x_fx, q2.z_fx ) ) ), ( L_add( Mpy_32_32( q1.y_fx, q2.w_fx ), Mpy_32_32( q1.z_fx, q2.x_fx ) ) ) ); // ( q1.q_fact + q2.q_fact ) - 31
      97      192273 :     move32();
      98      192273 :     tmp.z_fx = L_sub( ( L_add( Mpy_32_32( q1.w_fx, q2.z_fx ), Mpy_32_32( q1.x_fx, q2.y_fx ) ) ), ( L_sub( Mpy_32_32( q1.y_fx, q2.x_fx ), Mpy_32_32( q1.z_fx, q2.w_fx ) ) ) ); // ( q1.q_fact + q2.q_fact ) - 31
      99      192273 :     move32();
     100      192273 :     tmp.q_fact = sub( add( q1.q_fact, q2.q_fact ), 31 );
     101      192273 :     move16();
     102             : 
     103      192273 :     *r = tmp;
     104      192273 :     return;
     105             : }
     106             : 
     107             : /*------------------------------------------------------------------------------------------*
     108             :  * QuaternionDotProduct()
     109             :  *
     110             :  * Quaternion dot product
     111             :  *------------------------------------------------------------------------------------------*/
     112             : 
     113      613572 : static Word32 QuaternionDotProduct_fx(
     114             :     const IVAS_QUATERNION q1,
     115             :     const IVAS_QUATERNION q2,
     116             :     Word16 *q_fact )
     117             : {
     118             : 
     119      613572 :     Word32 result = 0;
     120      613572 :     move32();
     121             : 
     122      613572 :     result = L_add( ( L_add( Mpy_32_32( q1.x_fx, q2.x_fx ), Mpy_32_32( q1.y_fx, q2.y_fx ) ) ), ( L_add( Mpy_32_32( q1.z_fx, q2.z_fx ), Mpy_32_32( q1.w_fx, q2.w_fx ) ) ) ); // ( q1.q_fact + q2.q_fact ) - 31
     123             : 
     124      613572 :     *q_fact = sub( add( q1.q_fact, q2.q_fact ), 31 );
     125      613572 :     move16();
     126             : 
     127      613572 :     return result;
     128             : }
     129             : 
     130             : /*------------------------------------------------------------------------------------------*
     131             :  * QuaternionDivision()
     132             :  *
     133             :  * Divides a quaternion by a scalar
     134             :  *------------------------------------------------------------------------------------------*/
     135             : 
     136      537749 : static void QuaternionDivision_fx(
     137             :     const IVAS_QUATERNION q,
     138             :     const Word32 d,
     139             :     IVAS_QUATERNION *const r,
     140             :     Word16 den_e )
     141             : {
     142      537749 :     Word16 scale_e, result_e = 0, w_q, x_q, y_q, z_q, result_q;
     143             : 
     144      537749 :     r->w_fx = BASOP_Util_Divide3232_Scale_newton( ( q.w_fx ), d, &scale_e );
     145      537749 :     move32();
     146      537749 :     result_e = add( scale_e, sub( sub( Q31, q.q_fact ), den_e ) ); // e+e1-e2//
     147      537749 :     w_q = sub( Q31, result_e );
     148             : 
     149      537749 :     r->x_fx = BASOP_Util_Divide3232_Scale_newton( ( q.x_fx ), d, &scale_e );
     150      537749 :     move32();
     151      537749 :     result_e = add( scale_e, sub( sub( Q31, q.q_fact ), den_e ) );
     152      537749 :     x_q = sub( Q31, result_e );
     153             : 
     154      537749 :     r->y_fx = BASOP_Util_Divide3232_Scale_newton( ( q.y_fx ), d, &scale_e );
     155      537749 :     move32();
     156      537749 :     result_e = add( scale_e, sub( sub( Q31, q.q_fact ), den_e ) );
     157      537749 :     y_q = sub( Q31, result_e );
     158             : 
     159      537749 :     r->z_fx = BASOP_Util_Divide3232_Scale_newton( ( q.z_fx ), d, &scale_e );
     160      537749 :     move32();
     161      537749 :     result_e = add( scale_e, sub( sub( Q31, q.q_fact ), den_e ) );
     162      537749 :     z_q = sub( Q31, result_e );
     163             : 
     164      537749 :     result_q = sub( s_min( s_min( w_q, x_q ), s_min( y_q, z_q ) ), 1 ); // gaurdbits//
     165             : 
     166      537749 :     r->w_fx = L_shr( r->w_fx, sub( w_q, result_q ) ); // result_q
     167      537749 :     move32();
     168      537749 :     r->x_fx = L_shr( r->x_fx, sub( x_q, result_q ) ); // result_q
     169      537749 :     move32();
     170      537749 :     r->y_fx = L_shr( r->y_fx, sub( y_q, result_q ) ); // result_q
     171      537749 :     move32();
     172      537749 :     r->z_fx = L_shr( r->z_fx, sub( z_q, result_q ) ); // result_q
     173      537749 :     move32();
     174      537749 :     r->q_fact = result_q;
     175      537749 :     move16();
     176      537749 : }
     177             : 
     178             : 
     179             : /*------------------------------------------------------------------------------------------*
     180             :  * QuaternionNormalize()
     181             :  *
     182             :  * Normalizes a quaternion
     183             :  *------------------------------------------------------------------------------------------*/
     184             : 
     185      296303 : static void QuaternionNormalize_fx(
     186             :     const IVAS_QUATERNION q_fx,
     187             :     IVAS_QUATERNION *const r_fx )
     188             : {
     189      296303 :     Word16 q_dot, sqrt_e = 0;
     190      296303 :     move16();
     191             :     Word32 sqrt_fx;
     192      296303 :     Word32 dot_prod_fx = QuaternionDotProduct_fx( q_fx, q_fx, &q_dot );
     193      296303 :     sqrt_e = sub( Q31, q_dot );
     194      296303 :     sqrt_fx = Sqrt32( dot_prod_fx, &sqrt_e );
     195      296303 :     QuaternionDivision_fx( q_fx, sqrt_fx, r_fx, sqrt_e );
     196      296303 :     return;
     197             : }
     198             : 
     199             : 
     200             : /*------------------------------------------------------------------------------------------*
     201             :  * QuaternionSlerp()
     202             :  *
     203             :  * Computes a spherical linear interpolation between two quaternions
     204             :  *------------------------------------------------------------------------------------------*/
     205             : 
     206       97433 : void QuaternionSlerp_fx(
     207             :     const IVAS_QUATERNION q1_fx,
     208             :     const IVAS_QUATERNION q2_fx,
     209             :     const Word32 t_fx,
     210             :     IVAS_QUATERNION *const r_fx )
     211             : {
     212             :     IVAS_QUATERNION r1, r2, tmp_quat;
     213             :     Word32 sinPhi, cosPhi, temp_32;
     214             :     Word16 q_min, sin_e, phi, s1, s2, temp_16;
     215             : 
     216       97433 :     QuaternionNormalize_fx( q1_fx, &r1 );
     217       97433 :     QuaternionNormalize_fx( q2_fx, &r2 );
     218             : 
     219       97433 :     Word16 q_dot = 0;
     220       97433 :     move16();
     221       97433 :     cosPhi = QuaternionDotProduct_fx( r1, r2, &q_dot );
     222             : 
     223       97433 :     q_min = s_min( r1.q_fact, r2.q_fact );
     224       97433 :     r1.w_fx = L_shr( r1.w_fx, sub( r1.q_fact, q_min ) ); // q_min
     225       97433 :     move32();
     226       97433 :     r1.x_fx = L_shr( r1.x_fx, sub( r1.q_fact, q_min ) ); // q_min
     227       97433 :     move32();
     228       97433 :     r1.y_fx = L_shr( r1.y_fx, sub( r1.q_fact, q_min ) ); // q_min
     229       97433 :     move32();
     230       97433 :     r1.z_fx = L_shr( r1.z_fx, sub( r1.q_fact, q_min ) ); // q_min
     231       97433 :     move32();
     232       97433 :     r2.w_fx = L_shr( r2.w_fx, sub( r2.q_fact, q_min ) ); // q_min
     233       97433 :     move32();
     234       97433 :     r2.x_fx = L_shr( r2.x_fx, sub( r2.q_fact, q_min ) ); // q_min
     235       97433 :     move32();
     236       97433 :     r2.y_fx = L_shr( r2.y_fx, sub( r2.q_fact, q_min ) ); // q_min
     237       97433 :     move32();
     238       97433 :     r2.z_fx = L_shr( r2.z_fx, sub( r2.q_fact, q_min ) ); // q_min
     239       97433 :     move32();
     240       97433 :     r1.q_fact = r2.q_fact = q_min;
     241       97433 :     move16();
     242       97433 :     move16();
     243             : 
     244       97433 :     IF( cosPhi < 0 )
     245             :     {
     246        7143 :         cosPhi = L_negate( cosPhi );
     247        7143 :         r2.w_fx = L_negate( r2.w_fx );
     248        7143 :         move32();
     249        7143 :         r2.x_fx = L_negate( r2.x_fx );
     250        7143 :         move32();
     251        7143 :         r2.y_fx = L_negate( r2.y_fx );
     252        7143 :         move32();
     253        7143 :         r2.z_fx = L_negate( r2.z_fx );
     254        7143 :         move32();
     255             :     }
     256             : 
     257             : 
     258             :     /* Angle less than one degree, use linear interpolation */
     259       97433 :     IF( GE_32( cosPhi, L_shr( COS_ONE_TENTH_DEGREE_FX, sub( 31, q_dot ) ) ) )
     260             :     {
     261       32375 :         r_fx->w_fx = L_add( L_shr( r1.w_fx, 1 ), Mpy_32_32( L_sub( r2.w_fx, r1.w_fx ), t_fx ) ); // q_min-1
     262       32375 :         move32();
     263       32375 :         r_fx->x_fx = L_add( L_shr( r1.x_fx, 1 ), Mpy_32_32( L_sub( r2.x_fx, r1.x_fx ), t_fx ) ); // q_min-1
     264       32375 :         move32();
     265       32375 :         r_fx->y_fx = L_add( L_shr( r1.y_fx, 1 ), Mpy_32_32( L_sub( r2.y_fx, r1.y_fx ), t_fx ) ); // q_min-1
     266       32375 :         move32();
     267       32375 :         r_fx->z_fx = L_add( L_shr( r1.z_fx, 1 ), Mpy_32_32( L_sub( r2.z_fx, r1.z_fx ), t_fx ) ); // q_min-1
     268       32375 :         move32();
     269             : 
     270       32375 :         r_fx->q_fact = sub( q_min, 1 );
     271       32375 :         move16();
     272             :     }
     273             :     ELSE
     274             :     {
     275       65058 :         temp_32 = L_sub( L_shr( ONE_IN_Q31, sub( 62, shl( q_dot, 1 ) ) ), ( Mpy_32_32( cosPhi, cosPhi ) ) ); // exp: sin_e
     276       65058 :         sin_e = sub( 62, shl( q_dot, 1 ) );
     277       65058 :         sinPhi = Sqrt32( temp_32, &sin_e );
     278             : 
     279       65058 :         phi = BASOP_util_atan2( sinPhi, cosPhi, sub( sin_e, sub( 31, q_dot ) ) ); // Q13
     280             : 
     281       65058 :         temp_32 = L_shl( Mpy_32_16_1( L_sub( ONE_IN_Q30, t_fx ), phi ), 1 ); // Q29
     282             : 
     283       65058 :         temp_16 = extract_h( temp_32 );                 // Q13
     284       65058 :         s1 = getSineWord16R2( mult( temp_16, 20860 ) ); // Q15
     285             :         // 2 / pi in Q15 -> 20860
     286             : 
     287       65058 :         temp_32 = L_shl( Mpy_32_16_1( t_fx, phi ), 1 ); // Q29
     288       65058 :         temp_16 = extract_h( temp_32 );                 // Q13
     289       65058 :         s2 = getSineWord16R2( mult( temp_16, 20860 ) ); // Q15
     290             :         // 2 / pi in Q15 -> 20860
     291             : 
     292       65058 :         tmp_quat.w_fx = L_add( Mpy_32_16_1( r1.w_fx, s1 ), Mpy_32_16_1( r2.w_fx, s2 ) ); // q_min
     293       65058 :         move32();
     294       65058 :         tmp_quat.x_fx = L_add( Mpy_32_16_1( r1.x_fx, s1 ), Mpy_32_16_1( r2.x_fx, s2 ) ); // q_min
     295       65058 :         move32();
     296       65058 :         tmp_quat.y_fx = L_add( Mpy_32_16_1( r1.y_fx, s1 ), Mpy_32_16_1( r2.y_fx, s2 ) ); // q_min
     297       65058 :         move32();
     298       65058 :         tmp_quat.z_fx = L_add( Mpy_32_16_1( r1.z_fx, s1 ), Mpy_32_16_1( r2.z_fx, s2 ) ); // q_min
     299       65058 :         move32();
     300       65058 :         tmp_quat.q_fact = q_min;
     301       65058 :         move16();
     302             : 
     303       65058 :         QuaternionDivision_fx( tmp_quat, sinPhi, r_fx, sin_e );
     304             :     }
     305             : 
     306       97433 :     QuaternionNormalize_fx( *r_fx, r_fx );
     307       97433 :     return;
     308             : }
     309             : 
     310             : /*------------------------------------------------------------------------------------------*
     311             :  * QuaternionConjugate()
     312             :  *
     313             :  * Computes a quaternion conjugate
     314             :  *------------------------------------------------------------------------------------------*/
     315             : 
     316      219836 : static void QuaternionConjugate_fx(
     317             :     const IVAS_QUATERNION q,
     318             :     IVAS_QUATERNION *const r )
     319             : {
     320      219836 :     r->w_fx = q.w_fx;
     321      219836 :     move32();
     322      219836 :     r->x_fx = L_negate( q.x_fx );
     323      219836 :     move32();
     324      219836 :     r->y_fx = L_negate( q.y_fx );
     325      219836 :     move32();
     326      219836 :     r->z_fx = L_negate( q.z_fx );
     327      219836 :     move32();
     328      219836 :     r->q_fact = q.q_fact;
     329      219836 :     move16();
     330             : 
     331      219836 :     return;
     332             : }
     333             : 
     334             : /*------------------------------------------------------------------------------------------*
     335             :  * QuaternionAngle()
     336             :  *
     337             :  * Computes an angle between two quaternions
     338             :  *------------------------------------------------------------------------------------------*/
     339             : 
     340       43448 : static Word32 QuaternionAngle_fx(
     341             :     const IVAS_QUATERNION q1,
     342             :     const IVAS_QUATERNION q2 )
     343             : {
     344             :     IVAS_QUATERNION q12;
     345             : 
     346       43448 :     QuaternionConjugate_fx( q1, &q12 );
     347       43448 :     QuaternionProduct_fx( q12, q2, &q12 ); // q12:Q25, q2:Q29, q1: Q27//
     348             : 
     349       43448 :     Word32 temp = 0;
     350       43448 :     move32();
     351       43448 :     Word16 q_dot, result_e = 0;
     352       43448 :     move16();
     353       43448 :     temp = q12.w_fx;
     354       43448 :     move32();
     355       43448 :     q12.w_fx = 0;
     356       43448 :     move32();
     357       43448 :     Word32 result = 0;
     358       43448 :     move32();
     359       43448 :     result = QuaternionDotProduct_fx( q12, q12, &q_dot );
     360       43448 :     result_e = sub( 31, q_dot );
     361       43448 :     result = Sqrt32( result, &result_e );
     362       43448 :     q12.w_fx = temp;
     363       43448 :     move32();
     364             : 
     365       43448 :     Word16 tan_result = BASOP_util_atan2( result, q12.w_fx, sub( result_e, sub( 31, q12.q_fact ) ) );
     366       43448 :     result = L_deposit_h( tan_result ); // Q29
     367       43448 :     return result;
     368             : }
     369             : 
     370             : /*------------------------------------------------------------------------------------------*
     371             :  * QuaternionInverse()
     372             :  *
     373             :  * Computes an inverse quaternion
     374             :  *------------------------------------------------------------------------------------------*/
     375             : 
     376      176388 : void QuaternionInverse_fx(
     377             :     const IVAS_QUATERNION q,
     378             :     IVAS_QUATERNION *const r )
     379             : {
     380             :     Word32 dot_product;
     381      176388 :     Word16 dot_q = 0;
     382      176388 :     move16();
     383      176388 :     dot_product = QuaternionDotProduct_fx( q, q, &dot_q );
     384      176388 :     QuaternionConjugate_fx( q, r );
     385      176388 :     QuaternionDivision_fx( *r, dot_product, r, sub( Q31, dot_q ) );
     386             : 
     387      176388 :     return;
     388             : }
     389             : 
     390             : 
     391             : /*------------------------------------------------------------------------------------------*
     392             :  * VectorSubtract()
     393             :  *
     394             :  * Computes the difference of two vectors
     395             :  *------------------------------------------------------------------------------------------*/
     396             : 
     397        4004 : static IVAS_VECTOR3 VectorSubtract_fx(
     398             :     const IVAS_VECTOR3 p1,
     399             :     const IVAS_VECTOR3 p2 )
     400             : {
     401             :     IVAS_VECTOR3 result;
     402        4004 :     Word16 e_result = 0, x_qfact, y_qfact, z_qfact, q_result;
     403        4004 :     move16();
     404        4004 :     result.x_fx = BASOP_Util_Add_Mant32Exp( p1.x_fx, sub( Q31, p1.q_fact ), ( L_negate( p2.x_fx ) ), sub( Q31, p2.q_fact ), &e_result );
     405        4004 :     move32();
     406        4004 :     x_qfact = sub( 31, e_result );
     407             : 
     408        4004 :     result.y_fx = BASOP_Util_Add_Mant32Exp( p1.y_fx, sub( Q31, p1.q_fact ), ( L_negate( p2.y_fx ) ), sub( Q31, p2.q_fact ), &e_result );
     409        4004 :     move32();
     410        4004 :     y_qfact = sub( 31, e_result );
     411             : 
     412        4004 :     result.z_fx = BASOP_Util_Add_Mant32Exp( p1.z_fx, sub( Q31, p1.q_fact ), ( L_negate( p2.z_fx ) ), sub( Q31, p2.q_fact ), &e_result );
     413        4004 :     move32();
     414        4004 :     z_qfact = sub( 31, e_result );
     415             : 
     416        4004 :     q_result = sub( s_min( s_min( x_qfact, y_qfact ), z_qfact ), 1 ); // guardbit//
     417        4004 :     result.x_fx = L_shr( result.x_fx, sub( x_qfact, q_result ) );     // q_result
     418        4004 :     move32();
     419        4004 :     result.y_fx = L_shr( result.y_fx, sub( y_qfact, q_result ) ); // q_result
     420        4004 :     move32();
     421        4004 :     result.z_fx = L_shr( result.z_fx, sub( z_qfact, q_result ) ); // q_result
     422        4004 :     move32();
     423        4004 :     result.q_fact = q_result;
     424        4004 :     move16();
     425             : 
     426        4004 :     return result;
     427             : }
     428             : 
     429             : 
     430             : /*------------------------------------------------------------------------------------------*
     431             :  * VectorCrossProduct()
     432             :  *
     433             :  * Computes the cross product of two vectors
     434             :  *------------------------------------------------------------------------------------------*/
     435             : 
     436        4004 : static IVAS_VECTOR3 VectorCrossProduct_fx(
     437             :     const IVAS_VECTOR3 p1,
     438             :     const IVAS_VECTOR3 p2 )
     439             : {
     440             :     IVAS_VECTOR3 result_fx;
     441             : 
     442        4004 :     result_fx.x_fx = L_sub( Mpy_32_32( p1.y_fx, p2.z_fx ), Mpy_32_32( p1.z_fx, p2.y_fx ) ); // Q: ( p1.q_fact + p2.q_fact ) - 31
     443        4004 :     move32();
     444        4004 :     result_fx.y_fx = L_sub( Mpy_32_32( p1.z_fx, p2.x_fx ), Mpy_32_32( p1.x_fx, p2.z_fx ) ); // Q: ( p1.q_fact + p2.q_fact ) - 31
     445        4004 :     move32();
     446        4004 :     result_fx.z_fx = L_sub( Mpy_32_32( p1.x_fx, p2.y_fx ), Mpy_32_32( p1.y_fx, p2.x_fx ) ); // Q: ( p1.q_fact + p2.q_fact ) - 31
     447        4004 :     move32();
     448        4004 :     result_fx.q_fact = sub( add( p1.q_fact, p2.q_fact ), 31 );
     449        4004 :     move16();
     450             : 
     451        4004 :     return result_fx;
     452             : }
     453             : 
     454             : /*------------------------------------------------------------------------------------------*
     455             :  * VectorDotProduct(
     456             :  *
     457             :  * Computes the dot product of two vectors
     458             :  *------------------------------------------------------------------------------------------*/
     459             : 
     460        4004 : static Word32 VectorDotProduct_fx(
     461             :     const IVAS_VECTOR3 p1,
     462             :     const IVAS_VECTOR3 p2,
     463             :     Word16 *q_fact )
     464             : {
     465        4004 :     Word32 result_fx = 0;
     466        4004 :     move32();
     467             : 
     468        4004 :     result_fx = L_add( L_add( Mpy_32_32( p1.x_fx, p2.x_fx ), Mpy_32_32( p1.y_fx, p2.y_fx ) ), Mpy_32_32( p1.z_fx, p2.z_fx ) ); // // Q: ( p1.q_fact + p2.q_fact ) - 31
     469        4004 :     *q_fact = sub( add( p1.q_fact, p2.q_fact ), 31 );
     470        4004 :     move16();
     471             : 
     472        4004 :     return result_fx;
     473             : }
     474             : 
     475             : /*------------------------------------------------------------------------------------------*
     476             :  * VectorLength()
     477             :  *
     478             :  * Computes the length of a vector
     479             :  *------------------------------------------------------------------------------------------*/
     480             : 
     481       12012 : static Word32 VectorLength_fx(
     482             :     IVAS_VECTOR3 p,
     483             :     Word16 *q_fact )
     484             : {
     485       12012 :     Word32 result_fx = 0;
     486       12012 :     move32();
     487       12012 :     result_fx = L_add( L_add( Mpy_32_32( p.x_fx, p.x_fx ), Mpy_32_32( p.y_fx, p.y_fx ) ), Mpy_32_32( p.z_fx, p.z_fx ) ); // // Q: ( p1.q_fact + p2.q_fact ) - 31
     488             : 
     489       12012 :     *q_fact = sub( add( p.q_fact, p.q_fact ), 31 );
     490       12012 :     move16();
     491       12012 :     return result_fx;
     492             : }
     493             : 
     494             : /*------------------------------------------------------------------------------------------*
     495             :  * VectorNormalize()
     496             :  *
     497             :  * Normalizes a vector
     498             :  *------------------------------------------------------------------------------------------*/
     499             : 
     500        8008 : static IVAS_VECTOR3 VectorNormalize_fx(
     501             :     const IVAS_VECTOR3 p )
     502             : {
     503             :     IVAS_VECTOR3 result_fx;
     504             :     Word32 length_fx;
     505        8008 :     Word16 q_len, scale = 0, x_qfact, y_qfact, z_qfact, q_result;
     506        8008 :     move16();
     507        8008 :     length_fx = VectorLength_fx( p, &q_len );
     508             : 
     509        8008 :     result_fx.x_fx = BASOP_Util_Divide3232_Scale_newton( p.x_fx, length_fx, &scale );
     510        8008 :     move32();
     511        8008 :     x_qfact = sub( Q31, add( scale, sub( q_len, p.q_fact ) ) ); // e+(e1-e2)//
     512             : 
     513        8008 :     result_fx.y_fx = BASOP_Util_Divide3232_Scale_newton( p.y_fx, length_fx, &scale );
     514        8008 :     move32();
     515        8008 :     y_qfact = sub( Q31, add( scale, sub( q_len, p.q_fact ) ) );
     516             : 
     517        8008 :     result_fx.z_fx = BASOP_Util_Divide3232_Scale_newton( p.z_fx, length_fx, &scale );
     518        8008 :     move32();
     519        8008 :     z_qfact = sub( Q31, add( scale, sub( q_len, p.q_fact ) ) );
     520             : 
     521        8008 :     q_result = s_min( s_min( x_qfact, y_qfact ), z_qfact );
     522        8008 :     result_fx.x_fx = L_shr( result_fx.x_fx, sub( x_qfact, q_result ) ); // Q: q_result
     523        8008 :     move32();
     524        8008 :     result_fx.y_fx = L_shr( result_fx.y_fx, sub( y_qfact, q_result ) ); // Q: q_result
     525        8008 :     move32();
     526        8008 :     result_fx.z_fx = L_shr( result_fx.z_fx, sub( z_qfact, q_result ) ); // Q: q_result
     527        8008 :     move32();
     528        8008 :     result_fx.q_fact = q_result;
     529        8008 :     move16();
     530             : 
     531        8008 :     return result_fx;
     532             : }
     533             : 
     534             : /*------------------------------------------------------------------------------------------*
     535             :  * VectorRotationToQuaternion()
     536             :  *
     537             :  * Computes a quaternion representing the rotation from vector p1 to vector p2
     538             :  *------------------------------------------------------------------------------------------*/
     539             : 
     540        4004 : static void VectorRotationToQuaternion_fx(
     541             :     const IVAS_VECTOR3 p1,
     542             :     const IVAS_VECTOR3 p2,
     543             :     IVAS_QUATERNION *const r )
     544             : {
     545        4004 :     IVAS_VECTOR3 cross_product_fx, p1_normalized_fx = { 0 }, p2_normalized_fx = { 0 };
     546             :     Word32 dot_product_fx;
     547             :     Word16 q_dot, e_add, q_result;
     548             : 
     549        4004 :     p1_normalized_fx = VectorNormalize_fx( p1 );
     550        4004 :     p2_normalized_fx = VectorNormalize_fx( p2 );
     551        4004 :     cross_product_fx = VectorCrossProduct_fx( p1_normalized_fx, p2_normalized_fx );
     552        4004 :     dot_product_fx = VectorDotProduct_fx( p1_normalized_fx, p2_normalized_fx, &q_dot );
     553             :     // dot & cross product are same q//
     554             : 
     555        4004 :     Word32 comp_fx = -2147481472; //-0.999999f in Q31
     556        4004 :     move32();
     557        4004 :     Word16 comp_e = 0, check_flag;
     558        4004 :     move16();
     559        4004 :     IF( dot_product_fx > 0 )
     560             :     {
     561        1984 :         check_flag = 0;
     562        1984 :         move16();
     563             :     }
     564             :     ELSE
     565             :     {
     566        2020 :         check_flag = BASOP_Util_Cmp_Mant32Exp( comp_fx, comp_e, dot_product_fx, sub( 31, q_dot ) );
     567             :     }
     568        4004 :     IF( EQ_16( check_flag, 1 ) )
     569             :     {
     570          20 :         r->w_fx = 0;
     571          20 :         move32();
     572          20 :         r->x_fx = 0;
     573          20 :         move32();
     574          20 :         r->y_fx = 0;
     575          20 :         move32();
     576          20 :         r->z_fx = ONE_IN_Q31;
     577          20 :         move32();
     578          20 :         r->q_fact = Q31;
     579          20 :         move16();
     580             :     }
     581             :     ELSE
     582             :     {
     583             :         /* all regular cases */
     584        3984 :         r->x_fx = cross_product_fx.x_fx;
     585        3984 :         move32();
     586        3984 :         r->y_fx = cross_product_fx.y_fx;
     587        3984 :         move32();
     588        3984 :         r->z_fx = cross_product_fx.z_fx;
     589        3984 :         move32();
     590        3984 :         r->w_fx = BASOP_Util_Add_Mant32Exp( dot_product_fx, sub( 31, q_dot ), ONE_IN_Q31, 0, &e_add );
     591        3984 :         move32();
     592        3984 :         q_result = sub( s_min( sub( 31, e_add ), q_dot ), 1 ); // gaurd bits//
     593        3984 :         r->x_fx = L_shr( r->x_fx, sub( q_dot, q_result ) );
     594        3984 :         move32();
     595        3984 :         r->y_fx = L_shr( r->y_fx, sub( q_dot, q_result ) );
     596        3984 :         move32();
     597        3984 :         r->z_fx = L_shr( r->z_fx, sub( q_dot, q_result ) );
     598        3984 :         move32();
     599        3984 :         r->w_fx = L_shr( r->w_fx, sub( sub( 31, e_add ), q_result ) );
     600        3984 :         move32();
     601             : 
     602        3984 :         r->q_fact = q_result;
     603        3984 :         move16();
     604             :     }
     605        4004 :     QuaternionNormalize_fx( *r, r );
     606             : 
     607        4004 :     return;
     608             : }
     609             : 
     610             : /*-------------------------------------------------------------------*
     611             :  * ivas_orient_trk_Init()
     612             :  *
     613             :  *
     614             :  *-------------------------------------------------------------------*/
     615             : 
     616         176 : ivas_error ivas_orient_trk_Init_fx(
     617             :     ivas_orient_trk_state_t *pOTR ) /* i/o  : orientation tracker handle    */
     618             : {
     619             :     IVAS_QUATERNION identity_fx;
     620             : 
     621         176 :     IF( pOTR == NULL )
     622             :     {
     623           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     624             :     }
     625         176 :     identity_fx.w_fx = ONE_IN_Q31;
     626         176 :     move32();
     627         176 :     identity_fx.x_fx = identity_fx.y_fx = identity_fx.z_fx = 0;
     628         176 :     move32();
     629         176 :     move32();
     630         176 :     move32();
     631         176 :     identity_fx.q_fact = Q31;
     632         176 :     move16();
     633             : 
     634             :     /* configuration parameters */
     635         176 :     pOTR->centerAdaptationRate_fx = C_ADP_RATE_Q31;
     636         176 :     move32();
     637         176 :     pOTR->offCenterAdaptationRate_fx = OFF_C_ADP_RATE_Q31;
     638         176 :     move32();
     639         176 :     pOTR->adaptationAngle_fx = PI_OVER_4_Q29; /* Excursion angle relative to center at which maximum adaptation rate shall be applied */
     640         176 :     move32();
     641             : 
     642             :     /* initial adaptivity filter coefficient, will be auto-adapted */
     643             :     // pOTR->alpha = sinf( PI2 * pOTR->offCenterAdaptationRate / OTR_UPDATE_RATE ); /* start adaptation at off-center rate = fastest rate */
     644         176 :     pOTR->alpha_fx = 33731208;
     645         176 :     move32(); // Q31
     646         176 :     pOTR->Q_alpha = Q31;
     647         176 :     move16();
     648         176 :     pOTR->trkRot = identity_fx;
     649         176 :     pOTR->absAvgRot = identity_fx;
     650             :     /* Use frontal and horiontal orientation as reference orientation, unless/until overridden  */
     651         176 :     pOTR->refRot = identity_fx;
     652             : 
     653             :     // this part still float//
     654             :     /* set safe default tracking mode */
     655         176 :     pOTR->orientation_tracking = IVAS_HEAD_ORIENT_TRK_NONE;
     656         176 :     move16();
     657             : 
     658         176 :     return IVAS_ERR_OK;
     659             : }
     660             : 
     661             : /*-------------------------------------------------------------------*
     662             :  * ivas_orient_trk_SetTrackingType()
     663             :  *
     664             :  *
     665             :  *-------------------------------------------------------------------*/
     666             : 
     667         176 : ivas_error ivas_orient_trk_SetTrackingType_fx(
     668             :     ivas_orient_trk_state_t *pOTR,                    /* i/o: orientation tracker handle    */
     669             :     const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i  : orientation tracking type     */
     670             : )
     671             : {
     672         176 :     IF( pOTR == NULL )
     673             :     {
     674           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     675             :     }
     676             : 
     677         176 :     pOTR->orientation_tracking = orientation_tracking;
     678         176 :     move16();
     679             : 
     680         176 :     return IVAS_ERR_OK;
     681             : }
     682             : 
     683             : /*-------------------------------------------------------------------*
     684             :  * ivas_orient_trk_SetReferenceRotation()
     685             :  *
     686             :  *
     687             :  *-------------------------------------------------------------------*/
     688             : 
     689           0 : ivas_error ivas_orient_trk_SetReferenceRotation_fx(
     690             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle     */
     691             :     const IVAS_QUATERNION refRot   /* i  : reference rotation             */
     692             : )
     693             : {
     694           0 :     IF( pOTR == NULL )
     695             :     {
     696           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     697             :     }
     698             : 
     699             :     /* check for Euler angle signaling */
     700           0 :     IF( EQ_32( refRot.w_fx, L_negate( 12582912 ) ) && EQ_16( refRot.q_fact, Q22 ) )
     701             :     {
     702           0 :         Euler2Quat_fx( deg2rad_fx( refRot.x_fx ), deg2rad_fx( refRot.y_fx ), deg2rad_fx( refRot.z_fx ), &pOTR->refRot );
     703           0 :         modify_Quat_q_fx( &pOTR->refRot, &pOTR->refRot, Q29 );
     704             :     }
     705           0 :     pOTR->refRot = refRot;
     706             : 
     707           0 :     return IVAS_ERR_OK;
     708             : }
     709             : 
     710             : /*-------------------------------------------------------------------*
     711             :  * ivas_orient_trk_GetMainOrientation()
     712             :  *
     713             :  *
     714             :  *-------------------------------------------------------------------*/
     715             : 
     716           0 : ivas_error ivas_orient_trk_GetMainOrientation_fx(
     717             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle     */
     718             :     IVAS_QUATERNION *pOrientation  /* i/o: average/reference orientation  */
     719             : )
     720             : {
     721           0 :     test();
     722           0 :     IF( pOTR == NULL || pOrientation == NULL )
     723             :     {
     724           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     725             :     }
     726             : 
     727           0 :     SWITCH( pOTR->orientation_tracking )
     728             :     {
     729           0 :         case IVAS_HEAD_ORIENT_TRK_NONE:
     730           0 :             *pOrientation = IdentityQuaternion_fx();
     731           0 :             BREAK;
     732           0 :         case IVAS_HEAD_ORIENT_TRK_REF_VEC:
     733             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC_LEV:
     734             :         case IVAS_HEAD_ORIENT_TRK_REF:
     735           0 :             *pOrientation = pOTR->refRot;
     736           0 :             BREAK;
     737           0 :         case IVAS_HEAD_ORIENT_TRK_AVG:
     738           0 :             *pOrientation = pOTR->absAvgRot;
     739           0 :             BREAK;
     740             :     }
     741             : 
     742           0 :     return IVAS_ERR_OK;
     743             : }
     744             : 
     745             : /*-------------------------------------------------------------------*
     746             :  * ivas_orient_trk_GetTrackedRotation()
     747             :  *
     748             :  *
     749             :  *-------------------------------------------------------------------*/
     750             : 
     751           0 : ivas_error ivas_orient_trk_GetTrackedRotation_fx(
     752             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle    */
     753             :     IVAS_QUATERNION *pRotation     /* i/o: processed rotation            */
     754             : )
     755             : {
     756           0 :     test();
     757           0 :     IF( pOTR == NULL || pRotation == NULL )
     758             :     {
     759           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     760             :     }
     761             : 
     762           0 :     *pRotation = pOTR->trkRot;
     763             : 
     764           0 :     return IVAS_ERR_OK;
     765             : }
     766             : 
     767             : /*-------------------------------------------------------------------*
     768             :  * ivas_orient_trk_SetReferenceVector()
     769             :  *
     770             :  *
     771             :  *-------------------------------------------------------------------*/
     772             : 
     773        4004 : ivas_error ivas_orient_trk_SetReferenceVector_fx(
     774             :     ivas_orient_trk_state_t *pOTR,  /* i/o: orientation tracker handle  */
     775             :     const IVAS_VECTOR3 listenerPos, /* i  : Listener position           */
     776             :     const IVAS_VECTOR3 refPos       /* i  : Reference position          */
     777             : )
     778             : {
     779             :     IVAS_VECTOR3 acousticFrontVector, ivasForwardVector;
     780             :     IVAS_VECTOR3 listenerPosLevel, refPosLevel;
     781             :     Word32 acousticFrontVectorLength;
     782             : 
     783        4004 :     IF( pOTR == NULL )
     784             :     {
     785           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     786             :     }
     787             : 
     788        4004 :     SWITCH( pOTR->orientation_tracking )
     789             :     {
     790        2002 :         case IVAS_HEAD_ORIENT_TRK_NONE:
     791             :         case IVAS_HEAD_ORIENT_TRK_REF:
     792             :         case IVAS_HEAD_ORIENT_TRK_AVG:
     793             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC:
     794        2002 :             acousticFrontVector = VectorSubtract_fx( refPos, listenerPos );
     795        2002 :             BREAK;
     796        2002 :         case IVAS_HEAD_ORIENT_TRK_REF_VEC_LEV:
     797             :             /* ignore the height difference between listener position and reference position */
     798        2002 :             listenerPosLevel.z_fx = refPosLevel.z_fx = listenerPos.z_fx;
     799        2002 :             move32();
     800        2002 :             listenerPosLevel.x_fx = listenerPos.x_fx;
     801        2002 :             move32();
     802        2002 :             listenerPosLevel.y_fx = listenerPos.y_fx;
     803        2002 :             move32();
     804        2002 :             listenerPosLevel.q_fact = listenerPos.q_fact;
     805        2002 :             move16();
     806             : 
     807        2002 :             refPosLevel.x_fx = refPos.x_fx;
     808        2002 :             move32();
     809        2002 :             refPosLevel.y_fx = refPos.y_fx;
     810        2002 :             move32();
     811        2002 :             Word16 q_min = s_min( listenerPos.q_fact, refPos.q_fact );
     812        2002 :             refPosLevel.x_fx = L_shr( refPosLevel.x_fx, sub( refPos.q_fact, q_min ) );
     813        2002 :             move32();
     814        2002 :             refPosLevel.y_fx = L_shr( refPosLevel.y_fx, sub( refPos.q_fact, q_min ) );
     815        2002 :             move32();
     816        2002 :             refPosLevel.z_fx = L_shr( refPosLevel.z_fx, sub( refPos.q_fact, q_min ) );
     817        2002 :             move32();
     818        2002 :             refPosLevel.q_fact = q_min;
     819        2002 :             move16();
     820             : 
     821        2002 :             acousticFrontVector = VectorSubtract_fx( refPosLevel, listenerPosLevel );
     822        2002 :             BREAK;
     823           0 :         default:
     824           0 :             return IVAS_ERR_WRONG_PARAMS;
     825             :     }
     826             : 
     827        4004 :     Word16 accoustic_q = acousticFrontVector.q_fact;
     828        4004 :     move16();
     829        4004 :     acousticFrontVectorLength = VectorLength_fx( acousticFrontVector, &acousticFrontVector.q_fact );
     830        4004 :     acousticFrontVector.q_fact = accoustic_q;
     831        4004 :     move16();
     832             :     /* if the length is zero, the user has entered insensible listener and reference positions */
     833        4004 :     IF( LE_32( acousticFrontVectorLength, 0 ) )
     834             :     {
     835           0 :         return IVAS_ERR_WRONG_PARAMS;
     836             :     }
     837             : 
     838        4004 :     ivasForwardVector.x_fx = ONE_IN_Q31;
     839        4004 :     move32();
     840        4004 :     ivasForwardVector.y_fx = 0;
     841        4004 :     move32();
     842        4004 :     ivasForwardVector.z_fx = 0;
     843        4004 :     move32();
     844        4004 :     ivasForwardVector.q_fact = Q31;
     845        4004 :     move16();
     846        4004 :     VectorRotationToQuaternion_fx( ivasForwardVector, acousticFrontVector, &pOTR->refRot );
     847             : 
     848        4004 :     return IVAS_ERR_OK;
     849             : }
     850             : 
     851             : 
     852             : /*-------------------------------------------------------------------*
     853             :  * ivas_orient_trk_Process()
     854             :  *
     855             :  *
     856             :  *-------------------------------------------------------------------*/
     857             : 
     858      567032 : ivas_error ivas_orient_trk_Process_fx(
     859             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle    */
     860             :     IVAS_QUATERNION absRot,        /* i  : absolute head rotation        */
     861             :     Word32 updateRate_fx,          /* i  : rotation update rate [Hz]     */
     862             :     IVAS_QUATERNION *pTrkRot       /* o  : tracked rotation              */
     863             : )
     864             : {
     865             :     ivas_error result;
     866             :     Word32 rateRange_fx;
     867             :     Word32 cutoffFrequency_fx, cutoff_prod;
     868      567032 :     Word16 q_cutoff_prod = 0;
     869      567032 :     move16();
     870      567032 :     Word32 alpha_fx = L_shl( pOTR->alpha_fx, sub( Q30, pOTR->Q_alpha ) ); // Q30
     871             : 
     872      567032 :     test();
     873      567032 :     IF( pOTR == NULL || pTrkRot == NULL )
     874             :     {
     875           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     876             :     }
     877             : 
     878      567032 :     result = IVAS_ERR_OK;
     879      567032 :     move32();
     880             : 
     881      567032 :     SWITCH( pOTR->orientation_tracking )
     882             :     {
     883      507568 :         case IVAS_HEAD_ORIENT_TRK_NONE:
     884      507568 :             pOTR->trkRot = absRot;
     885      507568 :             BREAK;
     886       16016 :         case IVAS_HEAD_ORIENT_TRK_REF:
     887             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC:
     888             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC_LEV:
     889             :             /* Reset average orientation   */
     890       16016 :             pOTR->absAvgRot = absRot;
     891             : 
     892             :             Word16 scale_e;
     893             :             Word32 div;
     894       16016 :             div = L_deposit_h( BASOP_Util_Divide3232_Scale( pOTR->centerAdaptationRate_fx, updateRate_fx, &scale_e ) );
     895             : 
     896       16016 :             scale_e = sub( scale_e, 8 ); // e+e1-e2//
     897             :             // here div value is less so we can use sandwitch rule of sine//
     898       16016 :             pOTR->alpha_fx = div;
     899       16016 :             move32();
     900             :             /* Compute relative orientation = (absolute orientation) - (reference orientation) */
     901       16016 :             QuaternionInverse_fx( pOTR->refRot, &pOTR->trkRot );
     902       16016 :             QuaternionProduct_fx( pOTR->trkRot, absRot, &pOTR->trkRot );
     903       16016 :             BREAK;
     904             : 
     905       43448 :         case IVAS_HEAD_ORIENT_TRK_AVG:
     906             :             /* Compute average (low-pass filtered) absolute orientation */
     907       43448 :             QuaternionSlerp_fx( pOTR->absAvgRot, absRot, alpha_fx, &pOTR->absAvgRot );
     908             : 
     909             :             /* Compute relative orientation = (absolute orientation) - (average absolute orientation) */
     910       43448 :             QuaternionInverse_fx( pOTR->absAvgRot, &pOTR->trkRot );
     911       43448 :             Word32 angle_fx, relativeOrientationRate_fx = 0;
     912       43448 :             move32();
     913       43448 :             QuaternionProduct_fx( pOTR->trkRot, absRot, &pOTR->trkRot );
     914       43448 :             angle_fx = QuaternionAngle_fx( absRot, pOTR->trkRot ); // Q29
     915       43448 :             Word16 result_e = 0;
     916       43448 :             move16();
     917       43448 :             Word16 temp_result = BASOP_Util_Divide3232_Scale( angle_fx, pOTR->adaptationAngle_fx, &result_e );
     918       43448 :             relativeOrientationRate_fx = L_deposit_h( temp_result );
     919       43448 :             Word32 one_fx = ONE_IN_Q30;
     920       43448 :             move32();
     921             : 
     922       43448 :             IF( GT_32( relativeOrientationRate_fx, one_fx ) )
     923             :             {
     924        1444 :                 relativeOrientationRate_fx = 1;
     925        1444 :                 move32();
     926             :             }
     927             : 
     928             :             /* Compute range of the adaptation rate between center = lower rate and off-center = higher rate */
     929       43448 :             rateRange_fx = L_sub( pOTR->offCenterAdaptationRate_fx, pOTR->centerAdaptationRate_fx );
     930             :             /* 'if' assumed to perform comparison to 0 */
     931       43448 :             if ( 0 > rateRange_fx )
     932             :             {
     933           0 :                 rateRange_fx = 0;
     934           0 :                 move32();
     935             :             }
     936       43448 :             IF( EQ_32( relativeOrientationRate_fx, 1 ) )
     937             :             {
     938        1444 :                 cutoff_prod = rateRange_fx;
     939        1444 :                 move32();
     940        1444 :                 q_cutoff_prod = Q31;
     941        1444 :                 move16();
     942             :             }
     943             :             ELSE
     944             :             {
     945       42004 :                 cutoff_prod = Mpy_32_32( relativeOrientationRate_fx, rateRange_fx );
     946       42004 :                 q_cutoff_prod = add( Q31, sub( sub( 31, result_e ), 31 ) );
     947             :             }
     948             :             Word16 temp_diff;
     949       43448 :             temp_diff = sub( 31, q_cutoff_prod );
     950       43448 :             cutoff_prod = L_shl( cutoff_prod, temp_diff );
     951             :             /* Compute adaptivity cutoff frequency: interpolate between minimum (center) and maximum (off-center) values */
     952       43448 :             cutoffFrequency_fx = L_add( pOTR->centerAdaptationRate_fx, cutoff_prod ); // Q31
     953       43448 :             cutoff_prod = Mpy_32_32( cutoffFrequency_fx, PI2_C_Q28 );
     954       43448 :             q_cutoff_prod = ( ( 31 + 28 ) - 31 );
     955       43448 :             temp_result = BASOP_Util_Divide3232_Scale( cutoff_prod, updateRate_fx, &result_e );
     956       43448 :             result_e = add( result_e, sub( 23, q_cutoff_prod ) );
     957       43448 :             pOTR->alpha_fx = L_deposit_h( temp_result );
     958       43448 :             move32();
     959       43448 :             pOTR->Q_alpha = sub( Q31, result_e );
     960       43448 :             move16();
     961       43448 :             BREAK;
     962           0 :         default:
     963           0 :             result = IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Non-supported orientation tracking adaptation type" );
     964           0 :             BREAK;
     965             :     }
     966             : 
     967      567032 :     if ( result == IVAS_ERR_OK )
     968             :     {
     969      567032 :         *pTrkRot = pOTR->trkRot;
     970             :     }
     971      567032 :     return result;
     972             : }

Generated by: LCOV version 1.14