LCOV - code coverage report
Current view: top level - lib_dec - FEC_adapt_codebook.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 31 167 18.6 %
Date: 2025-05-23 08:37:30 Functions: 1 3 33.3 %

          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             : /*====================================================================================
      34             :     EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
      35             :   ====================================================================================*/
      36             : 
      37             : #include <stdint.h>
      38             : #include "options.h"
      39             : #ifdef DEBUGGING
      40             : #include "debug.h"
      41             : #endif
      42             : #include <math.h>
      43             : #include "cnst.h"
      44             : #include "rom_dec.h"
      45             : #include "prot.h"
      46             : #include "wmc_auto.h"
      47             : 
      48             : /*-------------------------------------------------------------------------
      49             :  * FEC_synchro_exc()
      50             :  *
      51             :  * Perform resynchronisation of the last glottal pulse in voiced frame lost
      52             :  *------------------------------------------------------------------------*/
      53             : 
      54             : /*! r: do_WI flag */
      55           0 : static int16_t FEC_synchro_exc(
      56             :     const int16_t L_frame,         /* i  : length of the frame                               */
      57             :     float *exc,                    /* i/o: exc vector to modify                              */
      58             :     const int16_t desire_puls_pos, /* i  : Pulse position send by the encoder                */
      59             :     const int16_t true_puls_pos,   /* i  : Present pulse location                            */
      60             :     const int16_t Old_pitch        /* i  : Pitch use to create temporary adaptive codebook   */
      61             : )
      62             : {
      63             :     float exc_tmp[L_FRAME16k + L_SUBFR], min_energy, *pt_exc, *pt_exc1, ftmp, fact;
      64           0 :     int16_t i, j, point_to_remove, point_to_add = -1, nb_min;
      65             :     int16_t min_pos[L_FRAME16k / PIT_MIN_DOUBLEEXTEND], points_by_pos[L_FRAME16k / PIT_MIN_DOUBLEEXTEND], total_point, tmp_len;
      66             :     int16_t *pt_pos, pos, start_search, tmp16;
      67             :     int16_t remaining_len;
      68             : 
      69             :     /* Init */
      70           0 :     for ( i = 0; i < L_FRAME16k / PIT_MIN_DOUBLEEXTEND; i++ )
      71             :     {
      72           0 :         min_pos[i] = 10000;
      73           0 :         points_by_pos[i] = 0;
      74             :     }
      75             : 
      76             :     /* Find number of point to remove and number of minimum */
      77           0 :     point_to_remove = true_puls_pos - desire_puls_pos; /* if it is negative it means remove point else it means add point */
      78             : 
      79           0 :     pos = L_frame - true_puls_pos;
      80           0 :     nb_min = pos / Old_pitch;
      81             : 
      82             :     /* if Old pitch < 128, must have at least 2 min */
      83           0 :     if ( Old_pitch <= 128 && nb_min < 2 )
      84             :     {
      85           0 :         nb_min = 2;
      86             :     }
      87             : 
      88             :     /* Must have at least 1 min */
      89           0 :     if ( nb_min == 0 )
      90             :     {
      91             :         /* Safety check, should be very rare but still needed*/
      92           0 :         nb_min = 1;
      93             :     }
      94             : 
      95           0 :     pt_exc = exc + pos;
      96             : 
      97             :     /* Find start_search for minimum energy search*/
      98           0 :     start_search = -3 * Old_pitch / 4;
      99             : 
     100           0 :     if ( start_search + pos < 0 )
     101             :     {
     102             :         /* This case is rare but still need to be taken care*/
     103           0 :         start_search = -pos;
     104             : 
     105           0 :         if ( abs( start_search ) < Old_pitch / 8 )
     106             :         {
     107             :             /* it's not safe to remove/add point inside 1/8 of the pulse position */
     108           0 :             return 0;
     109             :         }
     110             :     }
     111             : 
     112             :     /* Find min energy in the first pitch section */
     113           0 :     min_energy = 65536 * 65536.0f;
     114             : 
     115             :     /* --------------------------------------------------------------------
     116             :      * The minimum energy regions are determined by the computing the energy
     117             :      * using a sliding 5-sample window. The minimum energy position is set
     118             :      * at the middle of the window at which the energy is at minimum
     119             :      * --------------------------------------------------------------------*/
     120             : 
     121           0 :     ftmp = ( pt_exc[start_search] * pt_exc[start_search] );
     122           0 :     ftmp += ( pt_exc[start_search + 1] * pt_exc[start_search + 1] );
     123           0 :     ftmp += ( pt_exc[start_search + 2] * pt_exc[start_search + 2] );
     124           0 :     ftmp += ( pt_exc[start_search + 3] * pt_exc[start_search + 3] );
     125           0 :     ftmp += ( pt_exc[start_search + 4] * pt_exc[start_search + 4] );
     126             : 
     127           0 :     if ( ftmp < min_energy )
     128             :     {
     129           0 :         min_energy = ftmp;
     130           0 :         min_pos[0] = ( pos + start_search + 2 );
     131             :     }
     132             : 
     133           0 :     for ( i = start_search; i < -5; i++ )
     134             :     {
     135           0 :         ftmp -= pt_exc[i] * pt_exc[i];
     136           0 :         ftmp += pt_exc[i + 5] * pt_exc[i + 5];
     137           0 :         if ( ftmp < min_energy )
     138             :         {
     139           0 :             min_energy = ftmp;
     140           0 :             min_pos[0] = pos + i + 2;
     141             :         }
     142             :     }
     143             : 
     144           0 :     for ( j = 1; j < nb_min; j++ )
     145             :     {
     146           0 :         min_pos[j] = min_pos[j - 1] - Old_pitch;
     147             :         /* If the first minimum is in the past, forget this minimum */
     148           0 :         if ( min_pos[j] < 0 )
     149             :         {
     150             :             /* Safety check */
     151           0 :             min_pos[j] = -10000;
     152           0 :             nb_min = nb_min - 1;
     153             :         }
     154             :     }
     155             : 
     156             :     /* safety-measure against not properly initialized min_pos[] */
     157           0 :     if ( min_energy >= 65536 * 65536.0f )
     158             :     {
     159           0 :         return 0;
     160             :     }
     161             : 
     162             :     /*--------------------------------------------------------------------
     163             :      * Determine the number of samples to be added or removed at each pitch
     164             :      * cycle whereby less samples are added/removed at the beginning and
     165             :      * more towards the end of the frame
     166             :      * --------------------------------------------------------------------*/
     167             : 
     168           0 :     if ( nb_min == 1 || abs( point_to_remove ) == 1 )
     169             :     {
     170           0 :         nb_min = 1;
     171           0 :         points_by_pos[0] = (int16_t) abs( point_to_remove );
     172             :     }
     173             :     else
     174             :     {
     175             :         /* First position */
     176           0 :         fact = (float) abs( point_to_remove ) / ( nb_min * nb_min );
     177             : 
     178           0 :         total_point = (int16_t) ( fact + 0.5 );
     179           0 :         points_by_pos[0] = total_point;
     180             : 
     181           0 :         for ( i = 2; i <= nb_min; i++ )
     182             :         {
     183           0 :             points_by_pos[i - 1] = (int16_t) ( fact * ( i * i ) - total_point + 0.5 );
     184           0 :             total_point += points_by_pos[i - 1];
     185             : 
     186             :             /* ensure a constant increase */
     187           0 :             if ( points_by_pos[i - 1] < points_by_pos[i - 2] )
     188             :             {
     189           0 :                 tmp16 = points_by_pos[i - 2];
     190           0 :                 points_by_pos[i - 2] = points_by_pos[i - 1];
     191           0 :                 points_by_pos[i - 1] = tmp16;
     192             :             }
     193             :         }
     194             :     }
     195             : 
     196             :     /* --------------------------------------------------------------------
     197             :      * Sample deletion or insertion is performed in minimum energy regions.
     198             :      * At the end of this section the last maximum pulse in the concealed
     199             :      * excitation is forced to align to the actual maximum pulse position
     200             :      * at the end of the frame which is transmitted in the future frame.
     201             :      * --------------------------------------------------------------------*/
     202             : 
     203           0 :     if ( point_to_remove > 0 )
     204             :     {
     205           0 :         point_to_add = point_to_remove;
     206             :     }
     207             : 
     208           0 :     pt_exc = exc_tmp;
     209           0 :     pt_exc1 = exc;
     210             : 
     211           0 :     i = 0;
     212           0 :     pt_pos = min_pos + nb_min - 1;
     213           0 :     if ( point_to_add > 0 ) /* add some points */
     214             :     {
     215           0 :         remaining_len = L_frame;
     216             : 
     217           0 :         for ( i = 0; i < nb_min; i++ )
     218             :         {
     219             :             /* Copy section */
     220           0 :             if ( i == 0 )
     221             :             {
     222             :                 /* Compute len to copy */
     223           0 :                 tmp_len = *pt_pos;
     224             :             }
     225             :             else
     226             :             {
     227             :                 /* Compute len to copy */
     228           0 :                 tmp_len = *pt_pos - *( pt_pos + 1 ) - points_by_pos[i - 1];
     229             :             }
     230             : 
     231           0 :             mvr2r( pt_exc1, pt_exc, tmp_len );
     232           0 :             remaining_len -= tmp_len;
     233           0 :             pt_exc1 += tmp_len;
     234           0 :             pt_exc += tmp_len;
     235             : 
     236             :             /* add some points */
     237           0 :             ftmp = -( *pt_exc1 / 20 );
     238           0 :             for ( j = 0; j < points_by_pos[i]; j++ )
     239             :             {
     240           0 :                 *pt_exc++ = ftmp;
     241           0 :                 ftmp = -ftmp;
     242             :             }
     243             : 
     244           0 :             remaining_len -= points_by_pos[i];
     245           0 :             pt_pos--;
     246             :         }
     247             : 
     248             :         /* Copy remaining length */
     249           0 :         remaining_len = max( 0, remaining_len );
     250           0 :         mvr2r( pt_exc1, pt_exc, remaining_len );
     251             : 
     252             :         /* Update true excitation buffer*/
     253           0 :         mvr2r( exc_tmp, exc, L_frame );
     254             :     }
     255             :     else /* Remove points */
     256             :     {
     257           0 :         remaining_len = L_frame;
     258             : 
     259           0 :         for ( i = 0; i < nb_min; i++ )
     260             :         {
     261           0 :             if ( i == 0 )
     262             :             {
     263             :                 /* Compute len to copy */
     264           0 :                 tmp_len = *pt_pos;
     265             :             }
     266             :             else
     267             :             {
     268             :                 /* Compute len to copy */
     269           0 :                 tmp_len = *pt_pos - *( pt_pos + 1 ) - points_by_pos[i - 1];
     270             :             }
     271             : 
     272           0 :             mvr2r( pt_exc1, pt_exc, tmp_len );
     273           0 :             remaining_len -= tmp_len;
     274           0 :             pt_exc1 += tmp_len;
     275           0 :             pt_exc += tmp_len;
     276             : 
     277             :             /* Remove points */
     278           0 :             for ( j = 0; j < points_by_pos[i]; j++ )
     279             :             {
     280           0 :                 pt_exc1++;
     281             :             }
     282           0 :             pt_pos--;
     283             :         }
     284             : 
     285             :         /* Copy remaining length */
     286           0 :         remaining_len = max( 0, remaining_len );
     287           0 :         mvr2r( pt_exc1, pt_exc, remaining_len );
     288             : 
     289             :         /* Update true excitation buffer*/
     290           0 :         mvr2r( exc_tmp, exc, L_frame );
     291             :     }
     292             : 
     293           0 :     return 1;
     294             : }
     295             : 
     296             : 
     297             : /*---------------------------------------------------------------------*
     298             :  * FEC_SinOnset()
     299             :  *
     300             :  * Create an artificial onset when it is lost
     301             :  *---------------------------------------------------------------------*/
     302             : 
     303           9 : void FEC_SinOnset(
     304             :     float *exc,       /* i/o: exc vector to modify                */
     305             :     int16_t puls_pos, /* i  : last pulse position desired         */
     306             :     int16_t T0,
     307             :     float enr_q,          /* i  : energy provided by the encoder      */
     308             :     float *Aq,            /* i  : A(z) filter                         */
     309             :     const int16_t L_frame /* i  : frame length                        */
     310             : )
     311             : {
     312           9 :     int16_t P0, onset_len, sign = 0, i, len, L_subfr;
     313             :     float h1[L_SUBFR16k], mem[M], exc_tmp[L_FRAME16k + MODE1_L_FIR_FER];
     314             :     float *pt_end, *pt_exc, enr_LP, gain;
     315             : 
     316           9 :     L_subfr = L_SUBFR;
     317           9 :     if ( L_frame == L_FRAME16k )
     318             :     {
     319           9 :         L_subfr = L_SUBFR16k;
     320             :     }
     321             : 
     322           9 :     if ( T0 < 2 * L_subfr )
     323             :     {
     324           9 :         onset_len = 2 * L_subfr;
     325             :     }
     326             :     else
     327             :     {
     328           0 :         onset_len = T0;
     329             :     }
     330             : 
     331             : 
     332           9 :     P0 = puls_pos;
     333             : 
     334           9 :     if ( P0 < 0 )
     335             :     {
     336           0 :         sign = 1;
     337           0 :         P0 = -P0;
     338             :     }
     339             : 
     340           9 :     if ( P0 > PIT_MAX && L_frame == L_FRAME )
     341             :     {
     342           0 :         P0 = PIT_MAX; /* Should never be the case, however... */
     343             :     }
     344           9 :     else if ( P0 > PIT16k_MAX && L_frame == L_FRAME16k )
     345             :     {
     346           0 :         P0 = PIT16k_MAX; /* Should never be the case, however... */
     347             :     }
     348           9 :     set_f( exc_tmp, 0, L_frame + MODE1_L_FIR_FER ); /* Reset excitation vector */
     349             : 
     350             :     /*--------------------------------------------*
     351             :      * Find LP filter impulse response energy
     352             :      *--------------------------------------------*/
     353             : 
     354           9 :     set_f( h1, 0, L_subfr ); /* Find the impulse response */
     355           9 :     set_f( mem, 0, M );
     356           9 :     h1[0] = 1.0f;
     357           9 :     syn_filt( Aq, M, h1, h1, L_subfr, mem, 0 );
     358           9 :     enr_LP = dotp( h1, h1, L_subfr ) + 0.01f; /* Find the impulse response energy */
     359             : 
     360             :     /*------------------------------------------------------------------------------------------*
     361             :      * Construct the harmonic part as a train of low-pass filtered pulses
     362             :      *------------------------------------------------------------------------------------------*/
     363             : 
     364           9 :     pt_exc = exc_tmp + L_frame - 1 - MODE1_L_FIR_FER / 2 - P0; /* beginning of the 1st pulse */
     365           9 :     pt_end = exc_tmp + onset_len;
     366             : 
     367           9 :     len = (int16_t) ( pt_exc - pt_end );
     368           9 :     if ( len > MODE1_L_FIR_FER )
     369             :     {
     370           9 :         len = MODE1_L_FIR_FER;
     371             :     }
     372           9 :     if ( !sign )
     373             :     {
     374          54 :         for ( i = 0; i < len; i++ )
     375             :         {
     376             :             /* The filter response would have E=1 in full band. */
     377          45 :             pt_exc[i] += h_low[i]; /* As it is lp filtered, the E is somewhat lower */
     378             :         }
     379             :     }
     380             :     else
     381             :     {
     382           0 :         for ( i = 0; i < len; i++ )
     383             :         {
     384             :             /* The filter response would have E=1 in full band. */
     385           0 :             pt_exc[i] -= h_low[i]; /* As it is lp filtered, the E is somewhat lower */
     386             :         }
     387             :     }
     388             : 
     389           9 :     gain = (float) sqrt( 1.5 * enr_q / enr_LP ); /* divide by LP filter E, scale by transmitted E */
     390           9 :     gain *= 0.96f;
     391        2889 :     for ( i = 0; i < L_frame; i++ )
     392             :     {
     393        2880 :         exc_tmp[i] *= gain;
     394             :     }
     395             : 
     396           9 :     mvr2r( &exc_tmp[L_frame - L_EXC_MEM], exc, L_EXC_MEM );
     397             : 
     398           9 :     return;
     399             : }
     400             : 
     401           0 : int16_t FEC_enhACB(
     402             :     const int16_t L_frame,      /* i  : frame length                                                              */
     403             :     const int16_t last_L_frame, /* i  : frame length of last frame                                                */
     404             :     float *exc_io,              /* i/o: adaptive codebook memory                                                  */
     405             :     const int16_t new_pit,      /* i  : decoded first frame pitch                                                 */
     406             :     const int16_t puls_pos,     /* i  : decoder position of the last glottal pulses decoded in the previous frame */
     407             :     const float bfi_pitch       /* i  : pitch used for concealment                                                */
     408             : )
     409             : {
     410             :     int16_t Tc, P0, sign, pit_search;
     411             :     int16_t Tlist[10], Terr, diff_pit, dist_Plast;
     412             :     float ftmp;
     413             :     float exc[L_FRAME16k + L_SUBFR];
     414           0 :     int16_t do_WI = 1;
     415             : 
     416           0 :     set_f( exc, 0.0f, L_FRAME16k - L_EXC_MEM );
     417           0 :     set_f( exc + L_FRAME16k, 0.0f, L_SUBFR );
     418           0 :     mvr2r( exc_io, exc + L_FRAME16k - L_EXC_MEM, L_EXC_MEM );
     419             : 
     420           0 :     Tc = (int16_t) bfi_pitch;
     421           0 :     mvr2r( exc + L_FRAME16k - Tc, exc + L_FRAME16k, L_SUBFR );
     422             : 
     423             :     /*------------------------------------------------------------
     424             :      * Decode phase information transmitted in the bitstream
     425             :      * (The position of the absolute maximum glottal pulse from
     426             :      * the end of the frame and its sign)
     427             :      *------------------------------------------------------------*/
     428             : 
     429           0 :     P0 = puls_pos;
     430           0 :     sign = 0;
     431           0 :     if ( P0 < 0 )
     432             :     {
     433           0 :         sign = 1;
     434           0 :         P0 = -P0;
     435             :     }
     436             : 
     437           0 :     if ( L_frame == L_FRAME )
     438             :     {
     439           0 :         if ( P0 > PIT_MAX )
     440             :         {
     441           0 :             P0 = PIT_MAX; /* Should never be the case, however... */
     442             :         }
     443             :     }
     444             :     else /* L_frame == L_FRAME16k */
     445             :     {
     446           0 :         if ( P0 > PIT16k_MAX )
     447             :         {
     448           0 :             P0 = PIT16k_MAX; /* Should never be the case, however... */
     449             :         }
     450             :     }
     451             : 
     452             :     /*----------------------------------------------------------------------------------
     453             :      * Find the position of the first the maximum(minimum) lp_filtered pulse
     454             :      * <----- Mem --->|<--------------------- L_frame ------------>|<----- L_SUBFR --->|
     455             :      *                |<-------pit_search---->                     |                   |
     456             :      *----------------------------------------------------------------------------------*/
     457             : 
     458           0 :     pit_search = Tc;
     459             : 
     460           0 :     Tlist[0] = findpulse( L_frame, exc + L_frame - pit_search, pit_search, DEC, &sign );
     461             : 
     462           0 :     Terr = (int16_t) abs( pit_search - Tlist[0] - P0 );
     463             : 
     464           0 :     dist_Plast = Tc - Tlist[0];
     465             : 
     466           0 :     Tlist[1] = findpulse( L_frame, exc + L_frame - pit_search, pit_search + L_SUBFR, DEC, &sign );
     467             : 
     468           0 :     if ( Terr > abs( Tlist[1] - Tc + P0 ) )
     469             :     {
     470           0 :         dist_Plast = Tc - Tlist[1];
     471           0 :         Terr = (int16_t) abs( Tlist[1] - Tc + P0 );
     472             :     }
     473             : 
     474           0 :     diff_pit = (int16_t) abs( new_pit - Tc );
     475           0 :     ftmp = (float) (int16_t) ( (float) L_frame / (float) Tc + 0.5 );
     476             : 
     477           0 :     if ( Terr <= ftmp * diff_pit && Terr != 0 /* If Terr = 0, no resynchronization required */
     478           0 :          && Terr < L_SUBFR )                  /* prevent catastrophy search */
     479             :     {
     480             :         /* perform excitation resynchronization here */
     481           0 :         do_WI = FEC_synchro_exc( L_frame, exc, P0, dist_Plast, Tc );
     482           0 :         mvr2r( exc + L_FRAME16k - L_EXC_MEM, exc_io, L_EXC_MEM );
     483             :     }
     484             :     else
     485             :     {
     486           0 :         do_WI = 0;
     487             :     }
     488             : 
     489           0 :     if ( last_L_frame != L_FRAME16k )
     490             :     {
     491             :         /* This is essential in case of bitrate switching + FEC*/
     492           0 :         do_WI = 0;
     493             :     }
     494             : 
     495           0 :     return do_WI;
     496             : }

Generated by: LCOV version 1.14