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