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