LCOV - code coverage report
Current view: top level - lib_rend - ivas_objectRenderer_sfx_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main -- dec/rend @ 633e3f2e309758d10805ef21e0436356fe719b7a Lines: 137 137 100.0 %
Date: 2025-08-23 01:22:27 Functions: 3 3 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 <stdint.h>
      34             : #include "options.h"
      35             : #include <math.h>
      36             : #include "ivas_prot_rend_fx.h"
      37             : #include "ivas_rom_rend.h"
      38             : #include "prot_fx.h"
      39             : #include "wmc_auto.h"
      40             : 
      41             : 
      42             : /*---------------------------------------------------------------------*
      43             :  * Local constants
      44             :  *---------------------------------------------------------------------*/
      45             : 
      46             : 
      47             : /*---------------------------------------------------------------------*
      48             :  * Local function prototypes
      49             :  *---------------------------------------------------------------------*/
      50             : 
      51             : static void sincResample_fx( const Word32 *input_fx, Word32 *output_fx, const Word16 length_in, const Word16 length_out );
      52             : 
      53             : /*---------------------------------------------------------------------*
      54             :  * TDREND_Apply_ITD()
      55             :  *
      56             :  * Apply ITD by delaying late channel
      57             :  *---------------------------------------------------------------------*/
      58     1388199 : void TDREND_Apply_ITD_fx(
      59             :     Word32 *input_fx,     /* i  : Input subframe to be time adjusted    Qx */
      60             :     Word32 *out_left_fx,  /* o  : Output left channel with ITD applied  Qx */
      61             :     Word32 *out_right_fx, /* o  : Output right channel with ITD applied Qx */
      62             :     Word16 *previtd,      /* i/o: Previous ITD value                    Q0 */
      63             :     const Word16 itd,     /* i  : Current subframe ITD value            Q0 */
      64             :     Word32 *mem_itd_fx,   /* i/o: ITD buffer memory                     Qx */
      65             :     const Word16 length   /* i  : Subframe length                       Q0 */
      66             : )
      67             : {
      68             :     Word16 transition_len;
      69             :     Word16 tlen1, tlen2, tlen3;
      70             :     Word16 length_in1;
      71             :     Word16 length_in2;
      72             :     Word16 currShift;
      73             :     Word16 prevShift;
      74             :     Word32 *pstart1_fx;
      75             :     Word32 *pstart2_fx;
      76             :     Word32 *pstart3_fx;
      77             :     Word32 buffer_fx[ITD_MEM_LEN + L_SUBFRAME5MS_48k]; // Qx
      78             :     Word32 *p_input_fx;
      79             :     Word32 *out_buf_A_fx, *out_buf_B_fx;
      80             : 
      81     1388199 :     push_wmops( "TDREND_Apply_ITD" );
      82             : 
      83             :     /* Prepare resampling buffer */
      84     1388199 :     Copy32( mem_itd_fx, buffer_fx, ITD_MEM_LEN ); /* Retrieve memory */                       // Qx
      85     1388199 :     p_input_fx = buffer_fx + ITD_MEM_LEN; /* pointer to the current subframe */               // Qx
      86     1388199 :     Copy32( input_fx, p_input_fx, length ); /* input current subframe */                      // Qx
      87     1388199 :     Copy32( buffer_fx + length, mem_itd_fx, ITD_MEM_LEN ); /* update memory for next frame */ // Qx
      88             : 
      89     1388199 :     currShift = abs_s( itd );                                                                                                     // Q0
      90     1388199 :     prevShift = abs_s( *previtd );                                                                                                // Q0
      91     1388199 :     tlen3 = s_max( 0, sub( SFX_SPAT_BIN_SINC_M, currShift ) ); /* Make sure there is enough look-ahead for the sinc resampling */ // Q0
      92     1388199 :     transition_len = sub( length, tlen3 );                                                                                        // Q0
      93             : 
      94     1388199 :     IF( i_mult( ( *previtd ), itd ) < 0 )
      95             :     {
      96             :         /* ITD sign change - apply shift on both channels */
      97       40763 :         Word16 tmp1 = imult1616( transition_len, prevShift ); // Q0
      98       40763 :         Word16 tmp2 = add( prevShift, currShift );            // Q0
      99             :         Word16 tmp_e;
     100       40763 :         Word16 tmp3 = BASOP_Util_Divide1616_Scale( tmp1, tmp2, &tmp_e ); // exp(tmp_e)
     101             :         Word16 tmp4;
     102       40763 :         Word16 tmp_e2 = BASOP_Util_Add_MantExp( tmp3, tmp_e, ONE_IN_Q14, 0, &tmp4 ); // exp(tmp4)
     103       40763 :         tmp4 = shr( tmp4, sub( 15, tmp_e2 ) );                                       // Q0
     104       40763 :         tlen1 = tmp4;                                                                // Q0
     105       40763 :         move16();
     106             : 
     107       40763 :         tlen2 = sub( transition_len, tlen1 ); // Q0
     108       40763 :         pstart1_fx = p_input_fx - prevShift;  // Qx
     109       40763 :         length_in1 = add( tlen1, prevShift ); // Q0
     110       40763 :         pstart2_fx = pstart1_fx + length_in1; // Qx
     111       40763 :         length_in2 = sub( tlen2, currShift ); // Q0
     112       40763 :         pstart3_fx = pstart2_fx + length_in2; // Qx
     113             :     }
     114             :     ELSE
     115             :     {
     116             :         /* ITD sign stays the same, or one of them is zero */
     117     1347436 :         tlen1 = transition_len; // Q0
     118     1347436 :         move16();
     119     1347436 :         tlen2 = 0; // Q0
     120     1347436 :         move16();
     121     1347436 :         pstart1_fx = p_input_fx - prevShift;                             // Qx
     122     1347436 :         length_in1 = sub( add( transition_len, prevShift ), currShift ); // Q0
     123     1347436 :         pstart2_fx = pstart1_fx + length_in1;                            // Qx
     124     1347436 :         length_in2 = 0;                                                  // Q0
     125     1347436 :         move16();
     126     1347436 :         pstart3_fx = pstart2_fx + add( length_in2, currShift ); // Qx
     127             :     }
     128             : 
     129     1388199 :     IF( *previtd == 0 )
     130             :     {
     131      118838 :         IF( itd > 0 )
     132             :         {
     133        4194 :             out_buf_A_fx = out_right_fx; // Qx
     134        4194 :             out_buf_B_fx = out_left_fx;  // Qx
     135             :         }
     136             :         ELSE
     137             :         {
     138      114644 :             out_buf_A_fx = out_left_fx;  // Qx
     139      114644 :             out_buf_B_fx = out_right_fx; // Qx
     140             :         }
     141             :     }
     142             :     ELSE
     143             :     {
     144     1269361 :         IF( *previtd > 0 )
     145             :         {
     146      639852 :             out_buf_A_fx = out_right_fx; // Qx
     147      639852 :             out_buf_B_fx = out_left_fx;  // Qx
     148             :         }
     149             :         ELSE
     150             :         {
     151      629509 :             out_buf_A_fx = out_left_fx;  // Qx
     152      629509 :             out_buf_B_fx = out_right_fx; // Qx
     153             :         }
     154             :     }
     155             : 
     156             :     /* Output buffer A */
     157     1388199 :     sincResample_fx( pstart1_fx, out_buf_A_fx, length_in1, tlen1 );
     158     1388199 :     Copy32( pstart2_fx, out_buf_A_fx + tlen1, sub( length, tlen1 ) ); // Qx
     159             : 
     160             :     /* Output buffer B */
     161     1388199 :     Copy32( p_input_fx, out_buf_B_fx, tlen1 ); // Qx
     162     1388199 :     sincResample_fx( pstart2_fx, out_buf_B_fx + tlen1, length_in2, tlen2 );
     163     1388199 :     Copy32( pstart3_fx, out_buf_B_fx + transition_len, tlen3 ); // Qx
     164             : 
     165     1388199 :     *previtd = itd; // Q0
     166     1388199 :     move16();
     167             : 
     168     1388199 :     pop_wmops();
     169     1388199 :     return;
     170             : }
     171             : 
     172             : /*---------------------------------------------------------------------*
     173             :  * sincResample()
     174             :  *
     175             :  * Resample signal (stretch/compress) to new ITD
     176             :  * The sinc resampling reads SFX_SPAT_BIN_SINC_M (5) samples outside of
     177             :  * the target frame.
     178             :  *---------------------------------------------------------------------*/
     179             : 
     180     2776398 : static void sincResample_fx(
     181             :     const Word32 *input_fx, /*i  : Input signal    Qx */
     182             :     Word32 *output_fx,      /*o  : Output signal   Qx */
     183             :     const Word16 length_in, /*i  : Input length    Q0 */
     184             :     const Word16 length_out /*i  : Output length   Q0 */
     185             : )
     186             : {
     187             :     Word16 snc0;
     188             :     Word16 i, j;
     189             :     Word16 t;
     190             :     Word32 t_step_fx;
     191             :     Word16 t_step_e;
     192             :     Word32 t_frac_fx;
     193             :     Word16 t_frac_e;
     194             :     Word64 t_frac_fx_acc;
     195             :     Word64 tmp64_fx; // Qx + 32
     196             :     const Word32 *p_mid_fx;
     197             :     const Word32 *p_forward_fx;
     198             :     const Word32 *p_backward_fx;
     199             :     const Word32 *p_sinc_forward_fx;
     200             :     const Word32 *p_sinc_backward_fx;
     201             : 
     202             :     // epsilon: 1e-15f
     203     2776398 :     const Word32 eps = 1208925824; // exp(eps_e)
     204     2776398 :     move32();
     205     2776398 :     const Word16 eps_e = -49;
     206     2776398 :     move16();
     207             : 
     208             :     /* avoid division by 0 */
     209     2776398 :     IF( 0 == length_out )
     210             :     {
     211     1347436 :         return;
     212             :     }
     213             : 
     214             :     /* Compute fractional time step */
     215     1428962 :     t_step_fx = L_deposit_h( BASOP_Util_Divide1616_Scale( length_in, length_out, &t_step_e ) ); // exp(t_step_e)
     216     1428962 :     t_frac_fx_acc = 0;
     217     1428962 :     move64();
     218     1428962 :     t_frac_fx = 0;
     219     1428962 :     move32();
     220     1428962 :     t_frac_e = 0;
     221     1428962 :     move16();
     222             : 
     223   326814739 :     FOR( i = 0; i < length_out; i++ )
     224             :     {
     225             :         Word16 t_frac_plus_eps_e;
     226   325385777 :         Word32 t_frac_plus_eps = BASOP_Util_Add_Mant32Exp( t_frac_fx, t_frac_e, eps, eps_e, &t_frac_plus_eps_e ); // exp(t_frac_plus_eps_e)
     227   325385777 :         t = extract_l( L_shr( t_frac_plus_eps, sub( 31, t_frac_plus_eps_e ) ) );                                  // Q0
     228             : 
     229             :         /* Calculate the sinc-index for the center value of the sinc */
     230             :         Word16 center_val_e;
     231             :         Word64 center_val;
     232             : #ifndef FIX_ISSUE_1811_EXCEEDING_W_SHIFTS
     233             :         center_val = W_sub( t_frac_plus_eps, W_shl( t, sub( 31, t_frac_plus_eps_e ) ) ); // exp(center_val_e)
     234             : #else
     235   325385777 :         center_val = W_sub( t_frac_plus_eps, W_shl( t, s_min( sub( 31, t_frac_plus_eps_e ), 63 ) ) );                                        // exp( center_val_e )
     236             : #endif
     237   325385777 :         center_val_e = add( t_frac_plus_eps_e, 6 );
     238   325385777 :         Word16 com_e = s_max( 0, center_val_e );
     239   325385777 :         center_val = W_add( W_shr( center_val, sub( com_e, center_val_e ) ), W_shl( 1, sub( 30, com_e ) ) ); // exp(center_val_e)
     240   325385777 :         snc0 = extract_l( W_shl_sat_l( center_val, sub( com_e, 31 ) ) );
     241             :         /* Run convolution forward and backward from mid point */
     242   325385777 :         p_mid_fx = input_fx + t;                                                      // Qx
     243   325385777 :         p_forward_fx = p_mid_fx + 1;                                                  // Qx
     244   325385777 :         p_backward_fx = p_mid_fx - 1;                                                 // Qx
     245   325385777 :         p_sinc_forward_fx = SincTable_fx + sub( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 );  // Q31
     246   325385777 :         p_sinc_backward_fx = SincTable_fx + add( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
     247             : 
     248   325385777 :         tmp64_fx = W_mult_32_32( *p_mid_fx, SincTable_fx[snc0] ); /* Middle point */ // Qx + 32
     249             : 
     250  1626928885 :         FOR( j = 0; j < SFX_SPAT_BIN_SINC_M - 1; j++ )
     251             :         {
     252  1301543108 :             tmp64_fx = W_add( tmp64_fx, W_mac_32_32( W_mult_32_32( *p_forward_fx, *p_sinc_forward_fx ), *p_backward_fx, *p_sinc_backward_fx ) ); // Qx + 32
     253  1301543108 :             p_sinc_forward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES;                                                                                    // Q31
     254  1301543108 :             p_sinc_backward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES;                                                                                   // Q31
     255  1301543108 :             p_forward_fx++;                                                                                                                      // Qx
     256  1301543108 :             p_backward_fx--;                                                                                                                     // Qx
     257             :         }
     258             : 
     259   325385777 :         tmp64_fx = W_mac_32_32( tmp64_fx, *p_forward_fx, *p_sinc_forward_fx ); /* Integer index always rounded down --> 4 steps backward, 5 steps forward */ // Qx + 32
     260             : 
     261   325385777 :         output_fx[i] = W_extract_h( tmp64_fx ); // Qx
     262   325385777 :         move32();
     263             : 
     264             :         /* Advance fractional time */
     265   325385777 :         t_frac_fx_acc = W_add( t_frac_fx_acc, t_step_fx ); // t_step_e
     266   325385777 :         Word16 hdrm = W_norm( t_frac_fx_acc );
     267   325385777 :         hdrm = sub( hdrm, 32 );
     268   325385777 :         t_frac_fx = W_shl_sat_l( t_frac_fx_acc, hdrm );
     269   325385777 :         t_frac_e = sub( t_step_e, hdrm );
     270   325385777 :         move16();
     271             :     }
     272             : 
     273     1428962 :     return;
     274             : }
     275             : 
     276             : 
     277             : /*-------------------------------------------------------------------*
     278             :  * TDREND_firfilt()
     279             :  *
     280             :  * FIR filtering function
     281             :  *
     282             :  --------------------------------------------------------------------*/
     283             : 
     284     2776398 : void TDREND_firfilt_fx(
     285             :     Word32 *signal_fx,             /* i/o: Input signal / Filtered signal   Qx */
     286             :     Word32 *filter_fx,             /* i/o: FIR filter                 filter_e */
     287             :     const Word16 filter_e,         /* i  : FIR filter exp                   Q0 */
     288             :     const Word32 *filter_delta_fx, /* i  : FIR filter delta           filter_e */
     289             :     const Word16 intp_count,       /* i  : interpolation count              Q0 */
     290             :     Word32 *mem_fx,                /* i/o: filter memory                    Qx */
     291             :     const Word16 subframe_length,  /* i  : Length of signal                 Q0 */
     292             :     const Word16 filterlength,     /* i  : Filter length                    Q0 */
     293             :     const Word32 Gain_fx,          /* i  : Gain                            Q30 */
     294             :     const Word32 prevGain_fx       /* i  : Previous gain                   Q30 */
     295             : )
     296             : {
     297             :     /* NOTE: this function is implemented with the assumption that the exponent/Q-factor of input signal will not change. */
     298             :     Word32 buffer_fx[SFX_SPAT_BIN_MAX_FILTER_LENGTH - 1 + L_SUBFRAME5MS_48k]; // Qx
     299             :     Word32 *p_signal_fx;                                                      // Qx
     300             :     Word32 *p_tmp_fx;                                                         // Qx
     301             :     Word32 *p_filter_fx;                                                      // exp(filter_e)
     302             :     Word16 i, j;
     303             :     Word32 tmp_fx;
     304             :     Word32 step_fx /* Q31 */, gain_tmp_fx /* Q31 */, gain_delta_fx /* Q30 */;
     305             :     Word16 tmp_e;
     306             :     Word64 tmp64_fx;
     307     2776398 :     Word16 shift = sub( filter_e, 32 );
     308     2776398 :     gain_delta_fx = L_sub( Gain_fx, prevGain_fx );                                                  // Q30
     309     2776398 :     step_fx = L_deposit_h( BASOP_Util_Divide3232_Scale( gain_delta_fx, subframe_length, &tmp_e ) ); // exp(tmp_e)
     310     2776398 :     tmp_e = sub( tmp_e, Q30 );
     311     2776398 :     step_fx = L_shl_sat( step_fx, tmp_e );     // Q31
     312     2776398 :     gain_tmp_fx = L_shl_sat( prevGain_fx, 1 ); // Q31
     313             : 
     314             :     /* Handle memory */
     315     2776398 :     p_signal_fx = buffer_fx + sub( filterlength, 1 );                        // Qx
     316     2776398 :     Copy32( mem_fx, buffer_fx, sub( filterlength, 1 ) ); /* Insert memory */ // Qx
     317             : #ifdef NONBE_FIX_1176_OSBA_REVERB_JBM_ASAN_ERROR
     318     2776398 :     Copy32( signal_fx, p_signal_fx, subframe_length ); /* Insert current frame */                                                              // Qx
     319     2776398 :     Copy32( p_signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
     320             : #else
     321             :     Copy32( signal_fx, buffer_fx + sub( filterlength, 1 ), subframe_length ); /* Insert current frame */                                     // Qx
     322             :     Copy32( signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
     323             : #endif
     324             : 
     325             :     /* Convolution */
     326    20436762 :     FOR( i = 0; i < intp_count; i++ )
     327             :     {
     328    17660364 :         tmp64_fx = 0;
     329    17660364 :         move64();
     330    17660364 :         p_tmp_fx = p_signal_fx + i; // Qx
     331    17660364 :         p_filter_fx = filter_fx;    // exp(filter_e)
     332             : 
     333             : 
     334  2231383208 :         FOR( j = 0; j < filterlength; j++ )
     335             :         {
     336  2213722844 :             tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
     337  2213722844 :             p_filter_fx++;                                               // exp(filter_e)
     338  2213722844 :             p_tmp_fx--;                                                  // Qx
     339             :         }
     340             : 
     341             :         // This is done to keep the output Q same as input Q for signal
     342    17660364 :         tmp_fx = W_shl_sat_l( tmp64_fx, shift ); // Qx
     343             : 
     344             :         /* Apply linear gain interpolation in case of abrupt gain changes */
     345    17660364 :         gain_tmp_fx = L_add_sat( gain_tmp_fx, step_fx ); /* Saturating values which just exceeds 1, Q31*/
     346    17660364 :         signal_fx[i] = Mpy_32_32( tmp_fx, gain_tmp_fx ); // Qx
     347    17660364 :         move32();
     348    17660364 :         v_add_fx( filter_fx, filter_delta_fx, filter_fx, filterlength ); // exp(filter_e)
     349             :     }
     350   638192194 :     FOR( ; i < subframe_length; i++ )
     351             :     {
     352   635415796 :         tmp64_fx = 0;
     353   635415796 :         move64();
     354   635415796 :         p_tmp_fx = p_signal_fx + i; // Qx
     355   635415796 :         p_filter_fx = filter_fx;    // exp(filter_e)
     356             : 
     357             : 
     358 81184343192 :         FOR( j = 0; j < filterlength; j++ )
     359             :         {
     360 80548927396 :             tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
     361 80548927396 :             p_filter_fx++;                                               // exp(filter_e)
     362 80548927396 :             p_tmp_fx--;                                                  // Qx
     363             :         }
     364             : 
     365             :         // This is done to keep the output Q same as input Q for signal
     366   635415796 :         tmp_fx = W_shl_sat_l( tmp64_fx, shift ); // Qx
     367             : 
     368             :         /* Apply linear gain interpolation in case of abrupt gain changes */
     369   635415796 :         gain_tmp_fx = L_add_sat( gain_tmp_fx, step_fx ); /* Saturating values which just exceeds 1, Q31*/
     370   635415796 :         signal_fx[i] = Mpy_32_32( tmp_fx, gain_tmp_fx ); // Qx
     371   635415796 :         move32();
     372             :     }
     373             : 
     374     2776398 :     return;
     375             : }

Generated by: LCOV version 1.14