LCOV - code coverage report
Current view: top level - lib_rend - ivas_orient_trk.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 163 205 79.5 %
Date: 2025-05-23 08:37:30 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.h"
      37             : #include "ivas_prot_rend.h"
      38             : #include "ivas_cnst.h"
      39             : #ifdef DEBUGGING
      40             : #include "debug.h"
      41             : #endif
      42             : #include <math.h>
      43             : #include <assert.h>
      44             : #include "wmc_auto.h"
      45             : 
      46             : 
      47             : /*------------------------------------------------------------------------------------------*
      48             :  * Local constants
      49             :  *------------------------------------------------------------------------------------------*/
      50             : 
      51             : #define OTR_UPDATE_RATE      (float) FRAMES_PER_SEC /* rate of the Process() calls [Hz]; 1x per IVAS frame */
      52             : #define COS_ONE_TENTH_DEGREE ( 0.999998476913288f )
      53             : 
      54             : /*------------------------------------------------------------------------------------------*
      55             :  * Local functions
      56             :  *------------------------------------------------------------------------------------------*/
      57             : 
      58             : /*------------------------------------------------------------------------------------------*
      59             :  * IdentityQuaternion()
      60             :  *
      61             :  *
      62             :  *------------------------------------------------------------------------------------------*/
      63             : 
      64           0 : static IVAS_QUATERNION IdentityQuaternion(
      65             :     void )
      66             : {
      67             :     IVAS_QUATERNION q;
      68             : 
      69           0 :     q.w = 1.0f;
      70           0 :     q.x = q.y = q.z = 0.0f;
      71             : 
      72           0 :     return q;
      73             : }
      74             : 
      75             : 
      76             : /*------------------------------------------------------------------------------------------*
      77             :  * QuaternionProduct()
      78             :  *
      79             :  * Quaternion product
      80             :  *------------------------------------------------------------------------------------------*/
      81             : 
      82      576679 : void QuaternionProduct(
      83             :     const IVAS_QUATERNION q1,
      84             :     const IVAS_QUATERNION q2,
      85             :     IVAS_QUATERNION *const r )
      86             : {
      87             :     IVAS_QUATERNION tmp;
      88      576679 :     tmp.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
      89      576679 :     tmp.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
      90      576679 :     tmp.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
      91      576679 :     tmp.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
      92             : 
      93      576679 :     *r = tmp;
      94             : 
      95      576679 :     return;
      96             : }
      97             : 
      98             : /*------------------------------------------------------------------------------------------*
      99             :  * QuaternionDotProduct()
     100             :  *
     101             :  * Quaternion dot product
     102             :  *------------------------------------------------------------------------------------------*/
     103             : 
     104     1709897 : static float QuaternionDotProduct(
     105             :     const IVAS_QUATERNION q1,
     106             :     const IVAS_QUATERNION q2 )
     107             : {
     108     1709897 :     return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
     109             : }
     110             : 
     111             : 
     112             : /*------------------------------------------------------------------------------------------*
     113             :  * QuaternionDivision()
     114             :  *
     115             :  * Divides a quaternion by a scalar
     116             :  *------------------------------------------------------------------------------------------*/
     117             : 
     118     1417658 : static void QuaternionDivision(
     119             :     const IVAS_QUATERNION q,
     120             :     const float d,
     121             :     IVAS_QUATERNION *const r )
     122             : {
     123     1417658 :     r->w = q.w / d;
     124     1417658 :     r->x = q.x / d;
     125     1417658 :     r->y = q.y / d;
     126     1417658 :     r->z = q.z / d;
     127             : 
     128     1417658 :     return;
     129             : }
     130             : 
     131             : 
     132             : /*------------------------------------------------------------------------------------------*
     133             :  * QuaternionNormalize()
     134             :  *
     135             :  * Normalizes a quaternion
     136             :  *------------------------------------------------------------------------------------------*/
     137             : 
     138      888729 : static void QuaternionNormalize(
     139             :     const IVAS_QUATERNION q,
     140             :     IVAS_QUATERNION *const r )
     141             : {
     142      888729 :     QuaternionDivision( q, sqrtf( QuaternionDotProduct( q, q ) ), r );
     143             : 
     144      888729 :     return;
     145             : }
     146             : 
     147             : 
     148             : /*------------------------------------------------------------------------------------------*
     149             :  * QuaternionSlerp()
     150             :  *
     151             :  * Computes a spherical linear interpolation between two quaternions
     152             :  *------------------------------------------------------------------------------------------*/
     153             : 
     154      292239 : void QuaternionSlerp(
     155             :     const IVAS_QUATERNION q1,
     156             :     const IVAS_QUATERNION q2,
     157             :     const float t,
     158             :     IVAS_QUATERNION *const r )
     159             : {
     160             :     IVAS_QUATERNION r1, r2;
     161             :     float phi, sinPhi, cosPhi, s1, s2;
     162             : 
     163      292239 :     QuaternionNormalize( q1, &r1 );
     164      292239 :     QuaternionNormalize( q2, &r2 );
     165             : 
     166      292239 :     cosPhi = QuaternionDotProduct( r1, r2 );
     167             : 
     168      292239 :     if ( cosPhi < 0 )
     169             :     {
     170       21429 :         cosPhi = -cosPhi;
     171       21429 :         r2.w = -r2.w;
     172       21429 :         r2.x = -r2.x;
     173       21429 :         r2.y = -r2.y;
     174       21429 :         r2.z = -r2.z;
     175             :     }
     176             : 
     177             :     /* Angle less than one degree, use linear interpolation */
     178      292239 :     if ( cosPhi >= COS_ONE_TENTH_DEGREE )
     179             :     {
     180      142587 :         r->w = r1.w + t * ( r2.w - r1.w );
     181      142587 :         r->x = r1.x + t * ( r2.x - r1.x );
     182      142587 :         r->y = r1.y + t * ( r2.y - r1.y );
     183      142587 :         r->z = r1.z + t * ( r2.z - r1.z );
     184             :     }
     185             :     else
     186             :     {
     187      149652 :         phi = acosf( cosPhi );
     188      149652 :         sinPhi = sinf( phi );
     189             : 
     190      149652 :         s1 = sinf( ( 1 - t ) * phi );
     191      149652 :         s2 = sinf( t * phi );
     192             : 
     193      149652 :         r->w = ( s1 * r1.w + s2 * r2.w ) / sinPhi;
     194      149652 :         r->x = ( s1 * r1.x + s2 * r2.x ) / sinPhi;
     195      149652 :         r->y = ( s1 * r1.y + s2 * r2.y ) / sinPhi;
     196      149652 :         r->z = ( s1 * r1.z + s2 * r2.z ) / sinPhi;
     197             :     }
     198      292239 :     QuaternionNormalize( *r, r );
     199             : 
     200      292239 :     return;
     201             : }
     202             : 
     203             : 
     204             : /*------------------------------------------------------------------------------------------*
     205             :  * QuaternionConjugate()
     206             :  *
     207             :  * Computes a quaternion conjugate
     208             :  *------------------------------------------------------------------------------------------*/
     209             : 
     210      659213 : static void QuaternionConjugate(
     211             :     const IVAS_QUATERNION q,
     212             :     IVAS_QUATERNION *const r )
     213             : {
     214      659213 :     r->w = q.w;
     215      659213 :     r->x = -q.x;
     216      659213 :     r->y = -q.y;
     217      659213 :     r->z = -q.z;
     218             : 
     219      659213 :     return;
     220             : }
     221             : 
     222             : 
     223             : /*------------------------------------------------------------------------------------------*
     224             :  * QuaternionAngle()
     225             :  *
     226             :  * Computes an angle between two quaternions
     227             :  *------------------------------------------------------------------------------------------*/
     228             : 
     229      130284 : static float QuaternionAngle(
     230             :     const IVAS_QUATERNION q1,
     231             :     const IVAS_QUATERNION q2 )
     232             : {
     233             :     IVAS_QUATERNION q12;
     234             :     float angle;
     235             : 
     236      130284 :     QuaternionConjugate( q1, &q12 );
     237      130284 :     QuaternionProduct( q12, q2, &q12 );
     238      130284 :     angle = 2.0f * atan2f( sqrtf( q12.x * q12.x + q12.y * q12.y + q12.z * q12.z ), q12.w );
     239             : 
     240      130284 :     return angle;
     241             : }
     242             : 
     243             : 
     244             : /*------------------------------------------------------------------------------------------*
     245             :  * QuaternionInverse()
     246             :  *
     247             :  * Computes an inverse quaternion
     248             :  *------------------------------------------------------------------------------------------*/
     249             : 
     250      528929 : void QuaternionInverse(
     251             :     const IVAS_QUATERNION q,
     252             :     IVAS_QUATERNION *const r )
     253             : {
     254             :     float dot_product;
     255             : 
     256      528929 :     dot_product = QuaternionDotProduct( q, q );
     257      528929 :     QuaternionConjugate( q, r );
     258      528929 :     QuaternionDivision( *r, dot_product, r );
     259             : 
     260      528929 :     return;
     261             : }
     262             : 
     263             : 
     264             : /*------------------------------------------------------------------------------------------*
     265             :  * VectorSubtract()
     266             :  *
     267             :  * Computes the difference of two vectors
     268             :  *------------------------------------------------------------------------------------------*/
     269             : 
     270       12012 : static IVAS_VECTOR3 VectorSubtract(
     271             :     const IVAS_VECTOR3 p1,
     272             :     const IVAS_VECTOR3 p2 )
     273             : {
     274             :     IVAS_VECTOR3 result;
     275             : 
     276       12012 :     result.x = p1.x - p2.x;
     277       12012 :     result.y = p1.y - p2.y;
     278       12012 :     result.z = p1.z - p2.z;
     279             : 
     280       12012 :     return result;
     281             : }
     282             : 
     283             : 
     284             : /*------------------------------------------------------------------------------------------*
     285             :  * VectorCrossProduct()
     286             :  *
     287             :  * Computes the cross product of two vectors
     288             :  *------------------------------------------------------------------------------------------*/
     289             : 
     290       12012 : static IVAS_VECTOR3 VectorCrossProduct(
     291             :     const IVAS_VECTOR3 p1,
     292             :     const IVAS_VECTOR3 p2 )
     293             : {
     294             :     IVAS_VECTOR3 result;
     295       12012 :     result.x = p1.y * p2.z - p1.z * p2.y;
     296       12012 :     result.y = p1.z * p2.x - p1.x * p2.z;
     297       12012 :     result.z = p1.x * p2.y - p1.y * p2.x;
     298             : 
     299       12012 :     return result;
     300             : }
     301             : 
     302             : 
     303             : /*------------------------------------------------------------------------------------------*
     304             :  * VectorDotProduct(
     305             :  *
     306             :  * Computes the dot product of two vectors
     307             :  *------------------------------------------------------------------------------------------*/
     308             : 
     309       12012 : static float VectorDotProduct(
     310             :     const IVAS_VECTOR3 p1,
     311             :     const IVAS_VECTOR3 p2 )
     312             : {
     313       12012 :     return p1.x * p2.x + p1.y * p2.y + p1.z * p2.z;
     314             : }
     315             : 
     316             : 
     317             : /*------------------------------------------------------------------------------------------*
     318             :  * VectorLength()
     319             :  *
     320             :  * Computes the length of a vector
     321             :  *------------------------------------------------------------------------------------------*/
     322             : 
     323       36036 : static float VectorLength(
     324             :     const IVAS_VECTOR3 p )
     325             : {
     326       36036 :     return sqrtf( p.x * p.x + p.y * p.y + p.z * p.z );
     327             : }
     328             : 
     329             : 
     330             : /*------------------------------------------------------------------------------------------*
     331             :  * VectorNormalize()
     332             :  *
     333             :  * Normalizes a vector
     334             :  *------------------------------------------------------------------------------------------*/
     335             : 
     336       24024 : static IVAS_VECTOR3 VectorNormalize(
     337             :     const IVAS_VECTOR3 p )
     338             : {
     339             :     IVAS_VECTOR3 result;
     340             : 
     341       24024 :     const float length = VectorLength( p );
     342             : 
     343       24024 :     result.x = p.x / length;
     344       24024 :     result.y = p.y / length;
     345       24024 :     result.z = p.z / length;
     346             : 
     347       24024 :     return result;
     348             : }
     349             : 
     350             : 
     351             : /*------------------------------------------------------------------------------------------*
     352             :  * VectorRotationToQuaternion()
     353             :  *
     354             :  * Computes a quaternion representing the rotation from vector p1 to vector p2
     355             :  *------------------------------------------------------------------------------------------*/
     356             : 
     357       12012 : static void VectorRotationToQuaternion(
     358             :     const IVAS_VECTOR3 p1,
     359             :     const IVAS_VECTOR3 p2,
     360             :     IVAS_QUATERNION *const r )
     361             : {
     362             :     float dot_product;
     363             :     IVAS_VECTOR3 cross_product, p1_normalized, p2_normalized;
     364             : 
     365       12012 :     p1_normalized = VectorNormalize( p1 );
     366       12012 :     p2_normalized = VectorNormalize( p2 );
     367       12012 :     cross_product = VectorCrossProduct( p1_normalized, p2_normalized );
     368       12012 :     dot_product = VectorDotProduct( p1_normalized, p2_normalized );
     369             : 
     370       12012 :     if ( dot_product < -0.999999 )
     371             :     {
     372             :         /* happens when the p1 vector is parallel to p2, but direction is flipped */
     373          60 :         r->w = 0.0f;
     374          60 :         r->x = 0.0f;
     375          60 :         r->y = 0.0f;
     376          60 :         r->z = 1.0f;
     377             :     }
     378             :     else
     379             :     {
     380             :         /* all regular cases */
     381       11952 :         r->x = cross_product.x;
     382       11952 :         r->y = cross_product.y;
     383       11952 :         r->z = cross_product.z;
     384       11952 :         r->w = 1.0f + dot_product;
     385             :     }
     386             : 
     387       12012 :     QuaternionNormalize( *r, r );
     388             : 
     389       12012 :     return;
     390             : }
     391             : 
     392             : /*-------------------------------------------------------------------*
     393             :  * ivas_orient_trk_Init()
     394             :  *
     395             :  *
     396             :  *-------------------------------------------------------------------*/
     397             : 
     398         437 : ivas_error ivas_orient_trk_Init(
     399             :     ivas_orient_trk_state_t *pOTR ) /* i/o  : orientation tracker handle    */
     400             : {
     401             :     IVAS_QUATERNION identity;
     402             : 
     403         437 :     if ( pOTR == NULL )
     404             :     {
     405           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     406             :     }
     407             : 
     408         437 :     identity.w = 1.0f;
     409         437 :     identity.x = identity.y = identity.z = 0.0f;
     410             : 
     411             :     /* configuration parameters */
     412         437 :     pOTR->centerAdaptationRate = 1.0f / 30.0f;
     413         437 :     pOTR->offCenterAdaptationRate = 1.0f / 8.0f;
     414         437 :     pOTR->adaptationAngle = PI_OVER_2; /* Excursion angle relative to center at which maximum adaptation rate shall be applied */
     415             : 
     416             :     /* initial adaptivity filter coefficient, will be auto-adapted */
     417         437 :     pOTR->alpha = sinf( PI2 * pOTR->offCenterAdaptationRate / OTR_UPDATE_RATE ); /* start adaptation at off-center rate = fastest rate */
     418             : 
     419         437 :     pOTR->trkRot = identity;
     420         437 :     pOTR->absAvgRot = identity;
     421             :     /* Use frontal and horiontal orientation as reference orientation, unless/until overridden  */
     422         437 :     pOTR->refRot = identity;
     423             : 
     424             :     /* set safe default tracking mode */
     425         437 :     pOTR->orientation_tracking = IVAS_HEAD_ORIENT_TRK_NONE;
     426             : 
     427         437 :     return IVAS_ERR_OK;
     428             : }
     429             : 
     430             : 
     431             : /*-------------------------------------------------------------------*
     432             :  * ivas_orient_trk_SetTrackingType()
     433             :  *
     434             :  *
     435             :  *-------------------------------------------------------------------*/
     436             : 
     437         437 : ivas_error ivas_orient_trk_SetTrackingType(
     438             :     ivas_orient_trk_state_t *pOTR,                    /* i/o: orientation tracker handle    */
     439             :     const IVAS_HEAD_ORIENT_TRK_T orientation_tracking /* i  : orientation tracking type     */
     440             : )
     441             : {
     442         437 :     if ( pOTR == NULL )
     443             :     {
     444           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     445             :     }
     446             : 
     447         437 :     pOTR->orientation_tracking = orientation_tracking;
     448             : 
     449         437 :     return IVAS_ERR_OK;
     450             : }
     451             : 
     452             : /*-------------------------------------------------------------------*
     453             :  * ivas_orient_trk_SetReferenceRotation()
     454             :  *
     455             :  *
     456             :  *-------------------------------------------------------------------*/
     457             : 
     458           0 : ivas_error ivas_orient_trk_SetReferenceRotation(
     459             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle     */
     460             :     const IVAS_QUATERNION refRot   /* i  : reference rotation             */
     461             : )
     462             : {
     463           0 :     if ( pOTR == NULL )
     464             :     {
     465           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     466             :     }
     467             : 
     468             :     /* check for Euler angle signaling */
     469           0 :     if ( refRot.w == -3.0f )
     470             :     {
     471           0 :         Euler2Quat( deg2rad( refRot.x ), deg2rad( refRot.y ), deg2rad( refRot.z ), &pOTR->refRot );
     472             :     }
     473             :     else
     474             :     {
     475           0 :         pOTR->refRot = refRot;
     476             :     }
     477             : 
     478           0 :     return IVAS_ERR_OK;
     479             : }
     480             : 
     481             : 
     482             : /*-------------------------------------------------------------------*
     483             :  * ivas_orient_trk_GetMainOrientation()
     484             :  *
     485             :  *
     486             :  *-------------------------------------------------------------------*/
     487             : 
     488           0 : ivas_error ivas_orient_trk_GetMainOrientation(
     489             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle     */
     490             :     IVAS_QUATERNION *pOrientation  /* i/o: average/reference orientation  */
     491             : )
     492             : {
     493           0 :     if ( pOTR == NULL || pOrientation == NULL )
     494             :     {
     495           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     496             :     }
     497             : 
     498           0 :     switch ( pOTR->orientation_tracking )
     499             :     {
     500           0 :         case IVAS_HEAD_ORIENT_TRK_NONE:
     501           0 :             *pOrientation = IdentityQuaternion();
     502           0 :             break;
     503           0 :         case IVAS_HEAD_ORIENT_TRK_REF_VEC:
     504             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC_LEV:
     505             :         case IVAS_HEAD_ORIENT_TRK_REF:
     506           0 :             *pOrientation = pOTR->refRot;
     507           0 :             break;
     508           0 :         case IVAS_HEAD_ORIENT_TRK_AVG:
     509           0 :             *pOrientation = pOTR->absAvgRot;
     510           0 :             break;
     511             :     }
     512             : 
     513           0 :     return IVAS_ERR_OK;
     514             : }
     515             : 
     516             : 
     517             : /*-------------------------------------------------------------------*
     518             :  * ivas_orient_trk_GetTrackedRotation()
     519             :  *
     520             :  *
     521             :  *-------------------------------------------------------------------*/
     522             : 
     523           0 : ivas_error ivas_orient_trk_GetTrackedRotation(
     524             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle    */
     525             :     IVAS_QUATERNION *pRotation     /* i/o: processed rotation            */
     526             : )
     527             : {
     528           0 :     if ( pOTR == NULL || pRotation == NULL )
     529             :     {
     530           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     531             :     }
     532             : 
     533           0 :     *pRotation = pOTR->trkRot;
     534             : 
     535           0 :     return IVAS_ERR_OK;
     536             : }
     537             : 
     538             : 
     539             : /*-------------------------------------------------------------------*
     540             :  * ivas_orient_trk_SetReferenceVector()
     541             :  *
     542             :  *
     543             :  *-------------------------------------------------------------------*/
     544             : 
     545       12012 : ivas_error ivas_orient_trk_SetReferenceVector(
     546             :     ivas_orient_trk_state_t *pOTR,  /* i/o: orientation tracker handle  */
     547             :     const IVAS_VECTOR3 listenerPos, /* i  : Listener position           */
     548             :     const IVAS_VECTOR3 refPos       /* i  : Reference position          */
     549             : )
     550             : {
     551             :     IVAS_VECTOR3 acousticFrontVector, ivasForwardVector;
     552             :     IVAS_VECTOR3 listenerPosLevel, refPosLevel;
     553             :     float acousticFrontVectorLength;
     554             : 
     555       12012 :     if ( pOTR == NULL )
     556             :     {
     557           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     558             :     }
     559             : 
     560       12012 :     switch ( pOTR->orientation_tracking )
     561             :     {
     562        6006 :         case IVAS_HEAD_ORIENT_TRK_NONE:
     563             :         case IVAS_HEAD_ORIENT_TRK_REF:
     564             :         case IVAS_HEAD_ORIENT_TRK_AVG:
     565             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC:
     566        6006 :             acousticFrontVector = VectorSubtract( refPos, listenerPos );
     567        6006 :             break;
     568        6006 :         case IVAS_HEAD_ORIENT_TRK_REF_VEC_LEV:
     569             :             /* ignore the height difference between listener position and reference position */
     570        6006 :             listenerPosLevel.z = refPosLevel.z = listenerPos.z;
     571        6006 :             listenerPosLevel.x = listenerPos.x;
     572        6006 :             listenerPosLevel.y = listenerPos.y;
     573        6006 :             refPosLevel.x = refPos.x;
     574        6006 :             refPosLevel.y = refPos.y;
     575        6006 :             acousticFrontVector = VectorSubtract( refPosLevel, listenerPosLevel );
     576        6006 :             break;
     577           0 :         default:
     578           0 :             return IVAS_ERR_WRONG_PARAMS;
     579             :     }
     580             : 
     581       12012 :     acousticFrontVectorLength = VectorLength( acousticFrontVector );
     582             : 
     583             :     /* if the length is zero, the user has entered insensible listener and reference positions */
     584       12012 :     if ( acousticFrontVectorLength < 0.0001f )
     585             :     {
     586           0 :         return IVAS_ERR_WRONG_PARAMS;
     587             :     }
     588             : 
     589       12012 :     ivasForwardVector.x = 1.0f;
     590       12012 :     ivasForwardVector.y = 0.0f;
     591       12012 :     ivasForwardVector.z = 0.0f;
     592       12012 :     VectorRotationToQuaternion( ivasForwardVector, acousticFrontVector, &pOTR->refRot );
     593             : 
     594       12012 :     return IVAS_ERR_OK;
     595             : }
     596             : 
     597             : 
     598             : /*-------------------------------------------------------------------*
     599             :  * ivas_orient_trk_Process()
     600             :  *
     601             :  *
     602             :  *-------------------------------------------------------------------*/
     603             : 
     604     1414569 : ivas_error ivas_orient_trk_Process(
     605             :     ivas_orient_trk_state_t *pOTR, /* i/o: orientation tracker handle    */
     606             :     IVAS_QUATERNION absRot,        /* i  : absolute head rotation        */
     607             :     float updateRate,              /* i  : rotation update rate [Hz]     */
     608             :     IVAS_QUATERNION *pTrkRot       /* o  : tracked rotation              */
     609             : )
     610             : {
     611             :     float normalizedOrientation;
     612             :     float relativeOrientationRate;
     613             :     float rateRange;
     614             :     float cutoffFrequency;
     615     1414569 :     float alpha = pOTR->alpha;
     616             :     float ang;
     617             :     ivas_error result;
     618             : 
     619     1414569 :     if ( pOTR == NULL || pTrkRot == NULL )
     620             :     {
     621           0 :         return IVAS_ERR_UNEXPECTED_NULL_POINTER;
     622             :     }
     623             : 
     624     1414569 :     result = IVAS_ERR_OK;
     625             : 
     626     1414569 :     switch ( pOTR->orientation_tracking )
     627             :     {
     628     1236257 :         case IVAS_HEAD_ORIENT_TRK_NONE:
     629     1236257 :             pOTR->trkRot = absRot;
     630     1236257 :             break;
     631       48028 :         case IVAS_HEAD_ORIENT_TRK_REF:
     632             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC:
     633             :         case IVAS_HEAD_ORIENT_TRK_REF_VEC_LEV:
     634             :             /* Reset average orientation   */
     635       48028 :             pOTR->absAvgRot = absRot;
     636             : 
     637             :             /* Reset adaptation filter - start adaptation at center rate */
     638       48028 :             pOTR->alpha = sinf( 2.0f * EVS_PI * pOTR->centerAdaptationRate / updateRate );
     639             : 
     640             :             /* Compute relative orientation = (absolute orientation) - (reference orientation) */
     641       48028 :             QuaternionInverse( pOTR->refRot, &pOTR->trkRot );
     642       48028 :             QuaternionProduct( pOTR->trkRot, absRot, &pOTR->trkRot );
     643       48028 :             break;
     644             : 
     645      130284 :         case IVAS_HEAD_ORIENT_TRK_AVG:
     646             :             /* Compute average (low-pass filtered) absolute orientation */
     647      130284 :             QuaternionSlerp( pOTR->absAvgRot, absRot, alpha, &pOTR->absAvgRot );
     648             : 
     649             :             /* Compute relative orientation = (absolute orientation) - (average absolute orientation) */
     650      130284 :             QuaternionInverse( pOTR->absAvgRot, &pOTR->trkRot );
     651      130284 :             QuaternionProduct( pOTR->trkRot, absRot, &pOTR->trkRot );
     652             : 
     653             :             /* Adapt LPF constant based on orientation excursion relative to current mean:
     654             :             - low  cutoff (slow adaptation) for small excursions (around center)
     655             :             - high cutoff (fast adaptation) for large excursions (off-center)
     656             :             */
     657      130284 :             ang = QuaternionAngle( absRot, pOTR->trkRot );
     658      130284 :             normalizedOrientation = ang * ang;
     659             : 
     660      130284 :             relativeOrientationRate = sqrtf( normalizedOrientation ) / pOTR->adaptationAngle;
     661             :             /* 'if'  assumed to perform comparison to 0 */
     662      130284 :             if ( relativeOrientationRate > 1.0f )
     663             :             {
     664           0 :                 relativeOrientationRate = 1.0f;
     665             :             }
     666             : 
     667             :             /* Compute range of the adaptation rate between center = lower rate and off-center = higher rate */
     668      130284 :             rateRange = pOTR->offCenterAdaptationRate - pOTR->centerAdaptationRate;
     669             :             /* 'if' assumed to perform comparison to 0 */
     670      130284 :             if ( rateRange < 0.0f )
     671             :             {
     672           0 :                 rateRange = 0.0f;
     673             :             }
     674             : 
     675             :             /* Compute adaptivity cutoff frequency: interpolate between minimum (center) and maximum (off-center) values */
     676      130284 :             cutoffFrequency = pOTR->centerAdaptationRate + ( relativeOrientationRate * rateRange );
     677             : 
     678             :             /* Compute filter coefficient corresponding to desired cutoff frequency */
     679      130284 :             pOTR->alpha = sinf( 2.0f * EVS_PI * cutoffFrequency / updateRate );
     680      130284 :             break;
     681           0 :         default:
     682           0 :             result = IVAS_ERROR( IVAS_ERR_INTERNAL_FATAL, "Non-supported orientation tracking adaptation type" );
     683           0 :             break;
     684             :     }
     685             : 
     686     1414569 :     if ( result == IVAS_ERR_OK )
     687             :     {
     688     1414569 :         *pTrkRot = pOTR->trkRot;
     689             :     }
     690             : 
     691     1414569 :     return result;
     692             : }

Generated by: LCOV version 1.14