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
CalcLrIntQ(WebRtc_Word32 fixVal,WebRtc_Word16 qDomain)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
WebRtcIsacfix_PitchFilter(WebRtc_Word16 * indatQQ,WebRtc_Word16 * outdatQQ,PitchFiltstr * pfp,WebRtc_Word16 * lagsQ7,WebRtc_Word16 * gainsQ12,WebRtc_Word16 type)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
WebRtcIsacfix_PitchFilterGains(const WebRtc_Word16 * indatQ0,PitchFiltstr * pfp,WebRtc_Word16 * lagsQ7,WebRtc_Word16 * gainsQ12)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