MythTV  0.26-pre
SoundTouch.cpp
Go to the documentation of this file.
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 // Last changed  : $Date$
00045 // File revision : $Revision$
00046 //
00047 // $Id$
00048 //
00050 //
00051 // License :
00052 //
00053 //  SoundTouch audio processing library
00054 //  Copyright (c) Olli Parviainen
00055 //
00056 //  This library is free software; you can redistribute it and/or
00057 //  modify it under the terms of the GNU Lesser General Public
00058 //  License as published by the Free Software Foundation; either
00059 //  version 2.1 of the License, or (at your option) any later version.
00060 //
00061 //  This library is distributed in the hope that it will be useful,
00062 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00063 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00064 //  Lesser General Public License for more details.
00065 //
00066 //  You should have received a copy of the GNU Lesser General Public
00067 //  License along with this library; if not, write to the Free Software
00068 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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     // Initialize rate transposer and tempo changer instances
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 // Sets the number of channels, 1 = mono, 2 = stereo
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 // Sets new rate control value. Normal rate = 1.0, smaller values
00159 // represent slower rate, larger faster rates.
00160 void SoundTouch::setRate(float newRate)
00161 {
00162     virtualRate = newRate;
00163     calcEffectiveRateAndTempo();
00164 }
00165 
00166 
00167 
00168 // Sets new rate control value as a difference in percents compared
00169 // to the original rate (-50 .. +100 %)
00170 void SoundTouch::setRateChange(float newRate)
00171 {
00172     virtualRate = 1.0f + 0.01f * newRate;
00173     calcEffectiveRateAndTempo();
00174 }
00175 
00176 
00177 
00178 // Sets new tempo control value. Normal tempo = 1.0, smaller values
00179 // represent slower tempo, larger faster tempo.
00180 void SoundTouch::setTempo(float newTempo)
00181 {
00182     virtualTempo = newTempo;
00183     calcEffectiveRateAndTempo();
00184 }
00185 
00186 
00187 
00188 // Sets new tempo control value as a difference in percents compared
00189 // to the original tempo (-50 .. +100 %)
00190 void SoundTouch::setTempoChange(float newTempo)
00191 {
00192     virtualTempo = 1.0f + 0.01f * newTempo;
00193     calcEffectiveRateAndTempo();
00194 }
00195 
00196 
00197 
00198 // Sets new pitch control value. Original pitch = 1.0, smaller values
00199 // represent lower pitches, larger values higher pitch.
00200 void SoundTouch::setPitch(float newPitch)
00201 {
00202     virtualPitch = newPitch;
00203     calcEffectiveRateAndTempo();
00204 }
00205 
00206 
00207 
00208 // Sets pitch change in octaves compared to the original pitch
00209 // (-1.00 .. +1.00)
00210 void SoundTouch::setPitchOctaves(float newPitch)
00211 {
00212     virtualPitch = (float)exp(0.69314718056f * newPitch);
00213     calcEffectiveRateAndTempo();
00214 }
00215 
00216 
00217 
00218 // Sets pitch change in semi-tones compared to the original pitch
00219 // (-12 .. +12)
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 // Calculates 'effective' rate and tempo values from the
00234 // nominal control values.
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             // move samples in the current output buffer to the output of pRateTransposer
00254             transOut = pRateTransposer->getOutput();
00255             transOut->moveSamples(*output);
00256             // move samples in tempo changer's input to pitch transposer's input
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             // move samples in the current output buffer to the output of pTDStretch
00270             tempoOut = pTDStretch->getOutput();
00271             tempoOut->moveSamples(*output);
00272             // move samples in pitch transposer's store buffer to tempo changer's input
00273             pTDStretch->moveSamples(*pRateTransposer->getStore());
00274 
00275             output = pTDStretch;
00276 
00277         }
00278     }
00279 }
00280 
00281 
00282 // Sets sample rate.
00283 void SoundTouch::setSampleRate(uint srate)
00284 {
00285     bSrateSet = TRUE;
00286     // set sample rate, leave other tempo changer parameters as they are.
00287     pTDStretch->setParameters(srate);
00288 }
00289 
00290 
00291 // Adds 'numSamples' pcs of samples from the 'samples' memory position into
00292 // the input of the object.
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     // Transpose the rate of the new samples if necessary
00305     /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
00306      */
00307     // NOTE: Removed the bypass change in soundtouch 1.3.1 for MythTV, this
00308     //       caused clipping for Cougar with our MMX implementation. -- dtk
00309     if (rate == 1.0f) 
00310     {
00311         // The rate value is same as the original, simply evaluate the tempo changer. 
00312         assert(output == pTDStretch);
00313         if (pRateTransposer->isEmpty() == 0) 
00314         {
00315             // yet flush the last samples in the pitch transposer buffer
00316             // (may happen if 'rate' changes from a non-zero value to zero)
00317             pTDStretch->moveSamples(*pRateTransposer);
00318         }
00319         pTDStretch->putSamples(samples, numSamples);
00320     } 
00321     else if (rate <= 1.0f) 
00322     {
00323         // transpose the rate down, output the transposed sound to tempo changer buffer
00324         assert(output == pTDStretch);
00325         pRateTransposer->putSamples(samples, numSamples);
00326         pTDStretch->moveSamples(*pRateTransposer);
00327     } 
00328     else 
00329     {
00330         assert(rate > 1.0f);
00331         // evaluate the tempo changer, then transpose the rate up, 
00332         assert(output == pRateTransposer);
00333         pTDStretch->putSamples(samples, numSamples);
00334         pRateTransposer->moveSamples(*pTDStretch);
00335     }
00336 }
00337 
00338 
00339 // Flushes the last samples from the processing pipeline to the output.
00340 // Clears also the internal processing buffers.
00341 //
00342 // Note: This function is meant for extracting the last samples of a sound
00343 // stream. This function may introduce additional blank samples in the end
00344 // of the sound stream, and thus it's not recommended to call this function
00345 // in the middle of a sound stream.
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     // "Push" the last active samples out from the processing pipeline by
00356     // feeding blank samples into the processing pipeline until new, 
00357     // processed samples appear in the output (not however, more than 
00358     // 8ksamples in any case)
00359     for (i = 0; i < 128; i ++) 
00360     {
00361         putSamples(buff, 64);
00362         if (numSamples() != nOut) break;  // new samples have appeared in the output!
00363     }
00364 
00365     // Clear working buffers
00366     pRateTransposer->clear();
00367     pTDStretch->clearInput();
00368     // yet leave the 'tempoChanger' output intouched as that's where the
00369     // flushed samples are!
00370 }
00371 
00372 
00373 // Changes a setting controlling the processing system behaviour. See the
00374 // 'SETTING_...' defines for available setting ID's.
00375 BOOL SoundTouch::setSetting(uint settingId, uint value)
00376 {
00377     uint sampleRate, sequenceMs, seekWindowMs, overlapMs;
00378 
00379     // read current tdstretch routine parameters
00380     pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
00381 
00382     switch (settingId) 
00383     {
00384         case SETTING_USE_AA_FILTER :
00385             // enables / disabless anti-alias filter
00386             pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE);
00387             return TRUE;
00388 
00389         case SETTING_AA_FILTER_LENGTH :
00390             // sets anti-alias filter length
00391             pRateTransposer->getAAFilter()->setLength(value);
00392             return TRUE;
00393 
00394         case SETTING_USE_QUICKSEEK :
00395             // enables / disables tempo routine quick seeking algorithm
00396             pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE);
00397             return TRUE;
00398 
00399         case SETTING_SEQUENCE_MS:
00400             // change time-stretch sequence duration parameter
00401             pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
00402             return TRUE;
00403 
00404         case SETTING_SEEKWINDOW_MS:
00405             // change time-stretch seek window length parameter
00406             pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
00407             return TRUE;
00408 
00409         case SETTING_OVERLAP_MS:
00410             // change time-stretch overlap length parameter
00411             pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
00412             return TRUE;
00413 
00414         default :
00415             return FALSE;
00416     }
00417 }
00418 
00419 
00420 // Reads a setting controlling the processing system behaviour. See the
00421 // 'SETTING_...' defines for available setting ID's.
00422 //
00423 // Returns the setting value.
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 // Clears all the samples in the object's output and internal processing
00458 // buffers.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends