Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h"
     12 
     13 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
     14 #include "webrtc/modules/audio_coding/codecs/isac/fix/source/settings.h"
     15 #include "webrtc/modules/audio_coding/codecs/isac/fix/source/structs.h"
     16 #include "webrtc/system_wrappers/interface/compile_assert_c.h"
     17 
     18 // Number of segments in a pitch subframe.
     19 static const int kSegments = 5;
     20 
     21 // A division factor of 1/5 in Q15.
     22 static const int16_t kDivFactor = 6553;
     23 
     24 // Interpolation coefficients; generated by design_pitch_filter.m.
     25 // Coefficients are stored in Q14.
     26 static const int16_t kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = {
     27   {-367, 1090, -2706,  9945, 10596, -3318,  1626, -781,  287},
     28   {-325,  953, -2292,  7301, 12963, -3320,  1570, -743,  271},
     29   {-240,  693, -1622,  4634, 14809, -2782,  1262, -587,  212},
     30   {-125,  358,  -817,  2144, 15982, -1668,   721, -329,  118},
     31   {   0,    0,    -1,     1, 16380,     1,    -1,    0,    0},
     32   { 118, -329,   721, -1668, 15982,  2144,  -817,  358, -125},
     33   { 212, -587,  1262, -2782, 14809,  4634, -1622,  693, -240},
     34   { 271, -743,  1570, -3320, 12963,  7301, -2292,  953, -325}
     35 };
     36 
     37 // Function prototype for pitch filtering.
     38 // TODO(Turaj): Add descriptions of input and output parameters.
     39 void WebRtcIsacfix_PitchFilterCore(int loopNumber,
     40                                    int16_t gain,
     41                                    int index,
     42                                    int16_t sign,
     43                                    int16_t* inputState,
     44                                    int16_t* outputBuf2,
     45                                    const int16_t* coefficient,
     46                                    int16_t* inputBuf,
     47                                    int16_t* outputBuf,
     48                                    int* index2);
     49 
     50 static __inline int32_t CalcLrIntQ(int32_t fixVal,
     51                                    int16_t qDomain) {
     52   int32_t intgr;
     53   int32_t roundVal;
     54 
     55   roundVal = WEBRTC_SPL_LSHIFT_W32((int32_t)1,  qDomain - 1);
     56   intgr = WEBRTC_SPL_RSHIFT_W32(fixVal + roundVal, qDomain);
     57 
     58   return intgr;
     59 }
     60 
     61 void WebRtcIsacfix_PitchFilter(int16_t* indatQQ, // Q10 if type is 1 or 4,
     62                                                        // Q0 if type is 2.
     63                                int16_t* outdatQQ,
     64                                PitchFiltstr* pfp,
     65                                int16_t* lagsQ7,
     66                                int16_t* gainsQ12,
     67                                int16_t type) {
     68   int    k, ind, cnt;
     69   int16_t sign = 1;
     70   int16_t inystateQQ[PITCH_DAMPORDER];
     71   int16_t ubufQQ[PITCH_INTBUFFSIZE + QLOOKAHEAD];
     72   const int16_t Gain = 21299;     // 1.3 in Q14
     73   int16_t oldLagQ7;
     74   int16_t oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12;
     75   int indW32 = 0, frcQQ = 0;
     76   int32_t tmpW32;
     77   const int16_t* fracoeffQQ = NULL;
     78 
     79   // Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM().
     80   COMPILE_ASSERT(PITCH_FRACORDER == 9);
     81   COMPILE_ASSERT(PITCH_DAMPORDER == 5);
     82 
     83   // Set up buffer and states.
     84   memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ));
     85   memcpy(inystateQQ, pfp->ystateQQ, sizeof(inystateQQ));
     86 
     87   // Get old lag and gain value from memory.
     88   oldLagQ7 = pfp->oldlagQ7;
     89   oldGainQ12 = pfp->oldgainQ12;
     90 
     91   if (type == 4) {
     92     sign = -1;
     93 
     94     // Make output more periodic.
     95     for (k = 0; k < PITCH_SUBFRAMES; k++) {
     96       gainsQ12[k] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
     97           gainsQ12[k], Gain, 14);
     98     }
     99   }
    100 
    101   // No interpolation if pitch lag step is big.
    102   if ((WEBRTC_SPL_MUL_16_16_RSFT(lagsQ7[0], 3, 1) < oldLagQ7) ||
    103       (lagsQ7[0] > WEBRTC_SPL_MUL_16_16_RSFT(oldLagQ7, 3, 1))) {
    104     oldLagQ7 = lagsQ7[0];
    105     oldGainQ12 = gainsQ12[0];
    106   }
    107 
    108   ind = 0;
    109 
    110   for (k = 0; k < PITCH_SUBFRAMES; k++) {
    111     // Calculate interpolation steps.
    112     lagdeltaQ7 = lagsQ7[k] - oldLagQ7;
    113     lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
    114                   lagdeltaQ7, kDivFactor, 15);
    115     curLagQ7 = oldLagQ7;
    116     gaindeltaQ12 = gainsQ12[k] - oldGainQ12;
    117     gaindeltaQ12 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(
    118                     gaindeltaQ12, kDivFactor, 15);
    119 
    120     curGainQ12 = oldGainQ12;
    121     oldLagQ7 = lagsQ7[k];
    122     oldGainQ12 = gainsQ12[k];
    123 
    124     // Each frame has 4 60-sample pitch subframes, and each subframe has 5
    125     // 12-sample segments. Each segment need to be processed with
    126     // newly-updated parameters, so we break the pitch filtering into
    127     // two for-loops (5 x 12) below. It's also why kDivFactor = 0.2 (in Q15).
    128     for (cnt = 0; cnt < kSegments; cnt++) {
    129       // Update parameters for each segment.
    130       curGainQ12 += gaindeltaQ12;
    131       curLagQ7 += lagdeltaQ7;
    132       indW32 = CalcLrIntQ(curLagQ7, 7);
    133       tmpW32 = WEBRTC_SPL_LSHIFT_W32(indW32, 7);
    134       tmpW32 -= curLagQ7;
    135       frcQQ = WEBRTC_SPL_RSHIFT_W32(tmpW32, 4);
    136       frcQQ += 4;
    137 
    138       if (frcQQ == PITCH_FRACS) {
    139         frcQQ = 0;
    140       }
    141       fracoeffQQ = kIntrpCoef[frcQQ];
    142 
    143       // Pitch filtering.
    144       WebRtcIsacfix_PitchFilterCore(PITCH_SUBFRAME_LEN / kSegments, curGainQ12,
    145         indW32, sign, inystateQQ, ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind);
    146     }
    147   }
    148 
    149   // Export buffer and states.
    150   memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ));
    151   memcpy(pfp->ystateQQ, inystateQQ, sizeof(pfp->ystateQQ));
    152 
    153   pfp->oldlagQ7 = oldLagQ7;
    154   pfp->oldgainQ12 = oldGainQ12;
    155 
    156   if (type == 2) {
    157     // Filter look-ahead segment.
    158     WebRtcIsacfix_PitchFilterCore(QLOOKAHEAD, curGainQ12, indW32, 1, inystateQQ,
    159                 ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind);
    160   }
    161 }
    162 
    163 
    164 void WebRtcIsacfix_PitchFilterGains(const int16_t* indatQ0,
    165                                     PitchFiltstr* pfp,
    166                                     int16_t* lagsQ7,
    167                                     int16_t* gainsQ12) {
    168   int  k, n, m, ind, pos, pos3QQ;
    169 
    170   int16_t ubufQQ[PITCH_INTBUFFSIZE];
    171   int16_t oldLagQ7, lagdeltaQ7, curLagQ7;
    172   const int16_t* fracoeffQQ = NULL;
    173   int16_t scale;
    174   int16_t cnt = 0, frcQQ, indW16 = 0, tmpW16;
    175   int32_t tmpW32, tmp2W32, csum1QQ, esumxQQ;
    176 
    177   // Set up buffer and states.
    178   memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ));
    179   oldLagQ7 = pfp->oldlagQ7;
    180 
    181   // No interpolation if pitch lag step is big.
    182   if ((WEBRTC_SPL_MUL_16_16_RSFT(lagsQ7[0], 3, 1) < oldLagQ7) ||
    183       (lagsQ7[0] > WEBRTC_SPL_MUL_16_16_RSFT(oldLagQ7, 3, 1))) {
    184     oldLagQ7 = lagsQ7[0];
    185   }
    186 
    187   ind = 0;
    188   pos = ind + PITCH_BUFFSIZE;
    189   scale = 0;
    190   for (k = 0; k < PITCH_SUBFRAMES; k++) {
    191 
    192     // Calculate interpolation steps.
    193     lagdeltaQ7 = lagsQ7[k] - oldLagQ7;
    194     lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
    195                    lagdeltaQ7, kDivFactor, 15);
    196     curLagQ7 = oldLagQ7;
    197     oldLagQ7 = lagsQ7[k];
    198 
    199     csum1QQ = 1;
    200     esumxQQ = 1;
    201 
    202     // Same as function WebRtcIsacfix_PitchFilter(), we break the pitch
    203     // filtering into two for-loops (5 x 12) below.
    204     for (cnt = 0; cnt < kSegments; cnt++) {
    205       // Update parameters for each segment.
    206       curLagQ7 += lagdeltaQ7;
    207       indW16 = (int16_t)CalcLrIntQ(curLagQ7, 7);
    208       tmpW16 = WEBRTC_SPL_LSHIFT_W16(indW16, 7);
    209       tmpW16 -= curLagQ7;
    210       frcQQ = WEBRTC_SPL_RSHIFT_W16(tmpW16, 4);
    211       frcQQ += 4;
    212 
    213       if (frcQQ == PITCH_FRACS) {
    214         frcQQ = 0;
    215       }
    216       fracoeffQQ = kIntrpCoef[frcQQ];
    217 
    218       pos3QQ = pos - (indW16 + 4);
    219 
    220       for (n = 0; n < PITCH_SUBFRAME_LEN / kSegments; n++) {
    221         // Filter to get fractional pitch.
    222 
    223         tmpW32 = 0;
    224         for (m = 0; m < PITCH_FRACORDER; m++) {
    225           tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQ[pos3QQ + m], fracoeffQQ[m]);
    226         }
    227 
    228         // Subtract from input and update buffer.
    229         ubufQQ[pos] = indatQ0[ind];
    230 
    231         tmp2W32 = WEBRTC_SPL_MUL_16_32_RSFT14(indatQ0[ind], tmpW32);
    232         tmpW32 += 8192;
    233         tmpW16 = (int16_t)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14);
    234         tmpW32 = WEBRTC_SPL_MUL_16_16(tmpW16, tmpW16);
    235 
    236         if ((tmp2W32 > 1073700000) || (csum1QQ > 1073700000) ||
    237             (tmpW32 > 1073700000) || (esumxQQ > 1073700000)) {  // 2^30
    238           scale++;
    239           csum1QQ = WEBRTC_SPL_RSHIFT_W32(csum1QQ, 1);
    240           esumxQQ = WEBRTC_SPL_RSHIFT_W32(esumxQQ, 1);
    241         }
    242         tmp2W32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, scale);
    243         csum1QQ += tmp2W32;
    244         tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmpW32, scale);
    245         esumxQQ += tmpW32;
    246 
    247         ind++;
    248         pos++;
    249         pos3QQ++;
    250       }
    251     }
    252 
    253     if (csum1QQ < esumxQQ) {
    254       tmp2W32 = WebRtcSpl_DivResultInQ31(csum1QQ, esumxQQ);
    255 
    256       // Gain should be half the correlation.
    257       tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, 20);
    258     } else {
    259       tmpW32 = 4096;
    260     }
    261     gainsQ12[k] = (int16_t)WEBRTC_SPL_SAT(PITCH_MAX_GAIN_Q12, tmpW32, 0);
    262   }
    263 
    264   // Export buffer and states.
    265   memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ));
    266   pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES - 1];
    267   pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES - 1];
    268 
    269 }
    270