LCOV - code coverage report
Current view: top level - lib_enc - ari_hm_enc_fx.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 302 302 100.0 %
Date: 2025-05-03 01:55:50 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /*====================================================================================
       2             :     EVS Codec 3GPP TS26.452 Aug 12, 2021. Version 16.3.0
       3             :   ====================================================================================*/
       4             : 
       5             : 
       6             : #include <stdint.h>
       7             : #include <assert.h>
       8             : #include "options.h"
       9             : #include "cnst.h"
      10             : #include "basop_util.h"
      11             : #include "rom_com.h"
      12             : #include "rom_enc.h"
      13             : #include "prot_fx.h"
      14             : #include "prot_fx_enc.h" /* Function prototypes                    */
      15             : 
      16             : /*-------------------------------------------------------------------*
      17             :  * EncodeIndex_fx()
      18             :  *
      19             :  *
      20             :  *-------------------------------------------------------------------*/
      21             : 
      22             : /*ari_hm_enc.c*/
      23             : /* Q13 format */
      24             : const Word16 kLowPeriodicityThr_fx[2] = { 4096 /*0.5f Q13*/, 1638 /*0.2f Q13*/ };
      25             : 
      26          55 : Word16 EncodeIndex_fx(
      27             :     const Word16 Bandwidth,
      28             :     Word16 PeriodicityIndex,
      29             :     BSTR_ENC_HANDLE hBst /* i/o: bitstream handle            */
      30             : )
      31             : {
      32             :     Word16 NumRatioBitsBwLtpIndx;
      33             : 
      34          55 :     IF( s_and( PeriodicityIndex, kLtpHmFlag ) != 0 )
      35             :     {
      36          45 :         Word16 LtpPitchIndex = shr( PeriodicityIndex, 9 );
      37          45 :         assert( 0 <= LtpPitchIndex && LtpPitchIndex <= 16 );
      38             : 
      39          45 :         PeriodicityIndex = sub( PeriodicityIndex, 1 );
      40          45 :         assert( ( PeriodicityIndex & 0xff ) < ( 1 << NumRatioBits[Bandwidth][LtpPitchIndex] ) );
      41             : 
      42          45 :         NumRatioBitsBwLtpIndx = NumRatioBits[Bandwidth][LtpPitchIndex];
      43          45 :         move16();
      44             : 
      45          45 :         push_next_indice( hBst, s_and( PeriodicityIndex, 0xff ), NumRatioBitsBwLtpIndx );
      46          45 :         return NumRatioBitsBwLtpIndx;
      47             :     }
      48             :     ELSE
      49             :     {
      50          10 :         push_next_indice( hBst, PeriodicityIndex, 8 );
      51          10 :         return 8;
      52             :     }
      53             : }
      54       19655 : Word16 EncodeIndex_ivas_fx(
      55             :     const Word16 Bandwidth,
      56             :     Word16 PeriodicityIndex,
      57             :     BSTR_ENC_HANDLE hBst /* i/o: bitstream handle            */
      58             : )
      59             : {
      60             :     Word16 NumRatioBitsBwLtpIndx;
      61             : 
      62       19655 :     IF( s_and( PeriodicityIndex, kLtpHmFlag ) != 0 )
      63             :     {
      64       10330 :         Word16 LtpPitchIndex = shr( PeriodicityIndex, 9 );
      65       10330 :         assert( 0 <= LtpPitchIndex && LtpPitchIndex <= 16 );
      66             : 
      67       10330 :         PeriodicityIndex = sub( PeriodicityIndex, 1 );
      68       10330 :         assert( ( PeriodicityIndex & 0xff ) < ( 1 << NumRatioBits[Bandwidth][LtpPitchIndex] ) );
      69             : 
      70       10330 :         NumRatioBitsBwLtpIndx = NumRatioBits[Bandwidth][LtpPitchIndex];
      71       10330 :         move16();
      72             : 
      73       10330 :         push_next_indice( hBst, s_and( PeriodicityIndex, 0xff ), NumRatioBitsBwLtpIndx );
      74       10330 :         return NumRatioBitsBwLtpIndx;
      75             :     }
      76             :     ELSE
      77             :     {
      78        9325 :         push_next_indice( hBst, PeriodicityIndex, 8 );
      79        9325 :         return 8;
      80             :     }
      81             : }
      82             : /*-------------------------------------------------------------------*
      83             :  * SearchPeriodicityIndex_Single()
      84             :  *
      85             :  *
      86             :  *-------------------------------------------------------------------*/
      87    17459453 : static Word16 SearchPeriodicityIndex_Single(
      88             :     const Word16 AbsMdct3[], // Qx
      89             :     const Word16 NumToConsider,
      90             :     const Word32 Lag,
      91             :     const Word16 FractionalResolution )
      92             : {
      93             :     Word16 HighestMultiplier;
      94             :     Word32 AbsMeanCurrent3; /* Mean for BucketWidth == 3 */
      95             :     Word32 Limit, OldIndex, i;
      96             :     Word16 Result, tmp1, tmp2;
      97             : 
      98             : 
      99    17459453 :     Limit = L_deposit_l( sub( NumToConsider, 1 ) );
     100    17459453 :     Limit = L_shl( Limit, FractionalResolution );
     101    17459453 :     AbsMeanCurrent3 = L_deposit_l( 0 );
     102    17459453 :     HighestMultiplier = 0;
     103    17459453 :     move16();
     104             : 
     105   754211746 :     FOR( i = Lag; i < Limit; i += Lag )
     106             :     {
     107   736752293 :         OldIndex = L_shr( i, FractionalResolution );
     108   736752293 :         tmp1 = Weight[s_min( HighestMultiplier, 85 )];
     109   736752293 :         move16();
     110   736752293 :         AbsMeanCurrent3 = L_add( AbsMeanCurrent3, L_shr( L_mult( AbsMdct3[OldIndex], tmp1 ), 7 ) );
     111   736752293 :         HighestMultiplier = add( HighestMultiplier, 1 );
     112             :     }
     113             : 
     114    17459453 :     tmp1 = sub( norm_l( AbsMeanCurrent3 ), 1 );
     115    17459453 :     tmp2 = norm_s( HighestMultiplier );
     116    17459453 :     Result = div_s( round_fx( L_shl( AbsMeanCurrent3, tmp1 ) ), s_max( shl( HighestMultiplier, tmp2 ), 0x4000 ) );
     117    17459453 :     if ( HighestMultiplier == 0 )
     118             :     {
     119        8982 :         tmp2 = 14 + 16;
     120        8982 :         move16();
     121             :     }
     122    17459453 :     Result = shr( Result, s_min( 15, sub( sub( tmp1, tmp2 ), 7 - 15 ) ) );
     123             : 
     124    17459453 :     return Result;
     125             : }
     126             : /*-------------------------------------------------------------------*
     127             :  * SearchPeriodicityIndex_Range()
     128             :  *
     129             :  *
     130             :  *-------------------------------------------------------------------*/
     131      738731 : static void SearchPeriodicityIndex_Range(
     132             :     const Word16 AbsMdct3[], // Qx
     133             :     const Word16 NumToConsider,
     134             :     const Word16 Lo,
     135             :     const Word16 Hi,
     136             :     const Word16 FractionalResolution,
     137             :     const Word16 Adj,
     138             :     const Word16 Spacing,
     139             :     Word16 *PeriodicityIndex,
     140             :     Word16 *Score // Q0
     141             : )
     142             : {
     143             :     Word16 Index, BestIndex;
     144             :     Word16 CurrentScore, BestScore;
     145             :     Word16 B;
     146             : 
     147      738731 :     BestScore = -1;
     148      738731 :     move16();
     149      738731 :     BestIndex = 0;
     150      738731 :     move16();
     151             : 
     152    15602091 :     FOR( Index = Lo; Index < Hi; Index += Spacing )
     153             :     {
     154    14863360 :         CurrentScore = SearchPeriodicityIndex_Single(
     155             :             AbsMdct3,
     156             :             NumToConsider,
     157    14863360 :             add( Index, Adj ),
     158             :             FractionalResolution );
     159             : 
     160    14863360 :         if ( GT_16( CurrentScore, BestScore ) )
     161             :         {
     162     2254170 :             BestIndex = Index;
     163     2254170 :             move16();
     164             :         }
     165    14863360 :         BestScore = s_max( BestScore, CurrentScore );
     166             :     }
     167             : 
     168      738731 :     if ( GT_16( BestScore, *Score ) )
     169             :     {
     170      193997 :         *PeriodicityIndex = BestIndex;
     171      193997 :         move16();
     172             :     }
     173      738731 :     BestScore = s_max( BestScore, *Score );
     174             : 
     175      738731 :     B = sub( BestIndex, shr( Spacing, 1 ) );
     176      738731 :     B = s_max( Lo, B );
     177             : 
     178     1385693 :     FOR( Index = B; Index < BestIndex; ++Index )
     179             :     {
     180      646962 :         CurrentScore = SearchPeriodicityIndex_Single(
     181             :             AbsMdct3,
     182             :             NumToConsider,
     183      646962 :             add( Index, Adj ),
     184             :             FractionalResolution );
     185             : 
     186      646962 :         if ( GT_16( CurrentScore, BestScore ) )
     187             :         {
     188       39911 :             *PeriodicityIndex = Index;
     189       39911 :             move16();
     190             :         }
     191      646962 :         BestScore = s_max( BestScore, CurrentScore );
     192             :     }
     193             : 
     194      738731 :     B = add( BestIndex, shr( Spacing, 1 ) );
     195             : 
     196     1630979 :     FOR( Index = BestIndex + 1; Index <= B; ++Index )
     197             :     {
     198      892248 :         CurrentScore = SearchPeriodicityIndex_Single(
     199             :             AbsMdct3,
     200             :             NumToConsider,
     201      892248 :             add( Index, Adj ),
     202             :             FractionalResolution );
     203             : 
     204      892248 :         if ( GT_16( CurrentScore, BestScore ) )
     205             :         {
     206       92730 :             *PeriodicityIndex = Index;
     207       92730 :             move16();
     208             :         }
     209      892248 :         BestScore = s_max( BestScore, CurrentScore );
     210             :     }
     211             : 
     212      738731 :     *Score = BestScore;
     213      738731 :     move16();
     214      738731 : }
     215             : 
     216             : /*-------------------------------------------------------------------*
     217             :  * SearchPeriodicityIndex_fx()
     218             :  *
     219             :  *
     220             :  *-------------------------------------------------------------------*/
     221      194945 : Word16 SearchPeriodicityIndex_fx(
     222             :     const Word32 Mdct[],           /* i  : Coefficients, Mdct[0..NumCoeffs-1]                      */
     223             :     const Word32 UnfilteredMdct[], /* i  : Unfiltered coefficients, UnfilteredMdct[0..NumCoeffs-1] */
     224             :     Word16 NumToConsider,          /* i  : Number of coefficients                                  */
     225             :     const Word16 TargetBits,       /* i  : Target bit budget (excl. Done flag)                     */
     226             :     const Word16 LtpPitchLag,      /* i  : TCX-LTP pitch                                           */
     227             :     const Word16 LtpGain,          /* i  : LTP gain                                           Q15     */
     228             :     Word16 *RelativeScore          /* o  : Energy concentration factor                      (2Q13) */
     229             : )
     230             : {
     231             :     Word16 AbsMdct3[MAX_LENGTH];
     232             :     Word32 A, B, C;
     233             :     Word16 i;
     234             :     Word16 MaxAt;
     235             :     Word16 Score, CurrentScore;
     236             :     Word16 PeriodicityIndex;
     237             :     Word32 AbsTotal; /* 16Q15 */
     238             :     Word16 Multiplier;
     239             :     Word16 LtpPitchIndex;
     240             :     Word8 Bandwidth;
     241             :     Word32 Lag;
     242             :     Word16 s, tmp, tmp2, tmp3;
     243             :     Word32 tmp32;
     244             : #ifdef BASOP_NOGLOB_DECLARE_LOCAL
     245      194945 :     Flag Overflow = 0;
     246      194945 :     move32();
     247             : #endif
     248             : 
     249             :     /* Debug init (not instrumented) */
     250      194945 :     C = -3000;
     251      194945 :     move32();
     252      194945 :     PeriodicityIndex = 0;
     253      194945 :     move16();
     254      194945 :     Score = -1;
     255      194945 :     move16();
     256             : 
     257      194945 :     s = sub( Find_Max_Norm32( Mdct, NumToConsider ), 2 );
     258             : 
     259      194945 :     A = L_shl( L_abs( Mdct[0] ), s );
     260      194945 :     B = L_shl( L_abs( Mdct[1] ), s );
     261             : 
     262      194945 :     tmp = sub( NumToConsider, 3 );
     263    53565240 :     FOR( i = 1; i < tmp; i += 3 )
     264             :     {
     265    53370295 :         C = L_shl( L_abs( Mdct[i + 1] ), s );
     266    53370295 :         AbsMdct3[i] = round_fx( L_add( L_add( A, B ), C ) );
     267    53370295 :         move16();
     268             : 
     269    53370295 :         A = L_shl( L_abs( Mdct[i + 2] ), s );
     270    53370295 :         AbsMdct3[i + 1] = round_fx( L_add( L_add( A, B ), C ) );
     271    53370295 :         move16();
     272             : 
     273    53370295 :         B = L_shl( L_abs( Mdct[i + 3] ), s );
     274    53370295 :         AbsMdct3[i + 2] = round_fx( L_add( L_add( A, B ), C ) );
     275    53370295 :         move16();
     276             :     }
     277             : 
     278      194945 :     IF( LT_16( i, sub( NumToConsider, 1 ) ) )
     279             :     {
     280      186776 :         C = L_shl( L_abs( Mdct[i + 1] ), s );
     281      186776 :         AbsMdct3[i] = round_fx( L_add( L_add( A, B ), C ) );
     282      186776 :         move16();
     283             :     }
     284             : 
     285      194945 :     IF( LT_16( i, sub( NumToConsider, 2 ) ) )
     286             :     {
     287       61889 :         A = L_shl( L_abs( Mdct[i + 2] ), s );
     288       61889 :         assert( C != -3000 );
     289       61889 :         AbsMdct3[i + 1] = round_fx( L_add( L_add( A, B ), C ) );
     290       61889 :         move16();
     291             :     }
     292             : 
     293      194945 :     AbsTotal = L_deposit_l( 0 );
     294      194945 :     IF( UnfilteredMdct != NULL )
     295             :     {
     296     8463009 :         FOR( i = 0; i < NumToConsider; ++i )
     297             :         {
     298     8449280 :             AbsTotal = L_add( AbsTotal, L_shr( L_abs( UnfilteredMdct[i] ), 16 ) );
     299             :         }
     300             :         /* balance difference between filtered and unfiltered mdct samples */
     301       13729 :         AbsTotal = L_shr( AbsTotal, sub( 4, s ) );
     302             :     }
     303             :     ELSE
     304             :     {
     305      181216 :         tmp = sub( NumToConsider, 1 );
     306    50926788 :         FOR( i = 1; i < tmp; i += 3 )
     307             :         {
     308    50745572 :             AbsTotal = L_mac0( AbsTotal, AbsMdct3[i], 1 );
     309             :         }
     310             :     }
     311             : 
     312      194945 :     test();
     313      194945 :     IF( ( LtpPitchLag > 0 ) && ( GT_16( LtpGain, kLtpHmGainThr ) ) )
     314             :     {
     315       46237 :         Bandwidth = 0;
     316       46237 :         move16();
     317       46237 :         if ( GE_16( NumToConsider, 256 ) )
     318             :         {
     319       46237 :             Bandwidth = 1;
     320       46237 :             move16();
     321             :         }
     322             : 
     323       46237 :         LtpPitchIndex = sub( mult_r( LtpPitchLag, 1 << ( 15 - kLtpHmFractionalResolution ) ), 2 );
     324       46237 :         assert( 0 <= LtpPitchIndex && LtpPitchIndex <= 16 );
     325             : 
     326       46237 :         tmp32 = L_shl( L_deposit_l( sub( NumToConsider, 2 ) ), kLtpHmFractionalResolution );
     327       46237 :         tmp = shl( 1, NumRatioBits[Bandwidth][LtpPitchIndex] );
     328     1111069 :         FOR( Multiplier = 1; Multiplier <= tmp; ++Multiplier )
     329             :         {
     330     1064832 :             Lag = L_shr( L_mult0( LtpPitchLag, Ratios_fx[Bandwidth][LtpPitchIndex][Multiplier - 1] ), 8 );
     331             : 
     332     1064832 :             test();
     333     1064832 :             IF( ( GE_32( Lag, 4 << kLtpHmFractionalResolution ) ) && ( LE_32( Lag, tmp32 ) ) )
     334             :             {
     335     1056883 :                 CurrentScore = SearchPeriodicityIndex_Single(
     336             :                     AbsMdct3,
     337             :                     NumToConsider,
     338             :                     Lag,
     339             :                     kLtpHmFractionalResolution );
     340             : 
     341     1056883 :                 if ( GT_16( CurrentScore, Score ) )
     342             :                 {
     343       73645 :                     PeriodicityIndex = s_or( Multiplier, kLtpHmFlag );
     344             :                 }
     345     1056883 :                 Score = s_max( Score, CurrentScore );
     346             :             }
     347             :         }
     348       46237 :         PeriodicityIndex = s_or( PeriodicityIndex, shl( LtpPitchIndex, 9 ) );
     349             :     }
     350             :     ELSE
     351             :     {
     352      148708 :         IF( UnfilteredMdct != NULL )
     353             :         {
     354        8470 :             MaxAt = 1;
     355        8470 :             move16();
     356        8470 :             A = L_shr( AbsMdct3[1], 6 );
     357             : 
     358     1717226 :             FOR( i = 4; i < NumToConsider - 1; i += 3 )
     359             :             {
     360     1708756 :                 if ( GT_32( AbsMdct3[i], AbsMdct3[MaxAt] ) )
     361             :                 {
     362       10540 :                     MaxAt = i;
     363       10540 :                     move16();
     364             :                 }
     365     1708756 :                 A = L_add( A, L_shr( AbsMdct3[i], 6 ) );
     366             :             }
     367             : 
     368        8470 :             if ( GT_32( L_shr( AbsMdct3[MaxAt], 6 ), Mpy_32_16_1( A, 22938 /*0.7 Q15*/ ) ) )
     369             :             {
     370         155 :                 NumToConsider = s_min( NumToConsider, add( MaxAt, 4 ) );
     371             :             }
     372             :         }
     373             : 
     374      148708 :         SearchPeriodicityIndex_Range(
     375             :             AbsMdct3,
     376             :             NumToConsider,
     377             :             0, 16,
     378             :             3,
     379             :             GET_ADJ2( 0, 6, 3 ),
     380             :             4,
     381             :             &PeriodicityIndex,
     382             :             &Score );
     383             : 
     384      148708 :         SearchPeriodicityIndex_Range(
     385             :             AbsMdct3,
     386             :             NumToConsider,
     387             :             16, 80,
     388             :             4,
     389             :             GET_ADJ2( 16, 8, 4 ),
     390             :             4,
     391             :             &PeriodicityIndex,
     392             :             &Score );
     393             : 
     394      148708 :         SearchPeriodicityIndex_Range(
     395             :             AbsMdct3,
     396             :             NumToConsider,
     397             :             80, 208,
     398             :             3,
     399             :             GET_ADJ2( 80, 12, 3 ),
     400             :             4,
     401             :             &PeriodicityIndex,
     402             :             &Score );
     403             : 
     404      148708 :         IF( LE_16( NumToConsider, 128 ) ) /* no long lags for band-limited MDCTs */
     405             :         {
     406         155 :             SearchPeriodicityIndex_Range(
     407             :                 AbsMdct3,
     408             :                 NumToConsider,
     409         155 :                 208, add( 88, NumToConsider ),
     410             :                 0,
     411             :                 GET_ADJ2( 224, 188, 0 ),
     412             :                 1,
     413             :                 &PeriodicityIndex,
     414             :                 &Score );
     415             :         }
     416             :         ELSE
     417             :         {
     418      148553 :             test();
     419      148553 :             IF( GT_16( TargetBits, kSmallerLagsTargetBitsThreshold ) && GE_16( NumToConsider, 256 ) )
     420             :             {
     421      143899 :                 SearchPeriodicityIndex_Range(
     422             :                     AbsMdct3,
     423             :                     NumToConsider,
     424             :                     208, 224,
     425             :                     1,
     426             :                     GET_ADJ2( 208, 28, 1 ),
     427             :                     1,
     428             :                     &PeriodicityIndex,
     429             :                     &Score );
     430      143899 :                 SearchPeriodicityIndex_Range(
     431             :                     AbsMdct3,
     432             :                     NumToConsider,
     433             :                     224, 256,
     434             :                     0,
     435             :                     GET_ADJ2( 224, 188, 0 ),
     436             :                     1,
     437             :                     &PeriodicityIndex,
     438             :                     &Score );
     439             :             }
     440             :             ELSE
     441             :             {
     442        4654 :                 SearchPeriodicityIndex_Range(
     443             :                     AbsMdct3,
     444             :                     NumToConsider,
     445             :                     208, 256,
     446             :                     1,
     447             :                     GET_ADJ2( 208, 28, 1 ),
     448             :                     1,
     449             :                     &PeriodicityIndex,
     450             :                     &Score );
     451             :             }
     452             :         }
     453             :     }
     454             : 
     455      194945 :     IF( AbsTotal > 0 )
     456             :     {
     457      194925 :         tmp32 = L_mult0( Score, NumToConsider ); /* -> 16Q15 */
     458      194925 :         tmp = sub( norm_l( tmp32 ), 1 );
     459      194925 :         tmp2 = norm_l( AbsTotal );
     460      194925 :         tmp3 = div_s( round_fx_o( L_shl_o( tmp32, tmp, &Overflow ), &Overflow ), round_fx_o( L_shl_o( AbsTotal, tmp2, &Overflow ), &Overflow ) );
     461      194925 :         *RelativeScore = shr_o( tmp3, add( sub( tmp, tmp2 ), 2 ), &Overflow ); /* -> 2Q13 */
     462      194925 :         move16();
     463             :     }
     464             :     ELSE
     465             :     {
     466          20 :         *RelativeScore = 0;
     467          20 :         move16();
     468             :     }
     469             : 
     470      194945 :     return PeriodicityIndex;
     471             : }
     472             : /*-------------------------------------------------------------------*
     473             :  * PeakFilter()
     474             :  *
     475             :  *
     476             :  *-------------------------------------------------------------------*/
     477             : 
     478       13729 : static void PeakFilter(
     479             :     const Word32 x[],    /* i  : absolute spectrum   Qx                        */
     480             :     Word32 y[],          /* O  : filtered absolute spectrum, must not alias x[] Q(x-4)*/
     481             :     const Word16 L_frame /* i  : number of spectral lines                       */
     482             : )
     483             : {
     484             :     Word16 flen, i;
     485             :     /*#define kPeakElevationThreshold 1.0f*/
     486             :     Word16 m;
     487             :     Word32 a;
     488             : 
     489       13729 :     flen = shr( L_frame, 4 );
     490             :     /* m = kPeakElevationThreshold / (float)(2*flen + 1); */
     491       13729 :     m = shr( div_s( 8 /*kPeakElevationThreshold Q3*/, add( shl( flen, 1 ), 1 ) ), 3 ); // Q15
     492             : 
     493       13729 :     a = L_deposit_l( 0 );
     494      541809 :     FOR( i = 0; i < flen; ++i )
     495             :     {
     496      528080 :         a = L_add( a, L_shr( x[i], 4 ) );
     497             :     }
     498             : 
     499      541809 :     FOR( i = 0; i < flen; ++i )
     500             :     {
     501      528080 :         y[i] = L_max( 0, L_sub( L_shr( x[i], 4 ), Mpy_32_16_1( a, m ) ) ); // Q(x-4)
     502      528080 :         move32();
     503      528080 :         a = L_add( a, L_shr( x[i + flen], 4 ) );
     504             :     }
     505       13729 :     sub( 0, 0 );
     506     7406849 :     FOR( ; i < L_frame - flen; ++i )
     507             :     {
     508     7393120 :         y[i] = L_max( 0, L_sub( L_shr( x[i], 4 ), Mpy_32_16_1( a, m ) ) ); // Q(x-4)
     509     7393120 :         move32();
     510     7393120 :         a = L_sub( a, L_shr( x[i - flen], 4 ) );
     511     7393120 :         a = L_add( a, L_shr( x[i + flen], 4 ) );
     512             :     }
     513             : 
     514      541809 :     FOR( ; i < L_frame; ++i )
     515             :     {
     516      528080 :         y[i] = L_max( 0, L_sub( L_shr( x[i], 4 ), Mpy_32_16_1( a, m ) ) ); // Q(x-4)
     517      528080 :         move32();
     518      528080 :         a = L_sub( a, L_shr( x[i - flen], 4 ) );
     519             :     }
     520       13729 : }
     521             : 
     522             : /*-------------------------------------------------------------------*
     523             :  * tcx_hm_get_re()
     524             :  *
     525             :  *
     526             :  *-------------------------------------------------------------------*/
     527       30927 : static Word32 tcx_hm_get_re(
     528             :     const Word16 x[],       /* i: absolute spectrum                       */
     529             :     const Word16 gain,      /* o: quantized harmonic model gain     Q11   */
     530             :     const Word32 lag,       /* i: pitch lag                         Q0    */
     531             :     const Word16 fract_res, /* i: fractional resolution of the lag  Q0    */
     532             :     Word16 p[],             /* i: harmonic model                    Q13   */
     533             :     const Word32 env[],     /* i: envelope                          Q16   */
     534             :     const Word16 L_frame    /* i: number of spectral lines          Q0    */
     535             : )
     536             : {
     537             :     Word16 i, inv_G, tmp;
     538             :     Word16 s, s_ne, s_x_ne;
     539             :     Word16 *x_ne;
     540             :     Word32 ne[N_MAX_ARI], G, e;
     541             : 
     542       30927 :     x_ne = (Word16 *) ne;
     543       30927 :     assert( L_frame <= N_MAX_ARI );
     544             : 
     545             :     /* Calculate new envelope with "gain" harmonic gain ***********************/
     546             : 
     547       30927 :     Copy32( env, ne, L_frame );
     548             : 
     549       30927 :     tcx_hm_modify_envelope(
     550             :         gain,
     551             :         lag,
     552             :         fract_res,
     553             :         p,
     554             :         ne,
     555             :         L_frame );
     556             : 
     557             :     /* Normalize **************************************************************/
     558             : 
     559       30927 :     s_ne = getScaleFactor32( ne, L_frame );
     560             : 
     561       30927 :     G = L_deposit_l( 0 );
     562    19147407 :     FOR( i = 0; i < L_frame; ++i )
     563             :     {
     564    19116480 :         x_ne[i] = mult( x[i], extract_h( L_shl( ne[i], s_ne ) ) ); /* exp: x_e+15-s_ne */
     565    19116480 :         move16();
     566    19116480 :         G = L_mac0( G, x_ne[i], 1 ); /* exp: x_e + 31 - s_ne */
     567             :     }
     568       30927 :     s = norm_l( G );
     569       30927 :     inv_G = div_s( 0x4000, extract_h( L_shl( G, s ) ) ); /* exp: 1 - (x_e + 31 - s_ne - s) */
     570             : 
     571             :     /* Calculate error ********************************************************/
     572       30927 :     s_x_ne = sub( getScaleFactor16( x_ne, L_frame ), 2 );
     573       30927 :     e = L_deposit_l( 0 );
     574    19147407 :     FOR( i = 0; i < L_frame; ++i )
     575             :     {
     576    19116480 :         tmp = shl( x_ne[i], s_x_ne ); /* exp: x_e + 15 - s_ne - s_x_ne */
     577    19116480 :         tmp = mult( tmp, tmp );       /* exp: 2 * (x_e + 15 - s_ne - s_x_ne) */
     578    19116480 :         e = L_mac( e, tmp, tmp );     /* exp: 4 * (x_e + 15 - s_ne - s_x_ne) */
     579             :     }
     580             : 
     581       30927 :     e = Mpy_32_16_1( e, inv_G );
     582       30927 :     e = Mpy_32_16_1( e, inv_G );
     583       30927 :     e = Mpy_32_16_1( e, inv_G );
     584       30927 :     e = Mpy_32_16_1( e, inv_G ); /* exp: 4 * (s - s_x_ne - 15) */
     585             : 
     586       30927 :     e = L_shl( e, shl( sub( sub( s, s_x_ne ), 15 ), 2 ) ); /* Q31 */
     587             : 
     588             : 
     589       30927 :     return e;
     590             : }
     591             : /*-------------------------------------------------------------------*
     592             :  * tcx_hm_quantize_gain()
     593             :  *
     594             :  *
     595             :  *-------------------------------------------------------------------*/
     596             : 
     597       13729 : static void tcx_hm_quantize_gain(
     598             :     const Word32 x[],        /* i: absolute spectrum                 Q31-x_e */
     599             :     const Word16 *x_e,       /* i: absolute spectrum exponent        Q0    */
     600             :     const Word32 env[],      /* i: envelope                          Q16   */
     601             :     const Word32 lag,        /* i: pitch lag                         Q0    */
     602             :     const Word16 fract_res,  /* i: fractional resolution of the lag  Q0    */
     603             :     Word16 p[],              /* i: harmonic model                    Q13   */
     604             :     const Word16 L_frame,    /* i: number of spectral lines          Q0    */
     605             :     const Word16 coder_type, /* i: coder_type                        Q0    */
     606             :     Word16 relative_score,   /* i: periodicity score                 Q13   */
     607             :     Word16 *gain_idx,        /* o: quantization index                Q0    */
     608             :     Word16 *gain             /* o: quantized harmonic model gain     Q11   */
     609             : )
     610             : {
     611             :     Word16 g;
     612             :     Word16 pe; /* Q14 */
     613             :     Word32 be; /* Q31 */
     614             :     Word32 e;  /* Q31 */
     615             :     Word16 i;
     616             :     Word16 x16[N_MAX_ARI], s_x;
     617             :     Word16 s;
     618             : 
     619             : 
     620       13729 :     assert( coder_type == VOICED || coder_type == GENERIC );
     621       13729 :     s = 0;
     622       13729 :     move16();
     623       13729 :     if ( EQ_16( coder_type, VOICED ) )
     624             :     {
     625        2759 :         s = 1;
     626        2759 :         move16();
     627             :     }
     628             : 
     629             : 
     630       13729 :     *gain = 0;
     631       13729 :     move16();
     632             : 
     633             :     /* Disable the harmonic model if periodicity is very low */
     634       13729 :     IF( LT_16( relative_score, kLowPeriodicityThr_fx[s] ) )
     635             :     {
     636        2404 :         return;
     637             :     }
     638             : 
     639             :     (void) x_e;
     640             : 
     641       11325 :     s_x = getScaleFactor32( x, L_frame );
     642     7038525 :     FOR( i = 0; i < L_frame; ++i )
     643             :     {
     644     7027200 :         x16[i] = extract_h( L_shl( x[i], s_x ) );
     645     7027200 :         move16();
     646             :     }
     647             : 
     648       11325 :     be = tcx_hm_get_re( x16, *gain, lag, fract_res, p, env, L_frame );
     649             : 
     650       11325 :     IF( EQ_16( coder_type, GENERIC ) )
     651             :     {
     652        8566 :         e = tcx_hm_get_re(
     653             :             x16,
     654        8566 :             qGains[s][0],
     655             :             lag,
     656             :             fract_res,
     657             :             p,
     658             :             env,
     659             :             L_frame );
     660             : 
     661        8566 :         pe = 17203 /*1.05 Q14*/;
     662        8566 :         move16();
     663             : 
     664             :         /* pe is Q14 */
     665        8566 :         IF( LT_32( L_shl( Mpy_32_16_1( e, pe ), 1 ), be ) )
     666             :         {
     667        4623 :             *gain_idx = 0;
     668        4623 :             move16();
     669        4623 :             *gain = qGains[s][0];
     670        4623 :             move16();
     671             :         }
     672             :     }
     673             :     ELSE
     674             :     {
     675             :         /* Iterate over all possible gain values */
     676       13795 :         FOR( g = 0; g < ( 1 << kTcxHmNumGainBits ); ++g )
     677             :         {
     678       11036 :             e = tcx_hm_get_re(
     679             :                 x16,
     680       11036 :                 qGains[s][g],
     681             :                 lag,
     682             :                 fract_res,
     683             :                 p,
     684             :                 env,
     685             :                 L_frame );
     686             : 
     687             :             /* Add bit penalty */
     688       11036 :             pe = 16384 /*1.0 Q14*/;
     689       11036 :             move16();
     690       11036 :             if ( *gain == 0 )
     691             :             {
     692        3920 :                 pe = 17203 /*1.05 Q14*/;
     693        3920 :                 move16();
     694             :             }
     695             : 
     696             :             /* Minimum selection, pe is Q14 */
     697       11036 :             IF( LT_32( L_shl( Mpy_32_16_1( e, pe ), 1 ), be ) )
     698             :             {
     699        5049 :                 be = e;
     700        5049 :                 move32();
     701        5049 :                 *gain_idx = g;
     702        5049 :                 move16();
     703        5049 :                 *gain = qGains[s][g];
     704        5049 :                 move16();
     705             :             }
     706             :         }
     707             :     }
     708             : }
     709             : 
     710       13729 : static Word16 tcx_hm_search(
     711             :     const Word32 abs_spectrum[], /* i:   absolute spectrum            Q31-e */
     712             :     const Word16 L_frame,        /* i:   number of spectral lines     Q0    */
     713             :     const Word16 targetBits,     /* i:   target bit budget            Q0    */
     714             :     const Word16 LtpPitchLag,    /* i:   LTP pitch lag or -1 if none  Q0    */
     715             :     const Word16 LtpGain,        /* i:   LTP gain                     Q15   */
     716             :     Word16 *RelativeScore        /* o:   Energy concentration factor  Q13   */
     717             : )
     718             : {
     719             :     Word32 fspec[N_MAX_ARI];
     720             : 
     721             :     /* Filter out noise and keep the peaks */
     722       13729 :     PeakFilter( abs_spectrum, fspec, L_frame );
     723             : 
     724             :     /* Get the best lag index */
     725       13729 :     return SearchPeriodicityIndex_fx(
     726             :         fspec,
     727             :         abs_spectrum,
     728             :         L_frame,
     729             :         targetBits,
     730             :         LtpPitchLag,
     731             :         LtpGain,
     732             :         RelativeScore );
     733             : }
     734             : 
     735       15849 : void tcx_hm_analyse_fx(
     736             :     const Word32 abs_spectrum[], /* i:   absolute spectrum            Q31-e */
     737             :     const Word16 *spectrum_e,    /* i:   absolute spectrum exponent   Q0    */
     738             :     const Word16 L_frame,        /* i:   number of spectral lines     Q0    */
     739             :     Word32 env[],                /* i/o: envelope shape               Q16   */
     740             :     const Word16 targetBits,     /* i:   target bit budget            Q0    */
     741             :     const Word16 coder_type,     /* i:  coder type                    Q0    */
     742             :     Word16 prm_hm[],             /* o:   HM parameters                Q0    */
     743             :     const Word16 LtpPitchLag,    /* i:   LTP pitch lag or -1 if none  Q0    */
     744             :     const Word16 LtpGain,        /* i:   LTP gain                     Q15   */
     745             :     Word16 *hm_bits_out          /* o:   bit consumption              Q0    */
     746             : )
     747             : {
     748             :     Word32 lag;
     749             :     Word16 fract_res;
     750             :     Word16 RelativeScore;                      /* Q13 */
     751             :     Word16 gain;                               /* Q11 */
     752             :     Word16 p[2 * kTcxHmParabolaHalfWidth + 1]; /* Q13 */
     753             :     Word16 hm_bits, bw_flag;
     754             : 
     755             : 
     756             :     /* Disable HM for non-GENERC, VOICED coder types */
     757       15849 :     if ( LT_16( coder_type, VOICED ) )
     758             :     {
     759        2120 :         *hm_bits_out = 0;
     760        2120 :         move16();
     761        2120 :         prm_hm[0] = 0;
     762        2120 :         move16();
     763             : 
     764        2120 :         return;
     765             :     }
     766             : 
     767       13729 :     bw_flag = 0;
     768       13729 :     move16();
     769       13729 :     if ( GE_16( L_frame, 256 ) )
     770             :     {
     771       13729 :         bw_flag = 1;
     772       13729 :         move16();
     773             :     }
     774             : 
     775             :     /* Bit consumption for the HM off case: 1 bit flag */
     776       13729 :     hm_bits = 1;
     777       13729 :     move16();
     778       13729 :     move16();
     779       13729 :     prm_hm[1] = tcx_hm_search(
     780             :         abs_spectrum,
     781             :         L_frame,
     782       13729 :         sub( targetBits, hm_bits ),
     783             :         LtpPitchLag,
     784             :         LtpGain,
     785             :         &RelativeScore );
     786             : 
     787             :     /* Convert the index to lag */
     788       13729 :     UnmapIndex(
     789       13729 :         prm_hm[1],
     790             :         bw_flag,
     791             :         LtpPitchLag,
     792       13729 :         ( ( LE_16( sub( targetBits, hm_bits ), kSmallerLagsTargetBitsThreshold ) ) || !bw_flag ),
     793             :         &fract_res,
     794             :         &lag );
     795       13729 :     test();
     796             : 
     797             :     /* Render harmonic model */
     798       13729 :     tcx_hm_render(
     799             :         lag,
     800             :         fract_res,
     801             :         p );
     802             : 
     803             :     /* Calculate and quantize gain */
     804       13729 :     gain = 0;
     805       13729 :     move16();
     806             : 
     807       13729 :     tcx_hm_quantize_gain(
     808             :         abs_spectrum,
     809             :         spectrum_e,
     810             :         env,
     811             :         lag,
     812             :         fract_res,
     813             :         p,
     814             :         L_frame,
     815             :         coder_type,
     816             :         RelativeScore,
     817             :         &prm_hm[2],
     818             :         &gain );
     819             : 
     820             :     /* Decision */
     821       13729 :     IF( gain > 0 )
     822             :     {
     823        7039 :         prm_hm[0] = 1; /* flag: on */
     824        7039 :         move16();
     825             : 
     826        7039 :         hm_bits = add( hm_bits, CountIndexBits( bw_flag, prm_hm[1] ) );
     827             : 
     828        7039 :         if ( EQ_16( coder_type, VOICED ) )
     829             :         {
     830        2416 :             hm_bits = add( hm_bits, kTcxHmNumGainBits );
     831             :         }
     832             : 
     833        7039 :         tcx_hm_modify_envelope(
     834             :             gain,
     835             :             lag,
     836             :             fract_res,
     837             :             p,
     838             :             env,
     839             :             L_frame );
     840             :     }
     841             :     ELSE
     842             :     {
     843        6690 :         prm_hm[0] = 0; /* flag: off   */
     844        6690 :         move16();
     845        6690 :         prm_hm[1] = -1; /* pitch index */
     846        6690 :         move16();
     847        6690 :         prm_hm[2] = 0; /* gain index  */
     848        6690 :         move16();
     849             :     }
     850             : 
     851       13729 :     *hm_bits_out = hm_bits;
     852       13729 :     move16();
     853             : }

Generated by: LCOV version 1.14