1 //////////////////////////////////////////////////////////////////////////////
3 /// SoundTouch - main class for tempo/pitch/rate adjusting routines.
6 /// - Initialize the SoundTouch object instance by setting up the sound stream
7 /// parameters with functions 'setSampleRate' and 'setChannels', then set
8 /// desired tempo/pitch/rate settings with the corresponding functions.
10 /// - The SoundTouch class behaves like a first-in-first-out pipeline: The
11 /// samples that are to be processed are fed into one of the pipe by calling
12 /// function 'putSamples', while the ready processed samples can be read
13 /// from the other end of the pipeline with function 'receiveSamples'.
15 /// - The SoundTouch processing classes require certain sized 'batches' of
16 /// samples in order to process the sound. For this reason the classes buffer
17 /// incoming samples until there are enough of samples available for
18 /// processing, then they carry out the processing step and consequently
19 /// make the processed samples available for outputting.
21 /// - For the above reason, the processing routines introduce a certain
22 /// 'latency' between the input and output, so that the samples input to
23 /// SoundTouch may not be immediately available in the output, and neither
24 /// the amount of outputtable samples may not immediately be in direct
25 /// relationship with the amount of previously input samples.
27 /// - The tempo/pitch/rate control parameters can be altered during processing.
28 /// Please notice though that they aren't currently protected by semaphores,
29 /// so in multi-thread application external semaphore protection may be
32 /// - This class utilizes classes 'TDStretch' for tempo change (without modifying
33 /// pitch) and 'RateTransposer' for changing the playback rate (that is, both
34 /// tempo and pitch in the same ratio) of the sound. The third available control
35 /// 'pitch' (change pitch but maintain tempo) is produced by a combination of
36 /// combining the two other controls.
38 /// Author : Copyright (c) Olli Parviainen
39 /// Author e-mail : oparviai @ iki.fi
40 /// SoundTouch WWW: http://www.iki.fi/oparviai/soundtouch
42 ////////////////////////////////////////////////////////////////////////////////
44 // Last changed : $Date$
45 // File revision : $Revision$
49 ////////////////////////////////////////////////////////////////////////////////
53 // SoundTouch audio processing library
54 // Copyright (c) Olli Parviainen
56 // This library is free software; you can redistribute it and/or
57 // modify it under the terms of the GNU Lesser General Public
58 // License as published by the Free Software Foundation; either
59 // version 2.1 of the License, or (at your option) any later version.
61 // This library is distributed in the hope that it will be useful,
62 // but WITHOUT ANY WARRANTY; without even the implied warranty of
63 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
64 // Lesser General Public License for more details.
66 // You should have received a copy of the GNU Lesser General Public
67 // License along with this library; if not, write to the Free Software
68 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
70 ////////////////////////////////////////////////////////////////////////////////
79 #include "SoundTouch.h"
80 #include "TDStretch.h"
81 #include "RateTransposer.h"
82 #include "cpu_detect.h"
84 using namespace soundtouch;
86 /// Print library version string
87 extern "C" void soundtouch_ac_test()
89 printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
93 SoundTouch::SoundTouch()
95 // Initialize rate transposer and tempo changer instances
97 pRateTransposer = RateTransposer::newInstance();
98 pTDStretch = TDStretch::newInstance();
100 setOutPipe(pTDStretch);
108 calcEffectiveRateAndTempo();
116 SoundTouch::~SoundTouch()
118 delete pRateTransposer;
124 /// Get SoundTouch library version string
125 const char *SoundTouch::getVersionString()
127 static const char *_version = SOUNDTOUCH_VERSION;
133 /// Get SoundTouch library version Id
134 uint SoundTouch::getVersionId()
136 return SOUNDTOUCH_VERSION_ID;
140 // Sets the number of channels, 1 = mono, 2 = stereo
141 void SoundTouch::setChannels(uint numChannels)
143 if (numChannels != 1 && numChannels != 2)
145 throw std::runtime_error("Illegal number of channels");
147 channels = numChannels;
148 pRateTransposer->setChannels(numChannels);
149 pTDStretch->setChannels(numChannels);
154 // Sets new rate control value. Normal rate = 1.0, smaller values
155 // represent slower rate, larger faster rates.
156 void SoundTouch::setRate(float newRate)
158 virtualRate = newRate;
159 calcEffectiveRateAndTempo();
164 // Sets new rate control value as a difference in percents compared
165 // to the original rate (-50 .. +100 %)
166 void SoundTouch::setRateChange(float newRate)
168 virtualRate = 1.0f + 0.01f * newRate;
169 calcEffectiveRateAndTempo();
174 // Sets new tempo control value. Normal tempo = 1.0, smaller values
175 // represent slower tempo, larger faster tempo.
176 void SoundTouch::setTempo(float newTempo)
178 virtualTempo = newTempo;
179 calcEffectiveRateAndTempo();
184 // Sets new tempo control value as a difference in percents compared
185 // to the original tempo (-50 .. +100 %)
186 void SoundTouch::setTempoChange(float newTempo)
188 virtualTempo = 1.0f + 0.01f * newTempo;
189 calcEffectiveRateAndTempo();
194 // Sets new pitch control value. Original pitch = 1.0, smaller values
195 // represent lower pitches, larger values higher pitch.
196 void SoundTouch::setPitch(float newPitch)
198 virtualPitch = newPitch;
199 calcEffectiveRateAndTempo();
204 // Sets pitch change in octaves compared to the original pitch
206 void SoundTouch::setPitchOctaves(float newPitch)
208 virtualPitch = (float)exp(0.69314718056f * newPitch);
209 calcEffectiveRateAndTempo();
214 // Sets pitch change in semi-tones compared to the original pitch
216 void SoundTouch::setPitchSemiTones(int newPitch)
218 setPitchOctaves((float)newPitch / 12.0f);
223 void SoundTouch::setPitchSemiTones(float newPitch)
225 setPitchOctaves(newPitch / 12.0f);
229 // Calculates 'effective' rate and tempo values from the
230 // nominal control values.
231 void SoundTouch::calcEffectiveRateAndTempo()
233 float oldTempo = tempo;
234 float oldRate = rate;
236 tempo = virtualTempo / virtualPitch;
237 rate = virtualPitch * virtualRate;
239 if (rate != oldRate) pRateTransposer->setRate(rate);
240 if (tempo != oldTempo) pTDStretch->setTempo(tempo);
244 if (output != pRateTransposer)
246 FIFOSamplePipe *transOut;
248 assert(output == pTDStretch);
249 // move samples in the current output buffer to the output of pRateTransposer
250 transOut = pRateTransposer->getOutput();
251 transOut->moveSamples(*output);
252 // move samples in tempo changer's input to pitch transposer's input
253 pRateTransposer->moveSamples(*pTDStretch->getInput());
255 output = pRateTransposer;
260 if (output != pTDStretch)
262 FIFOSamplePipe *tempoOut;
264 assert(output == pRateTransposer);
265 // move samples in the current output buffer to the output of pTDStretch
266 tempoOut = pTDStretch->getOutput();
267 tempoOut->moveSamples(*output);
268 // move samples in pitch transposer's store buffer to tempo changer's input
269 pTDStretch->moveSamples(*pRateTransposer->getStore());
279 void SoundTouch::setSampleRate(uint srate)
282 // set sample rate, leave other tempo changer parameters as they are.
283 pTDStretch->setParameters(srate);
287 // Adds 'numSamples' pcs of samples from the 'samples' memory position into
288 // the input of the object.
289 void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples)
291 if (bSrateSet == FALSE)
293 throw std::runtime_error("SoundTouch : Sample rate not defined");
295 else if (channels == 0)
297 throw std::runtime_error("SoundTouch : Number of channels not defined");
300 // Transpose the rate of the new samples if necessary
303 // The rate value is same as the original, simply evaluate the tempo changer.
304 assert(output == pTDStretch);
305 if (pRateTransposer->isEmpty() == 0)
307 // yet flush the last samples in the pitch transposer buffer
308 // (may happen if 'rate' changes from a non-zero value to zero)
309 pTDStretch->moveSamples(*pRateTransposer);
311 pTDStretch->putSamples(samples, numSamples);
313 else if (rate < 1.0f)
315 // transpose the rate down, output the transposed sound to tempo changer buffer
316 assert(output == pTDStretch);
317 pRateTransposer->putSamples(samples, numSamples);
318 pTDStretch->moveSamples(*pRateTransposer);
323 // evaluate the tempo changer, then transpose the rate up,
324 assert(output == pRateTransposer);
325 pTDStretch->putSamples(samples, numSamples);
326 pRateTransposer->moveSamples(*pTDStretch);
331 // Flushes the last samples from the processing pipeline to the output.
332 // Clears also the internal processing buffers.
334 // Note: This function is meant for extracting the last samples of a sound
335 // stream. This function may introduce additional blank samples in the end
336 // of the sound stream, and thus it's not recommended to call this function
337 // in the middle of a sound stream.
338 void SoundTouch::flush()
342 SAMPLETYPE buff[128];
346 memset(buff, 0, 128 * sizeof(SAMPLETYPE));
347 // "Push" the last active samples out from the processing pipeline by
348 // feeding blank samples into the processing pipeline until new,
349 // processed samples appear in the output (not however, more than
350 // 8ksamples in any case)
351 for (i = 0; i < 128; i ++)
353 putSamples(buff, 64);
354 if (numSamples() != nOut) break; // new samples have appeared in the output!
357 // Clear working buffers
358 pRateTransposer->clear();
359 pTDStretch->clearInput();
360 // yet leave the 'tempoChanger' output intouched as that's where the
361 // flushed samples are!
365 // Changes a setting controlling the processing system behaviour. See the
366 // 'SETTING_...' defines for available setting ID's.
367 BOOL SoundTouch::setSetting(uint settingId, uint value)
369 uint sampleRate, sequenceMs, seekWindowMs, overlapMs;
371 // read current tdstretch routine parameters
372 pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
376 case SETTING_USE_AA_FILTER :
377 // enables / disabless anti-alias filter
378 pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
381 case SETTING_AA_FILTER_LENGTH :
382 // sets anti-alias filter length
383 pRateTransposer->getAAFilter()->setLength(value);
386 case SETTING_USE_QUICKSEEK :
387 // enables / disables tempo routine quick seeking algorithm
388 pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
391 case SETTING_SEQUENCE_MS:
392 // change time-stretch sequence duration parameter
393 pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
396 case SETTING_SEEKWINDOW_MS:
397 // change time-stretch seek window length parameter
398 pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
401 case SETTING_OVERLAP_MS:
402 // change time-stretch overlap length parameter
403 pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
412 // Reads a setting controlling the processing system behaviour. See the
413 // 'SETTING_...' defines for available setting ID's.
415 // Returns the setting value.
416 uint SoundTouch::getSetting(uint settingId) const
422 case SETTING_USE_AA_FILTER :
423 return pRateTransposer->isAAFilterEnabled();
425 case SETTING_AA_FILTER_LENGTH :
426 return pRateTransposer->getAAFilter()->getLength();
428 case SETTING_USE_QUICKSEEK :
429 return pTDStretch->isQuickSeekEnabled();
431 case SETTING_SEQUENCE_MS:
432 pTDStretch->getParameters(NULL, &temp, NULL, NULL);
435 case SETTING_SEEKWINDOW_MS:
436 pTDStretch->getParameters(NULL, NULL, &temp, NULL);
439 case SETTING_OVERLAP_MS:
440 pTDStretch->getParameters(NULL, NULL, NULL, &temp);
449 // Clears all the samples in the object's output and internal processing
451 void SoundTouch::clear()
453 pRateTransposer->clear();
459 /// Returns number of samples currently unprocessed.
460 uint SoundTouch::numUnprocessedSamples() const
462 FIFOSamplePipe * psp;
465 psp = pTDStretch->getInput();
468 return psp->numSamples();