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/include/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 static __inline size_t CalcLrIntQ(int16_t fixVal,
     38                                   int16_t qDomain) {
     39   int32_t roundVal = 1 << (qDomain - 1);
     40 
     41   return (fixVal + roundVal) >> qDomain;
     42 }
     43 
     44 void WebRtcIsacfix_PitchFilter(int16_t* indatQQ, // Q10 if type is 1 or 4,
     45                                                        // Q0 if type is 2.
     46                                int16_t* outdatQQ,
     47                                PitchFiltstr* pfp,
     48                                int16_t* lagsQ7,
     49                                int16_t* gainsQ12,
     50                                int16_t type) {
     51   int    k, ind, cnt;
     52   int16_t sign = 1;
     53   int16_t inystateQQ[PITCH_DAMPORDER];
     54   int16_t ubufQQ[PITCH_INTBUFFSIZE + QLOOKAHEAD];
     55   const int16_t Gain = 21299;     // 1.3 in Q14
     56   int16_t oldLagQ7;
     57   int16_t oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12;
     58   size_t indW32 = 0, frcQQ = 0;
     59   const int16_t* fracoeffQQ = NULL;
     60 
     61   // Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM().
     62   COMPILE_ASSERT(PITCH_FRACORDER == 9);
     63   COMPILE_ASSERT(PITCH_DAMPORDER == 5);
     64 
     65   // Set up buffer and states.
     66   memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ));
     67   memcpy(inystateQQ, pfp->ystateQQ, sizeof(inystateQQ));
     68 
     69   // Get old lag and gain value from memory.
     70   oldLagQ7 = pfp->oldlagQ7;
     71   oldGainQ12 = pfp->oldgainQ12;
     72 
     73   if (type == 4) {
     74     sign = -1;
     75 
     76     // Make output more periodic.
     77     for (k = 0; k < PITCH_SUBFRAMES; k++) {
     78       gainsQ12[k] = (int16_t)(gainsQ12[k] * Gain >> 14);
     79     }
     80   }
     81 
     82   // No interpolation if pitch lag step is big.
     83   if (((lagsQ7[0] * 3 >> 1) < oldLagQ7) || (lagsQ7[0] > (oldLagQ7 * 3 >> 1))) {
     84     oldLagQ7 = lagsQ7[0];
     85     oldGainQ12 = gainsQ12[0];
     86   }
     87 
     88   ind = 0;
     89 
     90   for (k = 0; k < PITCH_SUBFRAMES; k++) {
     91     // Calculate interpolation steps.
     92     lagdeltaQ7 = lagsQ7[k] - oldLagQ7;
     93     lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
     94                   lagdeltaQ7, kDivFactor, 15);
     95     curLagQ7 = oldLagQ7;
     96     gaindeltaQ12 = gainsQ12[k] - oldGainQ12;
     97     gaindeltaQ12 = (int16_t)(gaindeltaQ12 * kDivFactor >> 15);
     98 
     99     curGainQ12 = oldGainQ12;
    100     oldLagQ7 = lagsQ7[k];
    101     oldGainQ12 = gainsQ12[k];
    102 
    103     // Each frame has 4 60-sample pitch subframes, and each subframe has 5
    104     // 12-sample segments. Each segment need to be processed with
    105     // newly-updated parameters, so we break the pitch filtering into
    106     // two for-loops (5 x 12) below. It's also why kDivFactor = 0.2 (in Q15).
    107     for (cnt = 0; cnt < kSegments; cnt++) {
    108       // Update parameters for each segment.
    109       curGainQ12 += gaindeltaQ12;
    110       curLagQ7 += lagdeltaQ7;
    111       indW32 = CalcLrIntQ(curLagQ7, 7);
    112       frcQQ = ((indW32 << 7) + 64 - curLagQ7) >> 4;
    113 
    114       if (frcQQ == PITCH_FRACS) {
    115         frcQQ = 0;
    116       }
    117       fracoeffQQ = kIntrpCoef[frcQQ];
    118 
    119       // Pitch filtering.
    120       WebRtcIsacfix_PitchFilterCore(PITCH_SUBFRAME_LEN / kSegments, curGainQ12,
    121         indW32, sign, inystateQQ, ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind);
    122     }
    123   }
    124 
    125   // Export buffer and states.
    126   memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ));
    127   memcpy(pfp->ystateQQ, inystateQQ, sizeof(pfp->ystateQQ));
    128 
    129   pfp->oldlagQ7 = oldLagQ7;
    130   pfp->oldgainQ12 = oldGainQ12;
    131 
    132   if (type == 2) {
    133     // Filter look-ahead segment.
    134     WebRtcIsacfix_PitchFilterCore(QLOOKAHEAD, curGainQ12, indW32, 1, inystateQQ,
    135                 ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind);
    136   }
    137 }
    138 
    139 
    140 void WebRtcIsacfix_PitchFilterGains(const int16_t* indatQ0,
    141                                     PitchFiltstr* pfp,
    142                                     int16_t* lagsQ7,
    143                                     int16_t* gainsQ12) {
    144   int  k, n, m;
    145   size_t ind, pos, pos3QQ;
    146 
    147   int16_t ubufQQ[PITCH_INTBUFFSIZE];
    148   int16_t oldLagQ7, lagdeltaQ7, curLagQ7;
    149   const int16_t* fracoeffQQ = NULL;
    150   int16_t scale;
    151   int16_t cnt = 0, tmpW16;
    152   size_t frcQQ, indW16 = 0;
    153   int32_t tmpW32, tmp2W32, csum1QQ, esumxQQ;
    154 
    155   // Set up buffer and states.
    156   memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ));
    157   oldLagQ7 = pfp->oldlagQ7;
    158 
    159   // No interpolation if pitch lag step is big.
    160   if (((lagsQ7[0] * 3 >> 1) < oldLagQ7) || (lagsQ7[0] > (oldLagQ7 * 3 >> 1))) {
    161     oldLagQ7 = lagsQ7[0];
    162   }
    163 
    164   ind = 0;
    165   pos = ind + PITCH_BUFFSIZE;
    166   scale = 0;
    167   for (k = 0; k < PITCH_SUBFRAMES; k++) {
    168 
    169     // Calculate interpolation steps.
    170     lagdeltaQ7 = lagsQ7[k] - oldLagQ7;
    171     lagdeltaQ7 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
    172                    lagdeltaQ7, kDivFactor, 15);
    173     curLagQ7 = oldLagQ7;
    174     oldLagQ7 = lagsQ7[k];
    175 
    176     csum1QQ = 1;
    177     esumxQQ = 1;
    178 
    179     // Same as function WebRtcIsacfix_PitchFilter(), we break the pitch
    180     // filtering into two for-loops (5 x 12) below.
    181     for (cnt = 0; cnt < kSegments; cnt++) {
    182       // Update parameters for each segment.
    183       curLagQ7 += lagdeltaQ7;
    184       indW16 = CalcLrIntQ(curLagQ7, 7);
    185       frcQQ = ((indW16 << 7) + 64 - curLagQ7) >> 4;
    186 
    187       if (frcQQ == PITCH_FRACS) {
    188         frcQQ = 0;
    189       }
    190       fracoeffQQ = kIntrpCoef[frcQQ];
    191 
    192       pos3QQ = pos - (indW16 + 4);
    193 
    194       for (n = 0; n < PITCH_SUBFRAME_LEN / kSegments; n++) {
    195         // Filter to get fractional pitch.
    196 
    197         tmpW32 = 0;
    198         for (m = 0; m < PITCH_FRACORDER; m++) {
    199           tmpW32 += ubufQQ[pos3QQ + m] * fracoeffQQ[m];
    200         }
    201 
    202         // Subtract from input and update buffer.
    203         ubufQQ[pos] = indatQ0[ind];
    204 
    205         tmp2W32 = WEBRTC_SPL_MUL_16_32_RSFT14(indatQ0[ind], tmpW32);
    206         tmpW32 += 8192;
    207         tmpW16 = tmpW32 >> 14;
    208         tmpW32 = tmpW16 * tmpW16;
    209 
    210         if ((tmp2W32 > 1073700000) || (csum1QQ > 1073700000) ||
    211             (tmpW32 > 1073700000) || (esumxQQ > 1073700000)) {  // 2^30
    212           scale++;
    213           csum1QQ >>= 1;
    214           esumxQQ >>= 1;
    215         }
    216         csum1QQ += tmp2W32 >> scale;
    217         esumxQQ += tmpW32 >> scale;
    218 
    219         ind++;
    220         pos++;
    221         pos3QQ++;
    222       }
    223     }
    224 
    225     if (csum1QQ < esumxQQ) {
    226       tmp2W32 = WebRtcSpl_DivResultInQ31(csum1QQ, esumxQQ);
    227 
    228       // Gain should be half the correlation.
    229       tmpW32 = tmp2W32 >> 20;
    230     } else {
    231       tmpW32 = 4096;
    232     }
    233     gainsQ12[k] = (int16_t)WEBRTC_SPL_SAT(PITCH_MAX_GAIN_Q12, tmpW32, 0);
    234   }
    235 
    236   // Export buffer and states.
    237   memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ));
    238   pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES - 1];
    239   pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES - 1];
    240 
    241 }
    242