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