Line data Source code
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 21:40:22 +0000 (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 M_PI
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 0 : AAFilter::AAFilter(uint len)
86 : {
87 0 : pFIR = FIRFilter::newInstance();
88 0 : cutoffFreq = 0.5;
89 0 : setLength(len);
90 0 : }
91 :
92 :
93 :
94 0 : AAFilter::~AAFilter()
95 : {
96 0 : delete pFIR;
97 0 : }
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 0 : void AAFilter::setCutoffFreq(double newCutoffFreq)
105 : {
106 0 : cutoffFreq = newCutoffFreq;
107 0 : calculateCoeffs();
108 0 : }
109 :
110 :
111 :
112 : // Sets number of FIR filter taps
113 0 : void AAFilter::setLength(uint newLength)
114 : {
115 0 : length = newLength;
116 0 : calculateCoeffs();
117 0 : }
118 :
119 :
120 :
121 : // Calculates coefficients for a low-pass FIR filter using Hamming window
122 0 : 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 0 : assert(length >= 2);
132 0 : assert(length % 4 == 0);
133 0 : assert(cutoffFreq >= 0);
134 0 : assert(cutoffFreq <= 0.5);
135 :
136 0 : work = new double[length];
137 0 : coeffs = new SAMPLETYPE[length];
138 :
139 0 : wc = 2.0 * PI * cutoffFreq;
140 0 : tempCoeff = TWOPI / (double)length;
141 :
142 0 : sum = 0;
143 0 : for (i = 0; i < length; i ++)
144 : {
145 0 : cntTemp = (double)i - (double)(length / 2);
146 :
147 0 : temp = cntTemp * wc;
148 0 : if (temp != 0)
149 : {
150 0 : h = sin(temp) / temp; // sinc function
151 : }
152 : else
153 : {
154 0 : h = 1.0;
155 : }
156 0 : w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
157 :
158 0 : temp = w * h;
159 0 : work[i] = temp;
160 :
161 : // calc net sum of coefficients
162 0 : sum += temp;
163 : }
164 :
165 : // ensure the sum of coefficients is larger than zero
166 0 : assert(sum > 0);
167 :
168 : // ensure we've really designed a lowpass filter...
169 0 : assert(work[length/2] > 0);
170 0 : assert(work[length/2 + 1] > -1e-6);
171 0 : 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 0 : scaleCoeff = 16384.0f / sum;
176 :
177 0 : for (i = 0; i < length; i ++)
178 : {
179 0 : temp = work[i] * scaleCoeff;
180 : //#if SOUNDTOUCH_INTEGER_SAMPLES
181 : // scale & round to nearest integer
182 0 : temp += (temp >= 0) ? 0.5 : -0.5;
183 : // ensure no overfloods
184 0 : assert(temp >= -32768 && temp <= 32767);
185 : //#endif
186 0 : coeffs[i] = (SAMPLETYPE)temp;
187 : }
188 :
189 : // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
190 0 : pFIR->setCoefficients(coeffs, length, 14);
191 :
192 : _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
193 :
194 0 : delete[] work;
195 0 : delete[] coeffs;
196 0 : }
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 0 : uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
203 : {
204 0 : 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 0 : uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
213 : {
214 : SAMPLETYPE *pdest;
215 : const SAMPLETYPE *psrc;
216 : uint numSrcSamples;
217 : uint result;
218 0 : int numChannels = src.getChannels();
219 :
220 0 : assert(numChannels == dest.getChannels());
221 :
222 0 : numSrcSamples = src.numSamples();
223 0 : psrc = src.ptrBegin();
224 0 : pdest = dest.ptrEnd(numSrcSamples);
225 0 : result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
226 0 : src.receiveSamples(result);
227 0 : dest.putSamples(result);
228 :
229 0 : return result;
230 : }
231 :
232 :
233 0 : uint AAFilter::getLength() const
234 : {
235 0 : return pFIR->getLength();
236 : }
|