LCOV - code coverage report
Current view: top level - lib_rend - ivas_shoebox.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 143 162 88.3 %
Date: 2025-05-23 08:37:30 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************************************
       2             : 
       3             :    (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
       4             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
       5             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
       6             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
       7             :    contributors to this repository. All Rights Reserved.
       8             : 
       9             :    This software is protected by copyright law and by international treaties.
      10             :    The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
      11             :    Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
      12             :    Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
      13             :    Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
      14             :    contributors to this repository retain full ownership rights in their respective contributions in
      15             :    the software. This notice grants no license of any kind, including but not limited to patent
      16             :    license, nor is any license granted by implication, estoppel or otherwise.
      17             : 
      18             :    Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
      19             :    contributions.
      20             : 
      21             :    This software is provided "AS IS", without any express or implied warranties. The software is in the
      22             :    development stage. It is intended exclusively for experts who have experience with such software and
      23             :    solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
      24             :    and fitness for a particular purpose are hereby disclaimed and excluded.
      25             : 
      26             :    Any dispute, controversy or claim arising under or in relation to providing this software shall be
      27             :    submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
      28             :    accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
      29             :    the United Nations Convention on Contracts on the International Sales of Goods.
      30             : 
      31             : *******************************************************************************************************/
      32             : 
      33             : #include "options.h"
      34             : #include <stdint.h>
      35             : #include <math.h>
      36             : #include "ivas_prot.h"
      37             : #include "ivas_prot_rend.h"
      38             : #include "ivas_stat_rend.h"
      39             : #include "ivas_cnst.h"
      40             : #include "prot.h"
      41             : #include "wmc_auto.h"
      42             : 
      43             : 
      44             : /*-------------------------------------------------------------------------
      45             :  * Local constants
      46             :  *------------------------------------------------------------------------*/
      47             : 
      48             : #define ER_MAX_SOURCES     25
      49             : #define ER_REF_ORDER       1
      50             : #define ER_AIR_COEFF       ( 0.00137f )
      51             : #define ER_SOUND_SPEED     ( 343.0f )
      52             : #define ER_MIN_WALL_DIST   ( 0.1f )
      53             : #define ER_EUCLIDEAN_SCALE ( 1.29246971E-26f )
      54             : 
      55             : 
      56             : /*-----------------------------------------------------------------------------------------*
      57             :  * Function ivas_shoebox_config_init
      58             :  *
      59             :  * Function transfer the parameters from the reverb config handle to the shoebox
      60             :  * calibration data structure.
      61             :  *-----------------------------------------------------------------------------------------*/
      62             : 
      63          12 : void ivas_shoebox_config_init(
      64             :     shoebox_config_t *cal,
      65             :     RENDER_CONFIG_HANDLE hRenderConfig /* i  : Renderer configuration handle     */
      66             : )
      67             : {
      68             :     int16_t wall_idx;
      69             : 
      70          12 :     cal->room_L = hRenderConfig->roomAcoustics.dimensions.x;
      71          12 :     cal->room_W = hRenderConfig->roomAcoustics.dimensions.y;
      72          12 :     cal->room_H = hRenderConfig->roomAcoustics.dimensions.z;
      73             : 
      74             :     /*  Absorption Coefficients */
      75             :     /*  Convention: [Front wall, Back wall, Left wall, Right wall, Ceiling, Floor] */
      76          84 :     for ( wall_idx = 0; wall_idx < 6; wall_idx++ )
      77             :     {
      78          72 :         cal->abs_coeff[wall_idx] = hRenderConfig->roomAcoustics.AbsCoeff[wall_idx];
      79             :     }
      80             : 
      81             :     /* Listener position (only X and Y can be pos. or neg. ) */
      82          12 :     cal->list_orig[0] = hRenderConfig->roomAcoustics.ListenerOrigin.x;
      83          12 :     cal->list_orig[1] = hRenderConfig->roomAcoustics.ListenerOrigin.y;
      84          12 :     cal->list_orig[2] = hRenderConfig->roomAcoustics.ListenerOrigin.z;
      85             : 
      86          12 :     return;
      87             : }
      88             : 
      89             : 
      90             : /*-----------------------------------------------------------------------------------------*
      91             :  * Function ivas_shoebox_init()
      92             :  *
      93             :  * Function initializes the shoebox operating parameters by setting limits and defaults,
      94             :  * also contains the calibration structure.
      95             :  *-----------------------------------------------------------------------------------------*/
      96             : 
      97          12 : void ivas_shoebox_init(
      98             :     shoebox_obj_t *obj,
      99             :     shoebox_config_t *cal )
     100             : {
     101             :     uint16_t i;
     102             : 
     103             :     /* Add cal to obj struct */
     104          12 :     obj->cal = *cal;
     105             :     /* Add defaults */
     106          12 :     obj->max_bands = 1;
     107          12 :     obj->MAX_SOURCES = ER_MAX_SOURCES;
     108          12 :     obj->REF_ORDER = ER_REF_ORDER;
     109             : 
     110             :     /*  Positions */
     111          12 :     set_f( &obj->src_pos[0], 0.0f, 75U );
     112          12 :     set_f( &obj->src_dist[0], 0.0f, 25U );
     113             : 
     114          48 :     for ( i = 0; i < 3; i++ )
     115             :     {
     116          36 :         obj->list_pos[i] = cal->list_orig[i];
     117             :     }
     118             : 
     119             :     /*  Pointer */
     120          12 :     obj->nSrc = 0;
     121             : 
     122             :     /*  Flags */
     123          12 :     obj->isCartesian = 1;
     124          12 :     obj->isRelative = 1;
     125          12 :     obj->isZHeight = 1;
     126          12 :     obj->isRadians = 1;
     127             : 
     128             :     /*  Params */
     129          12 :     obj->radius = ER_RADIUS;
     130          12 :     obj->min_wall_dist = ER_MIN_WALL_DIST;
     131          12 :     obj->soundspeed = ER_SOUND_SPEED;
     132          12 :     obj->air_coeff = ER_AIR_COEFF;
     133             : 
     134          12 :     return;
     135             : }
     136             : 
     137             : 
     138             : /*-----------------------------------------------------------------------------------------*
     139             :  * Function shoebox_bound()
     140             :  *
     141             :  *  SHOEBOX_BOUND takes in CARTESIAN coordinates of either a receiver or
     142             :  *  source and checks if it is within the virtual room boundaries established
     143             :  *  by the surface parameters. If object is out of bounds, then new cartesian
     144             :  *  coordinates are established to collapse the object position.
     145             :  *-----------------------------------------------------------------------------------------*/
     146             : 
     147         126 : static void shoebox_bound(
     148             :     shoebox_obj_t *obj,
     149             :     float *out_pos )
     150             : {
     151             :     float out_tmp;
     152             :     int32_t i;
     153             : 
     154         126 :     out_tmp = ( obj->cal.room_L / 2.0f ) - obj->min_wall_dist;
     155             : 
     156         126 :     if ( ( out_pos[0] > out_tmp ) || ( out_pos[0] < ( ( ( -obj->cal.room_L ) / 2.0f ) + obj->min_wall_dist ) ) )
     157             :     {
     158           3 :         if ( out_pos[0] < 0.0f )
     159             :         {
     160           0 :             i = -1;
     161             :         }
     162             :         else
     163             :         {
     164           3 :             i = ( out_pos[0] > 0.0f ) ? ( (int32_t) 1 ) : ( (int32_t) 0 );
     165             :         }
     166           3 :         out_pos[0] = out_tmp * ( (float) i );
     167             :     }
     168             : 
     169         126 :     out_tmp = ( obj->cal.room_W / 2.0f ) - obj->min_wall_dist;
     170             : 
     171         126 :     if ( ( out_pos[1] > out_tmp ) || ( out_pos[1] < ( ( ( -obj->cal.room_W ) / 2.0f ) + obj->min_wall_dist ) ) )
     172             :     {
     173           3 :         if ( out_pos[1] < 0.0f )
     174             :         {
     175           3 :             i = -1;
     176             :         }
     177             :         else
     178             :         {
     179           0 :             i = ( out_pos[1] > 0.0f ) ? ( (int32_t) 1 ) : ( (int32_t) 0 );
     180             :         }
     181           3 :         out_pos[1] = out_tmp * ( (float) i );
     182             :     }
     183             : 
     184         126 :     out_tmp = ( obj->cal.room_H / 2.0f ) - obj->min_wall_dist;
     185             : 
     186         126 :     if ( ( out_pos[2] > out_tmp ) || ( out_pos[2] < ( ( ( -obj->cal.room_H ) / 2.0f ) + obj->min_wall_dist ) ) )
     187             :     {
     188           0 :         if ( out_pos[2] < 0.0f )
     189             :         {
     190           0 :             i = -1;
     191             :         }
     192             :         else
     193             :         {
     194           0 :             i = ( out_pos[2] > 0.0f ) ? ( (int32_t) 1 ) : ( (int32_t) 0 );
     195             :         }
     196           0 :         out_pos[2] = out_tmp * ( (float) i );
     197             :     }
     198             : 
     199         126 :     return;
     200             : }
     201             : 
     202             : 
     203             : /*-----------------------------------------------------------------------------------------*
     204             :  * Function shoebox_get_coord()
     205             :  *
     206             :  * Transform relative spherical coordinate to 3D cartesian point
     207             :  *-----------------------------------------------------------------------------------------*/
     208             : 
     209         114 : static void shoebox_get_coord(
     210             :     shoebox_obj_t *obj,
     211             :     float *fcnOutput_data,
     212             :     const float src_pos_data[],
     213             :     float *tmp_pos,
     214             :     float out_tmp,
     215             :     int32_t coord,
     216             :     int32_t loop_ub,
     217             :     int32_t k,
     218             :     uint16_t isRelative )
     219             : {
     220             :     float tmp_data[75];
     221             :     float rcoselev;
     222             :     int32_t tmp_size_idx_1;
     223             :     int32_t n;
     224             : 
     225         114 :     tmp_size_idx_1 = 3;
     226         114 :     if ( obj->isCartesian == 0 )
     227             :     {
     228             :         /*   Convert Spherical to Cartesian  */
     229         114 :         if ( obj->isRadians == 0 )
     230             :         {
     231           0 :             for ( n = 0; n < loop_ub; n++ )
     232             :             {
     233           0 :                 fcnOutput_data[n] = deg2rad( src_pos_data[k + n] );
     234             :             }
     235             :         }
     236         114 :         tmp_data[2] = fcnOutput_data[2] * sinf( fcnOutput_data[1] );
     237         114 :         rcoselev = fcnOutput_data[2] * cosf( fcnOutput_data[1] );
     238         114 :         tmp_data[0] = rcoselev * cosf( fcnOutput_data[0] );
     239         114 :         tmp_data[1] = rcoselev * sinf( fcnOutput_data[0] );
     240             :     }
     241             :     else
     242             :     {
     243             :         /*   CARTESIAN CASE */
     244           0 :         tmp_size_idx_1 = loop_ub;
     245           0 :         for ( n = 0; n < loop_ub; n++ )
     246             :         {
     247           0 :             tmp_data[n] = src_pos_data[k + n];
     248             :         }
     249           0 :         if ( obj->isZHeight != 0.0f )
     250             :         {
     251             :             /*  FIX Z COORDINATE */
     252           0 :             tmp_data[2] = src_pos_data[k + 2] - ( obj->cal.room_H / 2.0f );
     253             :         }
     254             :     }
     255             : 
     256         456 :     for ( k = 0; k < tmp_size_idx_1; k++ )
     257             :     {
     258         342 :         obj->src_pos[( coord + k ) - 1] = tmp_data[k];
     259             :     }
     260             : 
     261             :     /*   CENTER TO LISTENER */
     262         114 :     if ( ( out_tmp + 1.0f ) > ( ( out_tmp + 1.0f ) + 2.0f ) )
     263             :     {
     264           0 :         k = 1;
     265             :     }
     266             :     else
     267             :     {
     268         114 :         k = (int32_t) ( (float) ( out_tmp + 1.0f ) );
     269             :     }
     270             : 
     271         114 :     tmp_pos[0] = obj->src_pos[k - 1];
     272         114 :     tmp_pos[1] = obj->src_pos[k];
     273         114 :     tmp_pos[2] = obj->src_pos[k + 1];
     274             : 
     275         114 :     if ( isRelative != 0.0f )
     276             :     {
     277         114 :         tmp_pos[0] += obj->list_pos[0];
     278         114 :         tmp_pos[1] += obj->list_pos[1];
     279         114 :         tmp_pos[2] += obj->list_pos[2];
     280             :     }
     281             : 
     282         114 :     return;
     283             : }
     284             : 
     285             : 
     286             : /*-----------------------------------------------------------------------------------------*
     287             :  * Function shoebox_get_euclidian_distance_internal()
     288             :  *
     289             :  * Get 3D source distance from receiver
     290             :  *-----------------------------------------------------------------------------------------*/
     291             : 
     292         798 : static float shoebox_get_euclidian_distance_internal(
     293             :     shoebox_obj_t *obj,
     294             :     float *tmp_pos,
     295             :     float *scale )
     296             : {
     297             :     float absxk, out_tmp, t;
     298             : 
     299         798 :     absxk = fabsf( obj->list_pos[0] - tmp_pos[0] );
     300             : 
     301         798 :     if ( absxk > ER_EUCLIDEAN_SCALE )
     302             :     {
     303         768 :         out_tmp = 1.0f;
     304         768 :         *scale = absxk;
     305             :     }
     306             :     else
     307             :     {
     308          30 :         t = absxk / ER_EUCLIDEAN_SCALE;
     309          30 :         out_tmp = t * t;
     310             :     }
     311             : 
     312         798 :     absxk = fabsf( obj->list_pos[1] - tmp_pos[1] );
     313             : 
     314         798 :     if ( absxk > *scale )
     315             :     {
     316         318 :         t = *scale / absxk;
     317         318 :         out_tmp = ( ( out_tmp * t ) * t ) + 1.0f;
     318         318 :         *scale = absxk;
     319             :     }
     320             :     else
     321             :     {
     322         480 :         t = absxk / *scale;
     323         480 :         out_tmp += t * t;
     324             :     }
     325             : 
     326         798 :     absxk = fabsf( obj->list_pos[2] - tmp_pos[2] );
     327             : 
     328         798 :     if ( absxk > *scale )
     329             :     {
     330         228 :         t = *scale / absxk;
     331         228 :         out_tmp = ( ( out_tmp * t ) * t ) + 1.0f;
     332         228 :         *scale = absxk;
     333             :     }
     334             :     else
     335             :     {
     336         570 :         t = absxk / *scale;
     337         570 :         out_tmp += t * t;
     338             :     }
     339             : 
     340         798 :     return out_tmp;
     341             : }
     342             : 
     343             : 
     344             : /*-----------------------------------------------------------------------------------------*
     345             :  * Function ivas_shoebox_set_scene()
     346             :  *
     347             :  * Initial scene setup returning computed reflection (arrival times, DOA and gain).
     348             :  *-----------------------------------------------------------------------------------------*/
     349             : 
     350          12 : void ivas_shoebox_set_scene(
     351             :     shoebox_obj_t *obj,
     352             :     shoebox_output_t *ER_PARAMS,
     353             :     const float list_pos[3],
     354             :     const float src_pos_data[],
     355             :     const uint16_t isCartesian,
     356             :     const uint16_t isRelative )
     357             : {
     358             :     float tmp_pos[3];
     359             :     float out_tmp;
     360             :     int32_t i, j, k, n;
     361             :     int32_t loop_ub;
     362             :     /*  ------------- SET FLAGS ------------- */
     363          12 :     obj->isCartesian = isCartesian;
     364          12 :     obj->isRelative = isRelative;
     365             :     /*  ------------- CHECK DIMENSIONS ------------- */
     366          12 :     if ( ER_PARAMS->n_sources > obj->MAX_SOURCES )
     367             :     {
     368           0 :         obj->nSrc = obj->MAX_SOURCES;
     369             :     }
     370             :     else
     371             :     {
     372          12 :         obj->nSrc = ER_PARAMS->n_sources;
     373             :     }
     374             :     /*  ---------- RESET DATA HOLDERS ---------- */
     375          12 :     set_f( &obj->src_pos[0], 0.0f, 75U );
     376          12 :     obj->list_pos[0] = list_pos[0];
     377          12 :     obj->list_pos[1] = list_pos[1];
     378          12 :     obj->list_pos[2] = list_pos[2];
     379             :     /*  ---------- ADJUST LISTENER ------------- */
     380          12 :     if ( obj->isZHeight != 0 )
     381             :     {
     382          12 :         obj->list_pos[2] = list_pos[2] - ( obj->cal.room_H / 2.0f );
     383             :     }
     384          12 :     tmp_pos[1] = obj->list_pos[1];
     385          12 :     tmp_pos[2] = obj->list_pos[2];
     386             : 
     387          12 :     shoebox_bound( obj, obj->list_pos );
     388             : 
     389             :     /*  ---------- SOURCE LOOP ------------- */
     390          12 :     i = (int32_t) obj->nSrc;
     391         126 :     for ( j = 0; j < i; j++ )
     392             :     {
     393             :         float fcnOutput_data[75];
     394             :         float rcoselev;
     395             :         float scale;
     396             :         int32_t coord;
     397             :         /* idx = single(i); */
     398         114 :         out_tmp = 3.0f * ( ( ( (float) j ) + 1.0f ) - 1.0f );
     399             :         /*   GET COORDINATE IN CARTESIAN ABSOLUTE FORMAT */
     400         114 :         if ( ( out_tmp + 1.0f ) > ( ( out_tmp + 1.0f ) + 2.0f ) )
     401             :         {
     402           0 :             k = 0;
     403           0 :             n = 0;
     404           0 :             coord = 1;
     405             :         }
     406             :         else
     407             :         {
     408         114 :             k = ( (int32_t) ( (float) ( out_tmp + 1.0f ) ) ) - 1;
     409         114 :             n = (int32_t) ( (float) ( ( out_tmp + 1.0f ) + 2.0f ) );
     410         114 :             coord = (int32_t) ( (float) ( out_tmp + 1.0f ) );
     411             :         }
     412         114 :         loop_ub = n - k;
     413         456 :         for ( n = 0; n < loop_ub; n++ )
     414             :         {
     415         342 :             fcnOutput_data[n] = src_pos_data[k + n];
     416             :         }
     417             : 
     418         114 :         shoebox_get_coord( obj, fcnOutput_data, src_pos_data, tmp_pos, out_tmp, coord, loop_ub, k, isRelative );
     419             : 
     420         114 :         shoebox_bound( obj, tmp_pos );
     421             : 
     422         114 :         scale = ER_EUCLIDEAN_SCALE;
     423             : 
     424         114 :         out_tmp = shoebox_get_euclidian_distance_internal( obj, tmp_pos, &scale );
     425             : 
     426         114 :         obj->src_dist[( (int32_t) ( (float) ( ( (float) j ) + 1.0f ) ) ) - 1] = scale * sqrtf( out_tmp );
     427             : 
     428             :         /*   COMPUTE PATTERNS */
     429             : 
     430             :         /*  SHOEBOX_COMPUTE: fills an input structure (4 array fields of length NxR ) with the */
     431             :         /*  Early reflection metadata (time of arrival, gain, az, el). */
     432             :         /*  */
     433             :         /*  Input: */
     434             :         /*  1. obj        : Module data holder */
     435             :         /*  2. ER_struct  : Early reflection structure */
     436             :         /*  3. src_num    : Index of source to compute patterns for */
     437             :         /*  ------ */
     438         114 :         out_tmp = obj->src_dist[( (int32_t) ( (float) ( ( (float) j ) + 1.0f ) ) ) - 1];
     439         798 :         for ( loop_ub = 0; loop_ub < 6; loop_ub++ )
     440             :         {
     441             :             float im_pos[3];
     442             :             float path_dist;
     443             :             /*  Retrieve coordinate and surface sign */
     444         684 :             coord = ( (int32_t) ceilf( ( ( (float) loop_ub ) + 1.0f ) / 2.0f ) ) - 1;
     445         684 :             rcoselev = ( ( (float) loop_ub ) + 1.0f ) + ( ER_PARAMS->n_ref * ( ( ( (float) j ) + 1.0f ) - 1.0f ) );
     446             :             /*  Initialize image position coordinates */
     447         684 :             im_pos[0] = tmp_pos[0];
     448         684 :             im_pos[1] = tmp_pos[1];
     449         684 :             im_pos[2] = tmp_pos[2];
     450             :             /*  Calculate image projection coordinate based on current surface axis */
     451         684 :             if ( ( loop_ub + 1 ) < 3 )
     452             :             {
     453         228 :                 scale = obj->cal.room_L;
     454             :             }
     455         456 :             else if ( ( loop_ub + 1 ) < 5 )
     456             :             {
     457         228 :                 scale = obj->cal.room_W;
     458             :             }
     459             :             else
     460             :             {
     461         228 :                 scale = obj->cal.room_H;
     462             :             }
     463         684 :             im_pos[coord] =
     464         684 :                 tmp_pos[coord] +
     465         684 :                 ( 2.0f * ( ( ( ( -( 1.0f - ( fmodf( ( (float) loop_ub ) + 1.0f, 2.0f ) * 2.0f ) ) ) * scale ) / 2.0f ) - tmp_pos[coord] ) );
     466             :             /*  0. Get euclidean distance from IMAGE SOURCE [N,W] to LIST */
     467         684 :             scale = ER_EUCLIDEAN_SCALE;
     468         684 :             path_dist = shoebox_get_euclidian_distance_internal( obj, im_pos, &scale );
     469             : 
     470         684 :             path_dist = scale * sqrtf( path_dist );
     471             :             /*  1. Compute time-of arrival (TOA) */
     472         684 :             ER_PARAMS->times.data[( (int32_t) rcoselev ) - 1] = path_dist / obj->soundspeed;
     473             :             /*  2./3. DOA */
     474        1368 :             ER_PARAMS->az_angle.data[( (int32_t) rcoselev ) - 1] =
     475         684 :                 rad2deg(
     476         684 :                     atan2f( im_pos[1] - obj->list_pos[1], im_pos[0] - obj->list_pos[0] ) );
     477        1368 :             ER_PARAMS->el_angle.data[( (int32_t) rcoselev ) - 1] =
     478         684 :                 rad2deg(
     479         684 :                     asinf( ( im_pos[2] - obj->list_pos[2] ) / path_dist ) );
     480             :             /*  4. Compute gain taking into account air and surface absorption */
     481             :             /*  and propagation loss */
     482         684 :             if ( path_dist < out_tmp )
     483             :             {
     484           0 :                 path_dist = out_tmp;
     485             :             }
     486         684 :             ER_PARAMS->gains.data[( (int32_t) rcoselev ) - 1] =
     487         684 :                 ( ( 1.0f - obj->cal.abs_coeff[loop_ub] ) * ( out_tmp / path_dist ) ) - ( path_dist * obj->air_coeff );
     488             :         }
     489             :     }
     490             : 
     491          12 :     return;
     492             : }

Generated by: LCOV version 1.14