|
1 //////////////////////////////////////////////////////////////////////////////// |
|
2 /// |
|
3 /// FIR low-pass (anti-alias) filter with filter coefficient design routine and |
|
4 /// MMX optimization. |
|
5 /// |
|
6 /// Anti-alias filter is used to prevent folding of high frequencies when |
|
7 /// transposing the sample rate with interpolation. |
|
8 /// |
|
9 /// Author : Copyright (c) Olli Parviainen |
|
10 /// Author e-mail : oparviai 'at' iki.fi |
|
11 /// SoundTouch WWW: http://www.surina.net/soundtouch |
|
12 /// |
|
13 //////////////////////////////////////////////////////////////////////////////// |
|
14 // |
|
15 // Last changed : $Date: 2014-01-05 15:40:22 -0600 (Sun, 05 Jan 2014) $ |
|
16 // File revision : $Revision: 4 $ |
|
17 // |
|
18 // $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $ |
|
19 // |
|
20 //////////////////////////////////////////////////////////////////////////////// |
|
21 // |
|
22 // License : |
|
23 // |
|
24 // SoundTouch audio processing library |
|
25 // Copyright (c) Olli Parviainen |
|
26 // |
|
27 // This library is free software; you can redistribute it and/or |
|
28 // modify it under the terms of the GNU Lesser General Public |
|
29 // License as published by the Free Software Foundation; either |
|
30 // version 2.1 of the License, or (at your option) any later version. |
|
31 // |
|
32 // This library is distributed in the hope that it will be useful, |
|
33 // but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
34 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
35 // Lesser General Public License for more details. |
|
36 // |
|
37 // You should have received a copy of the GNU Lesser General Public |
|
38 // License along with this library; if not, write to the Free Software |
|
39 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
40 // |
|
41 //////////////////////////////////////////////////////////////////////////////// |
|
42 |
|
43 #include <memory.h> |
|
44 #include <assert.h> |
|
45 #include <math.h> |
|
46 #include <stdlib.h> |
|
47 #include "AAFilter.h" |
|
48 #include "FIRFilter.h" |
|
49 |
|
50 using namespace soundtouch; |
|
51 |
|
52 #define PI 3.141592655357989 |
|
53 #define TWOPI (2 * PI) |
|
54 |
|
55 // define this to save AA filter coefficients to a file |
|
56 // #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 |
|
57 |
|
58 #ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS |
|
59 #include <stdio.h> |
|
60 |
|
61 static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) |
|
62 { |
|
63 FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); |
|
64 if (fptr == NULL) return; |
|
65 |
|
66 for (int i = 0; i < len; i ++) |
|
67 { |
|
68 double temp = coeffs[i]; |
|
69 fprintf(fptr, "%lf\n", temp); |
|
70 } |
|
71 fclose(fptr); |
|
72 } |
|
73 |
|
74 #else |
|
75 #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) |
|
76 #endif |
|
77 |
|
78 |
|
79 /***************************************************************************** |
|
80 * |
|
81 * Implementation of the class 'AAFilter' |
|
82 * |
|
83 *****************************************************************************/ |
|
84 |
|
85 AAFilter::AAFilter(uint len) |
|
86 { |
|
87 pFIR = FIRFilter::newInstance(); |
|
88 cutoffFreq = 0.5; |
|
89 setLength(len); |
|
90 } |
|
91 |
|
92 |
|
93 |
|
94 AAFilter::~AAFilter() |
|
95 { |
|
96 delete pFIR; |
|
97 } |
|
98 |
|
99 |
|
100 |
|
101 // Sets new anti-alias filter cut-off edge frequency, scaled to |
|
102 // sampling frequency (nyquist frequency = 0.5). |
|
103 // The filter will cut frequencies higher than the given frequency. |
|
104 void AAFilter::setCutoffFreq(double newCutoffFreq) |
|
105 { |
|
106 cutoffFreq = newCutoffFreq; |
|
107 calculateCoeffs(); |
|
108 } |
|
109 |
|
110 |
|
111 |
|
112 // Sets number of FIR filter taps |
|
113 void AAFilter::setLength(uint newLength) |
|
114 { |
|
115 length = newLength; |
|
116 calculateCoeffs(); |
|
117 } |
|
118 |
|
119 |
|
120 |
|
121 // Calculates coefficients for a low-pass FIR filter using Hamming window |
|
122 void AAFilter::calculateCoeffs() |
|
123 { |
|
124 uint i; |
|
125 double cntTemp, temp, tempCoeff,h, w; |
|
126 double wc; |
|
127 double scaleCoeff, sum; |
|
128 double *work; |
|
129 SAMPLETYPE *coeffs; |
|
130 |
|
131 assert(length >= 2); |
|
132 assert(length % 4 == 0); |
|
133 assert(cutoffFreq >= 0); |
|
134 assert(cutoffFreq <= 0.5); |
|
135 |
|
136 work = new double[length]; |
|
137 coeffs = new SAMPLETYPE[length]; |
|
138 |
|
139 wc = 2.0 * PI * cutoffFreq; |
|
140 tempCoeff = TWOPI / (double)length; |
|
141 |
|
142 sum = 0; |
|
143 for (i = 0; i < length; i ++) |
|
144 { |
|
145 cntTemp = (double)i - (double)(length / 2); |
|
146 |
|
147 temp = cntTemp * wc; |
|
148 if (temp != 0) |
|
149 { |
|
150 h = sin(temp) / temp; // sinc function |
|
151 } |
|
152 else |
|
153 { |
|
154 h = 1.0; |
|
155 } |
|
156 w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window |
|
157 |
|
158 temp = w * h; |
|
159 work[i] = temp; |
|
160 |
|
161 // calc net sum of coefficients |
|
162 sum += temp; |
|
163 } |
|
164 |
|
165 // ensure the sum of coefficients is larger than zero |
|
166 assert(sum > 0); |
|
167 |
|
168 // ensure we've really designed a lowpass filter... |
|
169 assert(work[length/2] > 0); |
|
170 assert(work[length/2 + 1] > -1e-6); |
|
171 assert(work[length/2 - 1] > -1e-6); |
|
172 |
|
173 // Calculate a scaling coefficient in such a way that the result can be |
|
174 // divided by 16384 |
|
175 scaleCoeff = 16384.0f / sum; |
|
176 |
|
177 for (i = 0; i < length; i ++) |
|
178 { |
|
179 temp = work[i] * scaleCoeff; |
|
180 //#if SOUNDTOUCH_INTEGER_SAMPLES |
|
181 // scale & round to nearest integer |
|
182 temp += (temp >= 0) ? 0.5 : -0.5; |
|
183 // ensure no overfloods |
|
184 assert(temp >= -32768 && temp <= 32767); |
|
185 //#endif |
|
186 coeffs[i] = (SAMPLETYPE)temp; |
|
187 } |
|
188 |
|
189 // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 |
|
190 pFIR->setCoefficients(coeffs, length, 14); |
|
191 |
|
192 _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); |
|
193 |
|
194 delete[] work; |
|
195 delete[] coeffs; |
|
196 } |
|
197 |
|
198 |
|
199 // Applies the filter to the given sequence of samples. |
|
200 // Note : The amount of outputted samples is by value of 'filter length' |
|
201 // smaller than the amount of input samples. |
|
202 uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const |
|
203 { |
|
204 return pFIR->evaluate(dest, src, numSamples, numChannels); |
|
205 } |
|
206 |
|
207 |
|
208 /// Applies the filter to the given src & dest pipes, so that processed amount of |
|
209 /// samples get removed from src, and produced amount added to dest |
|
210 /// Note : The amount of outputted samples is by value of 'filter length' |
|
211 /// smaller than the amount of input samples. |
|
212 uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const |
|
213 { |
|
214 SAMPLETYPE *pdest; |
|
215 const SAMPLETYPE *psrc; |
|
216 uint numSrcSamples; |
|
217 uint result; |
|
218 int numChannels = src.getChannels(); |
|
219 |
|
220 assert(numChannels == dest.getChannels()); |
|
221 |
|
222 numSrcSamples = src.numSamples(); |
|
223 psrc = src.ptrBegin(); |
|
224 pdest = dest.ptrEnd(numSrcSamples); |
|
225 result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); |
|
226 src.receiveSamples(result); |
|
227 dest.putSamples(result); |
|
228 |
|
229 return result; |
|
230 } |
|
231 |
|
232 |
|
233 uint AAFilter::getLength() const |
|
234 { |
|
235 return pFIR->getLength(); |
|
236 } |