/[pcsx2_0.9.7]/trunk/3rdparty/SoundTouch/SoundTouch.cpp
ViewVC logotype

Contents of /trunk/3rdparty/SoundTouch/SoundTouch.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Mon Sep 6 13:44:19 2010 UTC (10 years, 2 months ago) by william
File size: 14340 byte(s)
initial checkout of r3113 from upstream repository
1 //////////////////////////////////////////////////////////////////////////////
2 ///
3 /// SoundTouch - main class for tempo/pitch/rate adjusting routines.
4 ///
5 /// Notes:
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.
9 ///
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'.
14 ///
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.
20 ///
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.
26 ///
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
30 /// required.
31 ///
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.
37 ///
38 /// Author : Copyright (c) Olli Parviainen
39 /// Author e-mail : oparviai 'at' iki.fi
40 /// SoundTouch WWW: http://www.surina.net/soundtouch
41 ///
42 ////////////////////////////////////////////////////////////////////////////////
43 //
44 // Last changed : $Date: 2009-05-19 07:57:30 +0300 (Tue, 19 May 2009) $
45 // File revision : $Revision: 4 $
46 //
47 // $Id: SoundTouch.cpp 73 2009-05-19 04:57:30Z oparviai $
48 //
49 ////////////////////////////////////////////////////////////////////////////////
50 //
51 // License :
52 //
53 // SoundTouch audio processing library
54 // Copyright (c) Olli Parviainen
55 //
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.
60 //
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.
65 //
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
69 //
70 ////////////////////////////////////////////////////////////////////////////////
71
72 #include <assert.h>
73 #include <stdlib.h>
74 #include <memory.h>
75 #include <math.h>
76 #include <stdexcept>
77 #include <stdio.h>
78
79 #include "SoundTouch.h"
80 #include "TDStretch.h"
81 #include "RateTransposer.h"
82 #include "cpu_detect.h"
83
84 using namespace soundtouch;
85
86 /// test if two floating point numbers are equal
87 #define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10)
88
89
90 /// Print library version string for autoconf
91 extern "C" void soundtouch_ac_test()
92 {
93 printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
94 }
95
96
97 SoundTouch::SoundTouch()
98 {
99 // Initialize rate transposer and tempo changer instances
100
101 pRateTransposer = RateTransposer::newInstance();
102 pTDStretch = TDStretch::newInstance();
103
104 setOutPipe(pTDStretch);
105
106 rate = tempo = 0;
107
108 virtualPitch =
109 virtualRate =
110 virtualTempo = 1.0;
111
112 calcEffectiveRateAndTempo();
113
114 channels = 0;
115 bSrateSet = FALSE;
116 }
117
118
119
120 SoundTouch::~SoundTouch()
121 {
122 delete pRateTransposer;
123 delete pTDStretch;
124 }
125
126
127
128 /// Get SoundTouch library version string
129 const char *SoundTouch::getVersionString()
130 {
131 static const char *_version = SOUNDTOUCH_VERSION;
132
133 return _version;
134 }
135
136
137 /// Get SoundTouch library version Id
138 uint SoundTouch::getVersionId()
139 {
140 return SOUNDTOUCH_VERSION_ID;
141 }
142
143
144 // Sets the number of channels, 1 = mono, 2 = stereo
145 void SoundTouch::setChannels(uint numChannels)
146 {
147 if (numChannels != 1 && numChannels != 2)
148 {
149 throw std::runtime_error("Illegal number of channels");
150 }
151 channels = numChannels;
152 pRateTransposer->setChannels((int)numChannels);
153 pTDStretch->setChannels((int)numChannels);
154 }
155
156
157
158 // Sets new rate control value. Normal rate = 1.0, smaller values
159 // represent slower rate, larger faster rates.
160 void SoundTouch::setRate(float newRate)
161 {
162 virtualRate = newRate;
163 calcEffectiveRateAndTempo();
164 }
165
166
167
168 // Sets new rate control value as a difference in percents compared
169 // to the original rate (-50 .. +100 %)
170 void SoundTouch::setRateChange(float newRate)
171 {
172 virtualRate = 1.0f + 0.01f * newRate;
173 calcEffectiveRateAndTempo();
174 }
175
176
177
178 // Sets new tempo control value. Normal tempo = 1.0, smaller values
179 // represent slower tempo, larger faster tempo.
180 void SoundTouch::setTempo(float newTempo)
181 {
182 virtualTempo = newTempo;
183 calcEffectiveRateAndTempo();
184 }
185
186
187
188 // Sets new tempo control value as a difference in percents compared
189 // to the original tempo (-50 .. +100 %)
190 void SoundTouch::setTempoChange(float newTempo)
191 {
192 virtualTempo = 1.0f + 0.01f * newTempo;
193 calcEffectiveRateAndTempo();
194 }
195
196
197
198 // Sets new pitch control value. Original pitch = 1.0, smaller values
199 // represent lower pitches, larger values higher pitch.
200 void SoundTouch::setPitch(float newPitch)
201 {
202 virtualPitch = newPitch;
203 calcEffectiveRateAndTempo();
204 }
205
206
207
208 // Sets pitch change in octaves compared to the original pitch
209 // (-1.00 .. +1.00)
210 void SoundTouch::setPitchOctaves(float newPitch)
211 {
212 virtualPitch = (float)exp(0.69314718056f * newPitch);
213 calcEffectiveRateAndTempo();
214 }
215
216
217
218 // Sets pitch change in semi-tones compared to the original pitch
219 // (-12 .. +12)
220 void SoundTouch::setPitchSemiTones(int newPitch)
221 {
222 setPitchOctaves((float)newPitch / 12.0f);
223 }
224
225
226
227 void SoundTouch::setPitchSemiTones(float newPitch)
228 {
229 setPitchOctaves(newPitch / 12.0f);
230 }
231
232
233 // Calculates 'effective' rate and tempo values from the
234 // nominal control values.
235 void SoundTouch::calcEffectiveRateAndTempo()
236 {
237 float oldTempo = tempo;
238 float oldRate = rate;
239
240 tempo = virtualTempo / virtualPitch;
241 rate = virtualPitch * virtualRate;
242
243 if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);
244 if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);
245
246 #ifndef PREVENT_CLICK_AT_RATE_CROSSOVER
247 if (rate <= 1.0f)
248 {
249 if (output != pTDStretch)
250 {
251 FIFOSamplePipe *tempoOut;
252
253 assert(output == pRateTransposer);
254 // move samples in the current output buffer to the output of pTDStretch
255 tempoOut = pTDStretch->getOutput();
256 tempoOut->moveSamples(*output);
257 // move samples in pitch transposer's store buffer to tempo changer's input
258 pTDStretch->moveSamples(*pRateTransposer->getStore());
259
260 output = pTDStretch;
261 }
262 }
263 else
264 #endif
265 {
266 if (output != pRateTransposer)
267 {
268 FIFOSamplePipe *transOut;
269
270 assert(output == pTDStretch);
271 // move samples in the current output buffer to the output of pRateTransposer
272 transOut = pRateTransposer->getOutput();
273 transOut->moveSamples(*output);
274 // move samples in tempo changer's input to pitch transposer's input
275 pRateTransposer->moveSamples(*pTDStretch->getInput());
276
277 output = pRateTransposer;
278 }
279 }
280 }
281
282
283 // Sets sample rate.
284 void SoundTouch::setSampleRate(uint srate)
285 {
286 bSrateSet = TRUE;
287 // set sample rate, leave other tempo changer parameters as they are.
288 pTDStretch->setParameters((int)srate);
289 }
290
291
292 // Adds 'numSamples' pcs of samples from the 'samples' memory position into
293 // the input of the object.
294 void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
295 {
296 if (bSrateSet == FALSE)
297 {
298 throw std::runtime_error("SoundTouch : Sample rate not defined");
299 }
300 else if (channels == 0)
301 {
302 throw std::runtime_error("SoundTouch : Number of channels not defined");
303 }
304
305 // Transpose the rate of the new samples if necessary
306 /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
307 if (rate == 1.0f)
308 {
309 // The rate value is same as the original, simply evaluate the tempo changer.
310 assert(output == pTDStretch);
311 if (pRateTransposer->isEmpty() == 0)
312 {
313 // yet flush the last samples in the pitch transposer buffer
314 // (may happen if 'rate' changes from a non-zero value to zero)
315 pTDStretch->moveSamples(*pRateTransposer);
316 }
317 pTDStretch->putSamples(samples, nSamples);
318 }
319 */
320 #ifndef PREVENT_CLICK_AT_RATE_CROSSOVER
321 else if (rate <= 1.0f)
322 {
323 // transpose the rate down, output the transposed sound to tempo changer buffer
324 assert(output == pTDStretch);
325 pRateTransposer->putSamples(samples, nSamples);
326 pTDStretch->moveSamples(*pRateTransposer);
327 }
328 else
329 #endif
330 {
331 // evaluate the tempo changer, then transpose the rate up,
332 assert(output == pRateTransposer);
333 pTDStretch->putSamples(samples, nSamples);
334 pRateTransposer->moveSamples(*pTDStretch);
335 }
336 }
337
338
339 // Flushes the last samples from the processing pipeline to the output.
340 // Clears also the internal processing buffers.
341 //
342 // Note: This function is meant for extracting the last samples of a sound
343 // stream. This function may introduce additional blank samples in the end
344 // of the sound stream, and thus it's not recommended to call this function
345 // in the middle of a sound stream.
346 void SoundTouch::flush()
347 {
348 int i;
349 uint nOut;
350 SAMPLETYPE buff[128];
351
352 nOut = numSamples();
353
354 memset(buff, 0, 128 * sizeof(SAMPLETYPE));
355 // "Push" the last active samples out from the processing pipeline by
356 // feeding blank samples into the processing pipeline until new,
357 // processed samples appear in the output (not however, more than
358 // 8ksamples in any case)
359 for (i = 0; i < 128; i ++)
360 {
361 putSamples(buff, 64);
362 if (numSamples() != nOut) break; // new samples have appeared in the output!
363 }
364
365 // Clear working buffers
366 pRateTransposer->clear();
367 pTDStretch->clearInput();
368 // yet leave the 'tempoChanger' output intouched as that's where the
369 // flushed samples are!
370 }
371
372
373 // Changes a setting controlling the processing system behaviour. See the
374 // 'SETTING_...' defines for available setting ID's.
375 BOOL SoundTouch::setSetting(int settingId, int value)
376 {
377 int sampleRate, sequenceMs, seekWindowMs, overlapMs;
378
379 // read current tdstretch routine parameters
380 pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
381
382 switch (settingId)
383 {
384 case SETTING_USE_AA_FILTER :
385 // enables / disabless anti-alias filter
386 pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
387 return TRUE;
388
389 case SETTING_AA_FILTER_LENGTH :
390 // sets anti-alias filter length
391 pRateTransposer->getAAFilter()->setLength(value);
392 return TRUE;
393
394 case SETTING_USE_QUICKSEEK :
395 // enables / disables tempo routine quick seeking algorithm
396 pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
397 return TRUE;
398
399 case SETTING_SEQUENCE_MS:
400 // change time-stretch sequence duration parameter
401 pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
402 return TRUE;
403
404 case SETTING_SEEKWINDOW_MS:
405 // change time-stretch seek window length parameter
406 pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
407 return TRUE;
408
409 case SETTING_OVERLAP_MS:
410 // change time-stretch overlap length parameter
411 pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
412 return TRUE;
413
414 default :
415 return FALSE;
416 }
417 }
418
419
420 // Reads a setting controlling the processing system behaviour. See the
421 // 'SETTING_...' defines for available setting ID's.
422 //
423 // Returns the setting value.
424 int SoundTouch::getSetting(int settingId) const
425 {
426 int temp;
427
428 switch (settingId)
429 {
430 case SETTING_USE_AA_FILTER :
431 return (uint)pRateTransposer->isAAFilterEnabled();
432
433 case SETTING_AA_FILTER_LENGTH :
434 return pRateTransposer->getAAFilter()->getLength();
435
436 case SETTING_USE_QUICKSEEK :
437 return (uint) pTDStretch->isQuickSeekEnabled();
438
439 case SETTING_SEQUENCE_MS:
440 pTDStretch->getParameters(NULL, &temp, NULL, NULL);
441 return temp;
442
443 case SETTING_SEEKWINDOW_MS:
444 pTDStretch->getParameters(NULL, NULL, &temp, NULL);
445 return temp;
446
447 case SETTING_OVERLAP_MS:
448 pTDStretch->getParameters(NULL, NULL, NULL, &temp);
449 return temp;
450
451 default :
452 return 0;
453 }
454 }
455
456
457 // Clears all the samples in the object's output and internal processing
458 // buffers.
459 void SoundTouch::clear()
460 {
461 pRateTransposer->clear();
462 pTDStretch->clear();
463 }
464
465
466
467 /// Returns number of samples currently unprocessed.
468 uint SoundTouch::numUnprocessedSamples() const
469 {
470 FIFOSamplePipe * psp;
471 if (pTDStretch)
472 {
473 psp = pTDStretch->getInput();
474 if (psp)
475 {
476 return psp->numSamples();
477 }
478 }
479 return 0;
480 }

  ViewVC Help
Powered by ViewVC 1.1.22