LCOV - code coverage report
Current view: top level - lib_dec - er_sync_exc.c (source / functions) Hit Total Coverage
Test: Coverage on main -- short test vectors @ 6c9ddc4024a9c0e1ecb8f643f114a84a0e26ec6b Lines: 99 101 98.0 %
Date: 2025-05-23 08:37:30 Functions: 4 4 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             : /*====================================================================================
      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 <assert.h>
      38             : #include <stdint.h>
      39             : #include "options.h"
      40             : #include <math.h>
      41             : #include "prot.h"
      42             : #include "cnst.h"
      43             : #include "wmc_auto.h"
      44             : 
      45             : /*-------------------------------------------------------------------*
      46             :  * Local constants
      47             :  *--------------------------------------------------------------------*/
      48             : 
      49             : #define NB_PULSES_MAX 15
      50             : 
      51             : 
      52             : /*-------------------------------------------------------------------*
      53             :  * GetMinimumPosition()
      54             :  *
      55             :  * Get the location of the minimum energy in the given signal.
      56             :  *--------------------------------------------------------------------*/
      57             : 
      58             : /*! r: Index of the position of the minimum energy, that is the position i where filter(x[i-filterLength/2],...,x[i+(filterLength-filterLength/2)-1]) is at maximum. */
      59       10014 : static int16_t GetMinimumPosition(
      60             :     const float *x,       /* i  : input signal                                                */
      61             :     const int16_t length, /* i  : length of the filter length used for the energy calculation */
      62             :     int16_t filterLength  /* i  : length of the filter length used for the energy calculation */
      63             : )
      64             : {
      65             :     int16_t iMinEnergyPos, center, i;
      66             :     float energy;
      67             : 
      68       10014 :     filterLength = min( filterLength, length );
      69       10014 :     center = filterLength / 2;
      70       10014 :     iMinEnergyPos = center;
      71       10014 :     if ( filterLength > 0 )
      72             :     {
      73        7203 :         energy = 0;
      74        7203 :         center += 1; /* To avoid adding 1 in the loop */
      75     1376376 :         for ( i = 0; i < length - filterLength; i++ )
      76             :         {
      77     1369173 :             energy -= x[i] * x[i];
      78     1369173 :             energy += x[i + filterLength] * x[i + filterLength];
      79     1369173 :             if ( energy < 0 )
      80             :             {
      81       49575 :                 energy = 0;
      82       49575 :                 iMinEnergyPos = i + center;
      83             :             }
      84             :         }
      85             :     }
      86             : 
      87       10014 :     return iMinEnergyPos;
      88             : }
      89             : 
      90             : 
      91        3096 : static void AddSamples(
      92             :     const float *old_exc,
      93             :     float *new_exc,
      94             :     const int16_t L_frame,
      95             :     const int16_t n_samples_to_add,
      96             :     const int16_t min_pos[],
      97             :     const int16_t points_by_pos[],
      98             :     const int16_t nb_min )
      99             : {
     100             :     float *pt_dest;
     101             :     const float *pt_src;
     102             :     int16_t last_min_pos, i, j;
     103             : 
     104        3096 :     pt_dest = new_exc;
     105        3096 :     pt_src = old_exc;
     106        3096 :     last_min_pos = 0;
     107       16722 :     for ( i = 0; i < nb_min; i++ )
     108             :     {
     109             :         float ftmp;
     110             : 
     111             :         /* Copy section */
     112     2021742 :         for ( j = min_pos[i] - last_min_pos; j > 0; j-- )
     113             :         {
     114     2008116 :             *pt_dest++ = *pt_src++;
     115             :         }
     116             : 
     117             :         /* Add some samples */
     118       13626 :         ftmp = -( *pt_src / 20 );
     119       34023 :         for ( j = 0; j < points_by_pos[i]; j++ )
     120             :         {
     121       20397 :             *pt_dest++ = ftmp;
     122       20397 :             ftmp = -ftmp;
     123             :         }
     124             : 
     125             :         /* Prepare for the next loop iteration */
     126       13626 :         last_min_pos = min_pos[i];
     127             :     }
     128             : 
     129             :     /* Copy remaining length */
     130      196407 :     for ( j = L_frame - n_samples_to_add - last_min_pos; j > 0; j-- )
     131             :     {
     132      193311 :         *pt_dest++ = *pt_src++;
     133             :     }
     134             : 
     135        3096 :     return;
     136             : }
     137             : 
     138             : 
     139        1905 : static void RemoveSamples(
     140             :     const float *old_exc,
     141             :     float *new_exc,
     142             :     const int16_t L_frame,
     143             :     const int16_t n_samples_to_add,
     144             :     const int16_t min_pos[],
     145             :     const int16_t points_by_pos[],
     146             :     const int16_t nb_min )
     147             : {
     148             :     float *pt_dest;
     149             :     const float *pt_src;
     150             :     int16_t last_min_pos, i, j;
     151             : 
     152        1905 :     pt_dest = new_exc + L_frame;
     153        1905 :     last_min_pos = L_frame - n_samples_to_add;
     154       11262 :     for ( i = nb_min - 1; i >= 0; i-- )
     155             :     {
     156             :         /* Compute len to copy */
     157             :         /* Copy section, removing some samples */
     158        9357 :         pt_src = old_exc + last_min_pos;
     159     1309866 :         for ( j = last_min_pos - ( min_pos[i] + points_by_pos[i] ); j > 0; j-- )
     160             :         {
     161     1300509 :             *--pt_dest = *--pt_src;
     162             :         }
     163             : 
     164             :         /* Prepare for the next loop iteration */
     165        9357 :         last_min_pos = min_pos[i];
     166             :     }
     167             : 
     168             :     /* Copy remaining length */
     169        1905 :     pt_src = old_exc + last_min_pos;
     170       90132 :     for ( j = last_min_pos; j > 0; j-- )
     171             :     {
     172       88227 :         *--pt_dest = *--pt_src;
     173             :     }
     174             : 
     175        1905 :     return;
     176             : }
     177             : 
     178             : 
     179             : /*-------------------------------------------------------------------*
     180             :  * PulseResynchronization()
     181             :  *
     182             :  * Resynchronize glottal pulse positions of the signal in src_exc and store it in dst_exc
     183             :  *--------------------------------------------------------------------*/
     184             : 
     185        5001 : void PulseResynchronization(
     186             :     const float *src_exc,       /* i  : Input excitation buffer                 */
     187             :     float *dst_exc,             /* o  : output excitation buffer                */
     188             :     const int16_t nFrameLength, /* i  : frame length                            */
     189             :     const int16_t nSubframes,   /* i  : Number of subframes                     */
     190             :     const float pitchStart,     /* i  : Pitch at the end of the last frame      */
     191             :     const float pitchEnd        /* i  : Pitch at the end of the current  frame  */
     192             : )
     193             : {
     194             :     int16_t T0, i, k;
     195             :     float pitchDelta, samplesDelta, perCycleDeltaDelta, cycleDelta, freqStart, fractionalLeft, absPitchDiff;
     196             :     int16_t roundedPitchStart, nSamplesDelta, nSamplesDeltaRemain, iMinPos1, iMinPos[NB_PULSES_MAX + 1], iDeltaSamples[NB_PULSES_MAX + 1], maxDeltaSamples, roundedCycleDelta;
     197             : 
     198        5001 :     assert( ( nFrameLength > 0 ) && ( nFrameLength > pitchStart ) && ( nSubframes > 1 ) && ( nSubframes <= 5 ) && ( nFrameLength % nSubframes == 0 ) && ( pitchStart > 0 ) && ( pitchEnd > 0 ) && ( pitchEnd / pitchStart > 1 - 2.0f / ( nSubframes + 1 ) ) && ( src_exc != NULL ) && ( dst_exc != NULL ) && ( src_exc < dst_exc ) );
     199             : 
     200        5001 :     pitchDelta = ( pitchEnd - pitchStart ) / nSubframes;
     201        5001 :     roundedPitchStart = (int16_t) ( pitchStart + 0.5f );
     202        5001 :     freqStart = 1.0f / roundedPitchStart;
     203             : 
     204             :     /* Calculate number of samples to be removed (if negative) or added (if positive) */
     205        5001 :     samplesDelta = 0.5f * pitchDelta * nFrameLength * ( nSubframes + 1 ) * freqStart;
     206        5001 :     samplesDelta -= nFrameLength * ( 1.0f - pitchStart * freqStart );
     207             : 
     208             :     /* To have enough samples in the buffer of length nFrameLength*(nSubframes+1)/nSubframes, pitchEnd/pitchEnd must be bigger than (nSubframes-1)/(nSubframes+1)=1-2/(nSubframes+1) */
     209             :     /* Thus nSubframes must be bigger than 1 */
     210        5001 :     nSamplesDelta = (int16_t) floor( samplesDelta + 0.5f );
     211        5001 :     nSamplesDeltaRemain = (int16_t) abs( nSamplesDelta );
     212             : 
     213             :     /* Find the location of the glottal pulse */
     214        5001 :     T0 = maximumAbs( src_exc, roundedPitchStart, NULL );
     215             : 
     216             :     /* Get the index of the last pulse in the resynchronized frame */
     217        5001 :     k = (int16_t) ceil( ( nFrameLength - nSamplesDelta - T0 ) * freqStart - 1 );
     218        5001 :     if ( ( k >= 0 ) && ( k + 1 <= NB_PULSES_MAX ) )
     219             :     {
     220        5001 :         absPitchDiff = (float) fabs( roundedPitchStart - pitchEnd );
     221             : 
     222             :         /* Calculate the delta of the samples to be added/removed between consecutive cycles */
     223        5001 :         perCycleDeltaDelta = ( absPitchDiff * ( nFrameLength - samplesDelta ) - (float) fabs( samplesDelta ) * roundedPitchStart ) / ( ( k + 1 ) * ( T0 + 0.5f * k * roundedPitchStart ) );
     224             : 
     225             :         /* Calculate the integer number of samples to be added/removed in each pitch cycle */
     226        5001 :         cycleDelta = max( 0, ( absPitchDiff - ( k + 1 ) * perCycleDeltaDelta ) * T0 * freqStart );
     227        5001 :         roundedCycleDelta = (int16_t) ( cycleDelta );
     228        5001 :         iDeltaSamples[0] = roundedCycleDelta;
     229        5001 :         fractionalLeft = cycleDelta - roundedCycleDelta;
     230        5001 :         nSamplesDeltaRemain -= roundedCycleDelta;
     231       17982 :         for ( i = 1; i <= k; i++ )
     232             :         {
     233       12981 :             cycleDelta = ( absPitchDiff - ( k + 1 - i ) * perCycleDeltaDelta ) + fractionalLeft;
     234       12981 :             cycleDelta = max( 0, cycleDelta );
     235             : 
     236             :             /* Make sure that the number of samples increases */
     237       12981 :             if ( roundedCycleDelta > cycleDelta )
     238             :             {
     239        1014 :                 iDeltaSamples[i] = roundedCycleDelta;
     240        1014 :                 roundedCycleDelta = (int16_t) ( cycleDelta );
     241        1014 :                 iDeltaSamples[i - 1] = roundedCycleDelta;
     242             :             }
     243             :             else
     244             :             {
     245       11967 :                 roundedCycleDelta = (int16_t) ( cycleDelta );
     246       11967 :                 iDeltaSamples[i] = roundedCycleDelta;
     247             :             }
     248       12981 :             fractionalLeft = cycleDelta - roundedCycleDelta;
     249       12981 :             nSamplesDeltaRemain -= roundedCycleDelta;
     250             :         }
     251             : 
     252        5001 :         iDeltaSamples[k + 1] = max( 0, nSamplesDeltaRemain );
     253        5001 :         maxDeltaSamples = max( iDeltaSamples[k], iDeltaSamples[k + 1] );
     254             : 
     255             :         /* Find the location of the minimum energy between the first two pulses */
     256        5001 :         iMinPos1 = T0 + GetMinimumPosition( src_exc + T0, min( roundedPitchStart, ( nSubframes + 1 ) * nFrameLength / nSubframes - T0 ), maxDeltaSamples );
     257        5001 :         if ( nSamplesDelta < 0 )
     258             :         {
     259             :             /* Find the location of the minimum energy before the first pulse */
     260        1905 :             if ( iMinPos1 > roundedPitchStart + iDeltaSamples[0] / 2 )
     261             :             {
     262         954 :                 iMinPos[0] = iMinPos1 - roundedPitchStart - iDeltaSamples[0] / 2;
     263             :             }
     264             :             else
     265             :             {
     266         951 :                 iMinPos[0] = GetMinimumPosition( src_exc, T0, iDeltaSamples[0] ) - iDeltaSamples[0] / 2;
     267             :             }
     268             : 
     269             :             /* Find the location of the minimum energy between the pulses */
     270        7452 :             for ( i = 1; i <= k; i++ )
     271             :             {
     272        5547 :                 iMinPos[i] = iMinPos1 + ( i - 1 ) * roundedPitchStart - iDeltaSamples[i] / 2;
     273             :             }
     274             : 
     275             :             /* Find the location of the minimum energy after the last pulse */
     276        1905 :             if ( iMinPos1 + k * roundedPitchStart + iDeltaSamples[k + 1] - iDeltaSamples[k + 1] / 2 < nFrameLength - nSamplesDelta )
     277             :             {
     278         891 :                 iMinPos[k + 1] = iMinPos1 + k * roundedPitchStart - iDeltaSamples[k + 1] / 2;
     279             :             }
     280             :             else
     281             :             {
     282        1014 :                 iMinPos[k + 1] = T0 + k * roundedPitchStart + GetMinimumPosition( src_exc + T0 + k * roundedPitchStart, nFrameLength - nSamplesDelta - ( T0 + k * roundedPitchStart ), iDeltaSamples[k + 1] ) - iDeltaSamples[k + 1] / 2;
     283             :             }
     284             : 
     285        1905 :             if ( iMinPos[k + 1] + iDeltaSamples[k + 1] > nFrameLength - nSamplesDelta )
     286             :             {
     287           0 :                 iDeltaSamples[k] += iMinPos[k + 1] + iDeltaSamples[k + 1] - ( nFrameLength - nSamplesDelta );
     288           0 :                 iDeltaSamples[k + 1] = nFrameLength - nSamplesDelta - iMinPos[k + 1];
     289             :             }
     290             : 
     291             :             /* Remove samples at the given positions */
     292        1905 :             RemoveSamples( src_exc, dst_exc, nFrameLength, nSamplesDelta, iMinPos, iDeltaSamples, k + 2 );
     293             :         }
     294             :         else
     295             :         {
     296             :             /* Find the location of the minimum energy before the first pulse */
     297        3096 :             if ( iMinPos1 > roundedPitchStart )
     298             :             {
     299        1659 :                 iMinPos[0] = iMinPos1 - roundedPitchStart;
     300             :             }
     301             :             else
     302             :             {
     303        1437 :                 iMinPos[0] = GetMinimumPosition( src_exc, T0, iDeltaSamples[0] );
     304             :             }
     305             : 
     306             :             /* Find the location of the minimum energy between the pulses */
     307       10530 :             for ( i = 1; i <= k; i++ )
     308             :             {
     309        7434 :                 iMinPos[i] = iMinPos1;
     310        7434 :                 iMinPos1 += roundedPitchStart;
     311             :             }
     312             : 
     313             :             /* Find the location of the minimum energy after the last pulse */
     314        3096 :             if ( iMinPos1 < nFrameLength - nSamplesDelta )
     315             :             {
     316        1485 :                 iMinPos[k + 1] = iMinPos1;
     317             :             }
     318             :             else
     319             :             {
     320        1611 :                 iMinPos[k + 1] = T0 + k * roundedPitchStart + GetMinimumPosition( src_exc + T0 + k * roundedPitchStart, nFrameLength - nSamplesDelta - ( T0 + k * roundedPitchStart ), iDeltaSamples[k + 1] );
     321             :             }
     322             : 
     323        3096 :             if ( iMinPos[k + 1] + iDeltaSamples[k + 1] > nFrameLength - nSamplesDelta )
     324             :             {
     325          57 :                 iDeltaSamples[k] += iMinPos[k + 1] + iDeltaSamples[k + 1] - ( nFrameLength - nSamplesDelta );
     326          57 :                 iDeltaSamples[k + 1] = nFrameLength - nSamplesDelta - iMinPos[k + 1];
     327             :             }
     328             : 
     329             :             /* Add samples at the given positions */
     330        3096 :             AddSamples( src_exc, dst_exc, nFrameLength, nSamplesDelta, iMinPos, iDeltaSamples, k + 2 );
     331             :         }
     332             :     }
     333             : 
     334        5001 :     return;
     335             : }

Generated by: LCOV version 1.14