1 ////////////////////////////////////////////////////////////////////////////////
2 ///
3 /// Sample rate transposer. Changes sample rate by using linear interpolation
4 /// together with anti-alias filtering (first order interpolation with anti-
5 /// alias filtering should be quite adequate for this application)
6 ///
7 /// Author        : Copyright (c) Olli Parviainen
8 /// Author e-mail : oparviai 'at' iki.fi
9 /// SoundTouch WWW: http://www.surina.net/soundtouch
10 ///
11 ////////////////////////////////////////////////////////////////////////////////
12 //
13 // Last changed  : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $
14 // File revision : $Revision: 4 $
15 //
16 // $Id: RateTransposer.cpp 225 2015-07-26 14:45:48Z oparviai $
17 //
18 ////////////////////////////////////////////////////////////////////////////////
19 //
20 // License :
21 //
22 //  SoundTouch audio processing library
23 //  Copyright (c) Olli Parviainen
24 //
25 //  This library is free software; you can redistribute it and/or
26 //  modify it under the terms of the GNU Lesser General Public
27 //  License as published by the Free Software Foundation; either
28 //  version 2.1 of the License, or (at your option) any later version.
29 //
30 //  This library is distributed in the hope that it will be useful,
31 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
32 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
33 //  Lesser General Public License for more details.
34 //
35 //  You should have received a copy of the GNU Lesser General Public
36 //  License along with this library; if not, write to the Free Software
37 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
38 //
39 ////////////////////////////////////////////////////////////////////////////////
40 
41 #include <memory.h>
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include "RateTransposer.h"
46 #include "InterpolateLinear.h"
47 #include "InterpolateCubic.h"
48 #include "InterpolateShannon.h"
49 #include "AAFilter.h"
50 
51 using namespace soundtouch;
52 
53 // Define default interpolation algorithm here
54 TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
55 
56 
57 // Constructor
RateTransposer()58 RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
59 {
60     bUseAAFilter = true;
61 
62     // Instantiates the anti-alias filter
63     pAAFilter = new AAFilter(64);
64     pTransposer = TransposerBase::newInstance();
65 }
66 
67 
68 
~RateTransposer()69 RateTransposer::~RateTransposer()
70 {
71     delete pAAFilter;
72     delete pTransposer;
73 }
74 
75 
76 
77 /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
enableAAFilter(bool newMode)78 void RateTransposer::enableAAFilter(bool newMode)
79 {
80     bUseAAFilter = newMode;
81 }
82 
83 
84 /// Returns nonzero if anti-alias filter is enabled.
isAAFilterEnabled() const85 bool RateTransposer::isAAFilterEnabled() const
86 {
87     return bUseAAFilter;
88 }
89 
90 
getAAFilter()91 AAFilter *RateTransposer::getAAFilter()
92 {
93     return pAAFilter;
94 }
95 
96 
97 
98 // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
99 // iRate, larger faster iRates.
setRate(double newRate)100 void RateTransposer::setRate(double newRate)
101 {
102     double fCutoff;
103 
104     pTransposer->setRate(newRate);
105 
106     // design a new anti-alias filter
107     if (newRate > 1.0)
108     {
109         fCutoff = 0.5 / newRate;
110     }
111     else
112     {
113         fCutoff = 0.5 * newRate;
114     }
115     pAAFilter->setCutoffFreq(fCutoff);
116 }
117 
118 
119 // Adds 'nSamples' pcs of samples from the 'samples' memory position into
120 // the input of the object.
putSamples(const SAMPLETYPE * samples,uint nSamples)121 void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
122 {
123     processSamples(samples, nSamples);
124 }
125 
126 
127 // Transposes sample rate by applying anti-alias filter to prevent folding.
128 // Returns amount of samples returned in the "dest" buffer.
129 // The maximum amount of samples that can be returned at a time is set by
130 // the 'set_returnBuffer_size' function.
processSamples(const SAMPLETYPE * src,uint nSamples)131 void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
132 {
133     uint count;
134 
135     if (nSamples == 0) return;
136 
137     // Store samples to input buffer
138     inputBuffer.putSamples(src, nSamples);
139 
140     // If anti-alias filter is turned off, simply transpose without applying
141     // the filter
142     if (bUseAAFilter == false)
143     {
144         count = pTransposer->transpose(outputBuffer, inputBuffer);
145         return;
146     }
147 
148     assert(pAAFilter);
149 
150     // Transpose with anti-alias filter
151     if (pTransposer->rate < 1.0f)
152     {
153         // If the parameter 'Rate' value is smaller than 1, first transpose
154         // the samples and then apply the anti-alias filter to remove aliasing.
155 
156         // Transpose the samples, store the result to end of "midBuffer"
157         pTransposer->transpose(midBuffer, inputBuffer);
158 
159         // Apply the anti-alias filter for transposed samples in midBuffer
160         pAAFilter->evaluate(outputBuffer, midBuffer);
161     }
162     else
163     {
164         // If the parameter 'Rate' value is larger than 1, first apply the
165         // anti-alias filter to remove high frequencies (prevent them from folding
166         // over the lover frequencies), then transpose.
167 
168         // Apply the anti-alias filter for samples in inputBuffer
169         pAAFilter->evaluate(midBuffer, inputBuffer);
170 
171         // Transpose the AA-filtered samples in "midBuffer"
172         pTransposer->transpose(outputBuffer, midBuffer);
173     }
174 }
175 
176 
177 // Sets the number of channels, 1 = mono, 2 = stereo
setChannels(int nChannels)178 void RateTransposer::setChannels(int nChannels)
179 {
180     assert(nChannels > 0);
181 
182     if (pTransposer->numChannels == nChannels) return;
183     pTransposer->setChannels(nChannels);
184 
185     inputBuffer.setChannels(nChannels);
186     midBuffer.setChannels(nChannels);
187     outputBuffer.setChannels(nChannels);
188 }
189 
190 
191 // Clears all the samples in the object
clear()192 void RateTransposer::clear()
193 {
194     outputBuffer.clear();
195     midBuffer.clear();
196     inputBuffer.clear();
197 }
198 
199 
200 // Returns nonzero if there aren't any samples available for outputting.
isEmpty() const201 int RateTransposer::isEmpty() const
202 {
203     int res;
204 
205     res = FIFOProcessor::isEmpty();
206     if (res == 0) return 0;
207     return inputBuffer.isEmpty();
208 }
209 
210 
211 //////////////////////////////////////////////////////////////////////////////
212 //
213 // TransposerBase - Base class for interpolation
214 //
215 
216 // static function to set interpolation algorithm
setAlgorithm(TransposerBase::ALGORITHM a)217 void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
218 {
219     TransposerBase::algorithm = a;
220 }
221 
222 
223 // Transposes the sample rate of the given samples using linear interpolation.
224 // Returns the number of samples returned in the "dest" buffer
transpose(FIFOSampleBuffer & dest,FIFOSampleBuffer & src)225 int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
226 {
227     int numSrcSamples = src.numSamples();
228     int sizeDemand = (int)((double)numSrcSamples / rate) + 8;
229     int numOutput;
230     SAMPLETYPE *psrc = src.ptrBegin();
231     SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
232 
233 #ifndef USE_MULTICH_ALWAYS
234     if (numChannels == 1)
235     {
236         numOutput = transposeMono(pdest, psrc, numSrcSamples);
237     }
238     else if (numChannels == 2)
239     {
240         numOutput = transposeStereo(pdest, psrc, numSrcSamples);
241     }
242     else
243 #endif // USE_MULTICH_ALWAYS
244     {
245         assert(numChannels > 0);
246         numOutput = transposeMulti(pdest, psrc, numSrcSamples);
247     }
248     dest.putSamples(numOutput);
249     src.receiveSamples(numSrcSamples);
250     return numOutput;
251 }
252 
253 
TransposerBase()254 TransposerBase::TransposerBase()
255 {
256     numChannels = 0;
257     rate = 1.0f;
258 }
259 
260 
~TransposerBase()261 TransposerBase::~TransposerBase()
262 {
263 }
264 
265 
setChannels(int channels)266 void TransposerBase::setChannels(int channels)
267 {
268     numChannels = channels;
269     resetRegisters();
270 }
271 
272 
setRate(double newRate)273 void TransposerBase::setRate(double newRate)
274 {
275     rate = newRate;
276 }
277 
278 
279 // static factory function
newInstance()280 TransposerBase *TransposerBase::newInstance()
281 {
282 #ifdef SOUNDTOUCH_INTEGER_SAMPLES
283     // Notice: For integer arithmetics support only linear algorithm (due to simplest calculus)
284     return ::new InterpolateLinearInteger;
285 #else
286     switch (algorithm)
287     {
288         case LINEAR:
289             return new InterpolateLinearFloat;
290 
291         case CUBIC:
292             return new InterpolateCubic;
293 
294         case SHANNON:
295             return new InterpolateShannon;
296 
297         default:
298             assert(false);
299             return NULL;
300     }
301 #endif
302 }
303