Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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 ////////////////////////////////////////////////////////////////////////////////
43 #include <memory.h>
44 #include <assert.h>
45 #include <math.h>
46 #include <stdlib.h>
47 #include "AAFilter.h"
48 #include "FIRFilter.h"
50 using namespace soundtouch;
52 #define PI 3.141592655357989
53 #define TWOPI (2 * PI)
55 // define this to save AA filter coefficients to a file
56 // #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1
58 #ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS
59 #include <stdio.h>
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;
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 }
74 #else
75 #define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
76 #endif
79 /*****************************************************************************
80 *
81 * Implementation of the class 'AAFilter'
82 *
83 *****************************************************************************/
85 AAFilter::AAFilter(uint len)
86 {
87 pFIR = FIRFilter::newInstance();
88 cutoffFreq = 0.5;
89 setLength(len);
90 }
94 AAFilter::~AAFilter()
95 {
96 delete pFIR;
97 }
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 }
112 // Sets number of FIR filter taps
113 void AAFilter::setLength(uint newLength)
114 {
115 length = newLength;
116 calculateCoeffs();
117 }
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;
131 assert(length >= 2);
132 assert(length % 4 == 0);
133 assert(cutoffFreq >= 0);
134 assert(cutoffFreq <= 0.5);
136 work = new double[length];
137 coeffs = new SAMPLETYPE[length];
139 wc = 2.0 * PI * cutoffFreq;
140 tempCoeff = TWOPI / (double)length;
142 sum = 0;
143 for (i = 0; i < length; i ++)
144 {
145 cntTemp = (double)i - (double)(length / 2);
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
158 temp = w * h;
159 work[i] = temp;
161 // calc net sum of coefficients
162 sum += temp;
163 }
165 // ensure the sum of coefficients is larger than zero
166 assert(sum > 0);
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);
173 // Calculate a scaling coefficient in such a way that the result can be
174 // divided by 16384
175 scaleCoeff = 16384.0f / sum;
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 }
189 // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
190 pFIR->setCoefficients(coeffs, length, 14);
192 _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
194 delete[] work;
195 delete[] coeffs;
196 }
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 }
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();
220 assert(numChannels == dest.getChannels());
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);
229 return result;
230 }
233 uint AAFilter::getLength() const
234 {
235 return pFIR->getLength();
236 }