00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00071
00072 #include <assert.h>
00073 #include <stdlib.h>
00074 #include <memory.h>
00075 #include <math.h>
00076 #include <stdexcept>
00077 #include <stdio.h>
00078
00079 #include "SoundTouch.h"
00080 #include "TDStretch.h"
00081 #include "RateTransposer.h"
00082 #include "cpu_detect.h"
00083
00084 using namespace soundtouch;
00085
00087 extern "C" void soundtouch_ac_test()
00088 {
00089 printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
00090 }
00091
00092
00093 SoundTouch::SoundTouch()
00094 {
00095
00096
00097 pRateTransposer = RateTransposer::newInstance();
00098 pTDStretch = TDStretch::newInstance();
00099
00100 setOutPipe(pTDStretch);
00101
00102 rate = tempo = 0;
00103
00104 virtualPitch =
00105 virtualRate =
00106 virtualTempo = 1.0;
00107
00108 calcEffectiveRateAndTempo();
00109
00110 channels = 0;
00111 bSrateSet = FALSE;
00112 }
00113
00114
00115
00116 SoundTouch::~SoundTouch()
00117 {
00118 delete pRateTransposer;
00119 delete pTDStretch;
00120 }
00121
00122
00123
00125 const char *SoundTouch::getVersionString()
00126 {
00127 static const char *_version = SOUNDTOUCH_VERSION;
00128
00129 return _version;
00130 }
00131
00132
00134 uint SoundTouch::getVersionId()
00135 {
00136 return SOUNDTOUCH_VERSION_ID;
00137 }
00138
00139
00140
00141 void SoundTouch::setChannels(uint numChannels)
00142 {
00143 #ifdef MULTICHANNEL
00144 if (numChannels < 1 || numChannels > MULTICHANNEL)
00145 #else
00146 if (numChannels != 1 && numChannels != 2)
00147 #endif
00148 {
00149 throw std::runtime_error("Illegal number of channels");
00150 }
00151 channels = numChannels;
00152 pRateTransposer->setChannels(numChannels);
00153 pTDStretch->setChannels(numChannels);
00154 }
00155
00156
00157
00158
00159
00160 void SoundTouch::setRate(float newRate)
00161 {
00162 virtualRate = newRate;
00163 calcEffectiveRateAndTempo();
00164 }
00165
00166
00167
00168
00169
00170 void SoundTouch::setRateChange(float newRate)
00171 {
00172 virtualRate = 1.0f + 0.01f * newRate;
00173 calcEffectiveRateAndTempo();
00174 }
00175
00176
00177
00178
00179
00180 void SoundTouch::setTempo(float newTempo)
00181 {
00182 virtualTempo = newTempo;
00183 calcEffectiveRateAndTempo();
00184 }
00185
00186
00187
00188
00189
00190 void SoundTouch::setTempoChange(float newTempo)
00191 {
00192 virtualTempo = 1.0f + 0.01f * newTempo;
00193 calcEffectiveRateAndTempo();
00194 }
00195
00196
00197
00198
00199
00200 void SoundTouch::setPitch(float newPitch)
00201 {
00202 virtualPitch = newPitch;
00203 calcEffectiveRateAndTempo();
00204 }
00205
00206
00207
00208
00209
00210 void SoundTouch::setPitchOctaves(float newPitch)
00211 {
00212 virtualPitch = (float)exp(0.69314718056f * newPitch);
00213 calcEffectiveRateAndTempo();
00214 }
00215
00216
00217
00218
00219
00220 void SoundTouch::setPitchSemiTones(int newPitch)
00221 {
00222 setPitchOctaves((float)newPitch / 12.0f);
00223 }
00224
00225
00226
00227 void SoundTouch::setPitchSemiTones(float newPitch)
00228 {
00229 setPitchOctaves(newPitch / 12.0f);
00230 }
00231
00232
00233
00234
00235 void SoundTouch::calcEffectiveRateAndTempo()
00236 {
00237 float oldTempo = tempo;
00238 float oldRate = rate;
00239
00240 tempo = virtualTempo / virtualPitch;
00241 rate = virtualPitch * virtualRate;
00242
00243 if (rate != oldRate) pRateTransposer->setRate(rate);
00244 if (tempo != oldTempo) pTDStretch->setTempo(tempo);
00245
00246 if (rate > 1.0f)
00247 {
00248 if (output != pRateTransposer)
00249 {
00250 FIFOSamplePipe *transOut;
00251
00252 assert(output == pTDStretch);
00253
00254 transOut = pRateTransposer->getOutput();
00255 transOut->moveSamples(*output);
00256
00257 pRateTransposer->moveSamples(*pTDStretch->getInput());
00258
00259 output = pRateTransposer;
00260 }
00261 }
00262 else
00263 {
00264 if (output != pTDStretch)
00265 {
00266 FIFOSamplePipe *tempoOut;
00267
00268 assert(output == pRateTransposer);
00269
00270 tempoOut = pTDStretch->getOutput();
00271 tempoOut->moveSamples(*output);
00272
00273 pTDStretch->moveSamples(*pRateTransposer->getStore());
00274
00275 output = pTDStretch;
00276
00277 }
00278 }
00279 }
00280
00281
00282
00283 void SoundTouch::setSampleRate(uint srate)
00284 {
00285 bSrateSet = TRUE;
00286
00287 pTDStretch->setParameters(srate);
00288 }
00289
00290
00291
00292
00293 void SoundTouch::putSamples(const SAMPLETYPE *samples, uint numSamples)
00294 {
00295 if (bSrateSet == FALSE)
00296 {
00297 throw std::runtime_error("SoundTouch : Sample rate not defined");
00298 }
00299 else if (channels == 0)
00300 {
00301 throw std::runtime_error("SoundTouch : Number of channels not defined");
00302 }
00303
00304
00305
00306
00307
00308
00309 if (rate == 1.0f)
00310 {
00311
00312 assert(output == pTDStretch);
00313 if (pRateTransposer->isEmpty() == 0)
00314 {
00315
00316
00317 pTDStretch->moveSamples(*pRateTransposer);
00318 }
00319 pTDStretch->putSamples(samples, numSamples);
00320 }
00321 else if (rate <= 1.0f)
00322 {
00323
00324 assert(output == pTDStretch);
00325 pRateTransposer->putSamples(samples, numSamples);
00326 pTDStretch->moveSamples(*pRateTransposer);
00327 }
00328 else
00329 {
00330 assert(rate > 1.0f);
00331
00332 assert(output == pRateTransposer);
00333 pTDStretch->putSamples(samples, numSamples);
00334 pRateTransposer->moveSamples(*pTDStretch);
00335 }
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 void SoundTouch::flush()
00347 {
00348 int i;
00349 uint nOut;
00350 SAMPLETYPE buff[128];
00351
00352 nOut = numSamples();
00353
00354 memset(buff, 0, 128 * sizeof(SAMPLETYPE));
00355
00356
00357
00358
00359 for (i = 0; i < 128; i ++)
00360 {
00361 putSamples(buff, 64);
00362 if (numSamples() != nOut) break;
00363 }
00364
00365
00366 pRateTransposer->clear();
00367 pTDStretch->clearInput();
00368
00369
00370 }
00371
00372
00373
00374
00375 BOOL SoundTouch::setSetting(uint settingId, uint value)
00376 {
00377 uint sampleRate, sequenceMs, seekWindowMs, overlapMs;
00378
00379
00380 pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
00381
00382 switch (settingId)
00383 {
00384 case SETTING_USE_AA_FILTER :
00385
00386 pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
00387 return TRUE;
00388
00389 case SETTING_AA_FILTER_LENGTH :
00390
00391 pRateTransposer->getAAFilter()->setLength(value);
00392 return TRUE;
00393
00394 case SETTING_USE_QUICKSEEK :
00395
00396 pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
00397 return TRUE;
00398
00399 case SETTING_SEQUENCE_MS:
00400
00401 pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
00402 return TRUE;
00403
00404 case SETTING_SEEKWINDOW_MS:
00405
00406 pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
00407 return TRUE;
00408
00409 case SETTING_OVERLAP_MS:
00410
00411 pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
00412 return TRUE;
00413
00414 default :
00415 return FALSE;
00416 }
00417 }
00418
00419
00420
00421
00422
00423
00424 uint SoundTouch::getSetting(uint settingId) const
00425 {
00426 uint temp;
00427
00428 switch (settingId)
00429 {
00430 case SETTING_USE_AA_FILTER :
00431 return pRateTransposer->isAAFilterEnabled();
00432
00433 case SETTING_AA_FILTER_LENGTH :
00434 return pRateTransposer->getAAFilter()->getLength();
00435
00436 case SETTING_USE_QUICKSEEK :
00437 return pTDStretch->isQuickSeekEnabled();
00438
00439 case SETTING_SEQUENCE_MS:
00440 pTDStretch->getParameters(NULL, &temp, NULL, NULL);
00441 return temp;
00442
00443 case SETTING_SEEKWINDOW_MS:
00444 pTDStretch->getParameters(NULL, NULL, &temp, NULL);
00445 return temp;
00446
00447 case SETTING_OVERLAP_MS:
00448 pTDStretch->getParameters(NULL, NULL, NULL, &temp);
00449 return temp;
00450
00451 default :
00452 return 0;
00453 }
00454 }
00455
00456
00457
00458
00459 void SoundTouch::clear()
00460 {
00461 pRateTransposer->clear();
00462 pTDStretch->clear();
00463 }
00464
00465
00466
00468 uint SoundTouch::numUnprocessedSamples() const
00469 {
00470 FIFOSamplePipe * psp;
00471 if (pTDStretch)
00472 {
00473 psp = pTDStretch->getInput();
00474 if (psp)
00475 {
00476 return psp->numSamples();
00477 }
00478 }
00479 return 0;
00480 }