LCOV - code coverage report
Current view: top level - lib_rend - ivas_objectRenderer_sfx_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 119 119 100.0 %
Date: 2025-05-03 01:55:50 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     1329442 : 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     1329442 :     push_wmops( "TDREND_Apply_ITD" );
      82             : 
      83             :     /* Prepare resampling buffer */
      84     1329442 :     Copy32( mem_itd_fx, buffer_fx, ITD_MEM_LEN ); /* Retrieve memory */                       // Qx
      85     1329442 :     p_input_fx = buffer_fx + ITD_MEM_LEN; /* pointer to the current subframe */               // Qx
      86     1329442 :     Copy32( input_fx, p_input_fx, length ); /* input current subframe */                      // Qx
      87     1329442 :     Copy32( buffer_fx + length, mem_itd_fx, ITD_MEM_LEN ); /* update memory for next frame */ // Qx
      88             : 
      89     1329442 :     currShift = abs_s( itd );                                                                                                     // Q0
      90     1329442 :     prevShift = abs_s( *previtd );                                                                                                // Q0
      91     1329442 :     tlen3 = s_max( 0, sub( SFX_SPAT_BIN_SINC_M, currShift ) ); /* Make sure there is enough look-ahead for the sinc resampling */ // Q0
      92     1329442 :     transition_len = sub( length, tlen3 );                                                                                        // Q0
      93             : 
      94     1329442 :     IF( i_mult( ( *previtd ), itd ) < 0 )
      95             :     {
      96             :         /* ITD sign change - apply shift on both channels */
      97       38168 :         Word16 tmp1 = imult1616( transition_len, prevShift ); // Q0
      98       38168 :         Word16 tmp2 = add( prevShift, currShift );            // Q0
      99             :         Word16 tmp_e;
     100       38168 :         Word16 tmp3 = BASOP_Util_Divide1616_Scale( tmp1, tmp2, &tmp_e ); // exp(tmp_e)
     101             :         Word16 tmp4;
     102       38168 :         Word16 tmp_e2 = BASOP_Util_Add_MantExp( tmp3, tmp_e, ONE_IN_Q14, 0, &tmp4 ); // exp(tmp4)
     103       38168 :         tmp4 = shr( tmp4, sub( 15, tmp_e2 ) );                                       // Q0
     104       38168 :         tlen1 = tmp4;                                                                // Q0
     105       38168 :         move16();
     106             : 
     107       38168 :         tlen2 = sub( transition_len, tlen1 ); // Q0
     108       38168 :         pstart1_fx = p_input_fx - prevShift;  // Qx
     109       38168 :         length_in1 = add( tlen1, prevShift ); // Q0
     110       38168 :         pstart2_fx = pstart1_fx + length_in1; // Qx
     111       38168 :         length_in2 = sub( tlen2, currShift ); // Q0
     112       38168 :         pstart3_fx = pstart2_fx + length_in2; // Qx
     113             :     }
     114             :     ELSE
     115             :     {
     116             :         /* ITD sign stays the same, or one of them is zero */
     117     1291274 :         tlen1 = transition_len; // Q0
     118     1291274 :         move16();
     119     1291274 :         tlen2 = 0; // Q0
     120     1291274 :         move16();
     121     1291274 :         pstart1_fx = p_input_fx - prevShift;                             // Qx
     122     1291274 :         length_in1 = sub( add( transition_len, prevShift ), currShift ); // Q0
     123     1291274 :         pstart2_fx = pstart1_fx + length_in1;                            // Qx
     124     1291274 :         length_in2 = 0;                                                  // Q0
     125     1291274 :         move16();
     126     1291274 :         pstart3_fx = pstart2_fx + add( length_in2, currShift ); // Qx
     127             :     }
     128             : 
     129     1329442 :     IF( *previtd == 0 )
     130             :     {
     131      111757 :         IF( itd > 0 )
     132             :         {
     133        3849 :             out_buf_A_fx = out_right_fx; // Qx
     134        3849 :             out_buf_B_fx = out_left_fx;  // Qx
     135             :         }
     136             :         ELSE
     137             :         {
     138      107908 :             out_buf_A_fx = out_left_fx;  // Qx
     139      107908 :             out_buf_B_fx = out_right_fx; // Qx
     140             :         }
     141             :     }
     142             :     ELSE
     143             :     {
     144     1217685 :         IF( *previtd > 0 )
     145             :         {
     146      613973 :             out_buf_A_fx = out_right_fx; // Qx
     147      613973 :             out_buf_B_fx = out_left_fx;  // Qx
     148             :         }
     149             :         ELSE
     150             :         {
     151      603712 :             out_buf_A_fx = out_left_fx;  // Qx
     152      603712 :             out_buf_B_fx = out_right_fx; // Qx
     153             :         }
     154             :     }
     155             : 
     156             :     /* Output buffer A */
     157     1329442 :     sincResample_fx( pstart1_fx, out_buf_A_fx, length_in1, tlen1 );
     158     1329442 :     Copy32( pstart2_fx, out_buf_A_fx + tlen1, sub( length, tlen1 ) ); // Qx
     159             : 
     160             :     /* Output buffer B */
     161     1329442 :     Copy32( p_input_fx, out_buf_B_fx, tlen1 ); // Qx
     162     1329442 :     sincResample_fx( pstart2_fx, out_buf_B_fx + tlen1, length_in2, tlen2 );
     163     1329442 :     Copy32( pstart3_fx, out_buf_B_fx + transition_len, tlen3 ); // Qx
     164             : 
     165     1329442 :     *previtd = itd; // Q0
     166     1329442 :     move16();
     167             : 
     168     1329442 :     pop_wmops();
     169     1329442 :     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     2658884 : 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 tmp64_fx; // Qx + 32
     195             :     const Word32 *p_mid_fx;
     196             :     const Word32 *p_forward_fx;
     197             :     const Word32 *p_backward_fx;
     198             :     const Word32 *p_sinc_forward_fx;
     199             :     const Word32 *p_sinc_backward_fx;
     200             : 
     201             :     // epsilon: 1e-15f
     202     2658884 :     const Word32 eps = 1208925824; // exp(eps_e)
     203     2658884 :     move32();
     204     2658884 :     const Word16 eps_e = -49;
     205     2658884 :     move16();
     206             : 
     207             :     /* avoid division by 0 */
     208     2658884 :     IF( 0 == length_out )
     209             :     {
     210     1291274 :         return;
     211             :     }
     212             : 
     213             :     /* Compute fractional time step */
     214     1367610 :     t_step_fx = L_deposit_h( BASOP_Util_Divide1616_Scale( length_in, length_out, &t_step_e ) ); // exp(t_step_e)
     215     1367610 :     t_frac_fx = 0;
     216     1367610 :     move32();
     217     1367610 :     t_frac_e = 0;
     218     1367610 :     move16();
     219             : 
     220   314247101 :     FOR( i = 0; i < length_out; i++ )
     221             :     {
     222             :         Word16 t_frac_plus_eps_e;
     223   312879491 :         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)
     224   312879491 :         t = extract_l( L_shr( t_frac_plus_eps, sub( 31, t_frac_plus_eps_e ) ) );                                  // Q0
     225             : 
     226             :         /* Calculate the sinc-index for the center value of the sinc */
     227             :         Word32 center_val;
     228             :         Word16 center_val_e;
     229   312879491 :         center_val = BASOP_Util_Add_Mant32Exp( t_frac_plus_eps, t_frac_plus_eps_e, L_negate( L_deposit_h( t ) ), 15, &center_val_e ); // exp(center_val_e)
     230   312879491 :         center_val_e = add( center_val_e, 6 );                                                                                        // center_val * SFX_SPAT_BIN_NUM_SUBSAMPLES (i.e. 64)
     231   312879491 :         center_val = BASOP_Util_Add_Mant32Exp( center_val, center_val_e, ONE_IN_Q29, 1, &center_val_e );                              // exp(center_val_e)
     232   312879491 :         snc0 = extract_l( L_shr( center_val, sub( 31, center_val_e ) ) );                                                             // Q0
     233             : 
     234             :         /* Run convolution forward and backward from mid point */
     235   312879491 :         p_mid_fx = input_fx + t;                                                      // Qx
     236   312879491 :         p_forward_fx = p_mid_fx + 1;                                                  // Qx
     237   312879491 :         p_backward_fx = p_mid_fx - 1;                                                 // Qx
     238   312879491 :         p_sinc_forward_fx = SincTable_fx + sub( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 );  // Q31
     239   312879491 :         p_sinc_backward_fx = SincTable_fx + add( SFX_SPAT_BIN_NUM_SUBSAMPLES, snc0 ); // Q31
     240             : 
     241   312879491 :         tmp64_fx = W_mult_32_32( *p_mid_fx, SincTable_fx[snc0] ); /* Middle point */ // Qx + 32
     242             : 
     243  1564397455 :         FOR( j = 0; j < SFX_SPAT_BIN_SINC_M - 1; j++ )
     244             :         {
     245  1251517964 :             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
     246  1251517964 :             p_sinc_forward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES;                                                                                    // Q31
     247  1251517964 :             p_sinc_backward_fx += SFX_SPAT_BIN_NUM_SUBSAMPLES;                                                                                   // Q31
     248  1251517964 :             p_forward_fx++;                                                                                                                      // Qx
     249  1251517964 :             p_backward_fx--;                                                                                                                     // Qx
     250             :         }
     251             : 
     252   312879491 :         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
     253             : 
     254   312879491 :         output_fx[i] = W_extract_h( tmp64_fx ); // Qx
     255   312879491 :         move32();
     256             : 
     257             :         /* Advance fractional time */
     258   312879491 :         t_frac_fx = BASOP_Util_Add_Mant32Exp( t_frac_fx, t_frac_e, t_step_fx, t_step_e, &t_frac_e ); // exp( t_frac_fx )
     259             :     }
     260             : 
     261     1367610 :     return;
     262             : }
     263             : 
     264             : 
     265             : /*-------------------------------------------------------------------*
     266             :  * TDREND_firfilt()
     267             :  *
     268             :  * FIR filtering function
     269             :  *
     270             :  --------------------------------------------------------------------*/
     271             : 
     272     2658884 : void TDREND_firfilt_fx(
     273             :     Word32 *signal_fx,             /* i/o: Input signal / Filtered signal   Qx */
     274             :     Word32 *filter_fx,             /* i/o: FIR filter                 filter_e */
     275             :     const Word16 filter_e,         /* i  : FIR filter exp                   Q0 */
     276             :     const Word32 *filter_delta_fx, /* i  : FIR filter delta           filter_e */
     277             :     const Word16 intp_count,       /* i  : interpolation count              Q0 */
     278             :     Word32 *mem_fx,                /* i/o: filter memory                    Qx */
     279             :     const Word16 subframe_length,  /* i  : Length of signal                 Q0 */
     280             :     const Word16 filterlength,     /* i  : Filter length                    Q0 */
     281             :     const Word16 Gain_fx,          /* i  : Gain                            Q14 */
     282             :     const Word16 prevGain_fx       /* i  : Previous gain                   Q14 */
     283             : )
     284             : {
     285             :     /* NOTE: this function is implemented with the assumption that the exponent/Q-factor of input signal will not change. */
     286             :     Word32 buffer_fx[SFX_SPAT_BIN_MAX_FILTER_LENGTH - 1 + L_SUBFRAME5MS_48k]; // Qx
     287             :     Word32 *p_signal_fx;                                                      // Qx
     288             :     Word32 *p_tmp_fx;                                                         // Qx
     289             :     Word32 *p_filter_fx;                                                      // exp(filter_e)
     290             :     Word16 i, j;
     291             :     Word32 tmp_fx;
     292             :     Word16 step_fx /* Q15 */, gain_tmp_fx /* Q15 */, gain_delta_fx /* Q14 */;
     293             :     Word16 tmp_e;
     294             :     Word64 tmp64_fx;
     295             : 
     296     2658884 :     gain_delta_fx = sub( Gain_fx, prevGain_fx );                                     // Q14
     297     2658884 :     step_fx = BASOP_Util_Divide1616_Scale( gain_delta_fx, subframe_length, &tmp_e ); // exp(tmp_e)
     298     2658884 :     tmp_e = sub( tmp_e, Q14 );
     299     2658884 :     step_fx = shl_sat( step_fx, tmp_e );     // Q15
     300     2658884 :     gain_tmp_fx = shl_sat( prevGain_fx, 1 ); // Q15
     301             : 
     302             :     /* Handle memory */
     303     2658884 :     p_signal_fx = buffer_fx + sub( filterlength, 1 );                                                                                        // Qx
     304     2658884 :     Copy32( mem_fx, buffer_fx, sub( filterlength, 1 ) ); /* Insert memory */                                                                 // Qx
     305     2658884 :     Copy32( signal_fx, buffer_fx + sub( filterlength, 1 ), subframe_length ); /* Insert current frame */                                     // Qx
     306     2658884 :     Copy32( signal_fx + add( sub( subframe_length, filterlength ), 1 ), mem_fx, sub( filterlength, 1 ) ); /* Update memory for next frame */ // Qx
     307             : 
     308             :     /* Convolution */
     309   630583044 :     FOR( i = 0; i < subframe_length; i++ )
     310             :     {
     311   627924160 :         tmp64_fx = 0;
     312   627924160 :         move64();
     313   627924160 :         tmp_e = 0;
     314   627924160 :         move16();
     315   627924160 :         p_tmp_fx = p_signal_fx + i; // Qx
     316   627924160 :         p_filter_fx = filter_fx;    // exp(filter_e)
     317             : 
     318             : 
     319 80312603840 :         FOR( j = 0; j < filterlength; j++ )
     320             :         {
     321 79684679680 :             tmp64_fx = W_mac_32_32( tmp64_fx, *p_filter_fx, *p_tmp_fx ); // Qx + (Q31 - filter_e) + 1
     322 79684679680 :             p_filter_fx++;                                               // exp(filter_e)
     323 79684679680 :             p_tmp_fx--;                                                  // Qx
     324             :         }
     325             : 
     326             :         // This is done to keep the output Q same as input Q for signal
     327   627924160 :         tmp64_fx = W_shl( tmp64_fx, filter_e ); // Qx + 32
     328   627924160 :         tmp_fx = W_extract_h( tmp64_fx );       // Qx
     329             : 
     330             :         /* Apply linear gain interpolation in case of abrupt gain changes */
     331   627924160 :         gain_tmp_fx = add( gain_tmp_fx, step_fx );         // Q15
     332   627924160 :         signal_fx[i] = Mpy_32_16_1( tmp_fx, gain_tmp_fx ); // Qx
     333   627924160 :         move32();
     334   627924160 :         IF( LT_16( i, intp_count ) )
     335             :         {
     336    17326932 :             v_add_fx( filter_fx, filter_delta_fx, filter_fx, filterlength ); // exp(filter_e)
     337             :         }
     338             :     }
     339             : 
     340     2658884 :     return;
     341             : }

Generated by: LCOV version 1.14