1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libsoundtouch/src/SoundTouch.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,507 @@ 1.4 +////////////////////////////////////////////////////////////////////////////// 1.5 +/// 1.6 +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. 1.7 +/// 1.8 +/// Notes: 1.9 +/// - Initialize the SoundTouch object instance by setting up the sound stream 1.10 +/// parameters with functions 'setSampleRate' and 'setChannels', then set 1.11 +/// desired tempo/pitch/rate settings with the corresponding functions. 1.12 +/// 1.13 +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The 1.14 +/// samples that are to be processed are fed into one of the pipe by calling 1.15 +/// function 'putSamples', while the ready processed samples can be read 1.16 +/// from the other end of the pipeline with function 'receiveSamples'. 1.17 +/// 1.18 +/// - The SoundTouch processing classes require certain sized 'batches' of 1.19 +/// samples in order to process the sound. For this reason the classes buffer 1.20 +/// incoming samples until there are enough of samples available for 1.21 +/// processing, then they carry out the processing step and consequently 1.22 +/// make the processed samples available for outputting. 1.23 +/// 1.24 +/// - For the above reason, the processing routines introduce a certain 1.25 +/// 'latency' between the input and output, so that the samples input to 1.26 +/// SoundTouch may not be immediately available in the output, and neither 1.27 +/// the amount of outputtable samples may not immediately be in direct 1.28 +/// relationship with the amount of previously input samples. 1.29 +/// 1.30 +/// - The tempo/pitch/rate control parameters can be altered during processing. 1.31 +/// Please notice though that they aren't currently protected by semaphores, 1.32 +/// so in multi-thread application external semaphore protection may be 1.33 +/// required. 1.34 +/// 1.35 +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying 1.36 +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both 1.37 +/// tempo and pitch in the same ratio) of the sound. The third available control 1.38 +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of 1.39 +/// combining the two other controls. 1.40 +/// 1.41 +/// Author : Copyright (c) Olli Parviainen 1.42 +/// Author e-mail : oparviai 'at' iki.fi 1.43 +/// SoundTouch WWW: http://www.surina.net/soundtouch 1.44 +/// 1.45 +//////////////////////////////////////////////////////////////////////////////// 1.46 +// 1.47 +// Last changed : $Date: 2014-04-06 10:57:21 -0500 (Sun, 06 Apr 2014) $ 1.48 +// File revision : $Revision: 4 $ 1.49 +// 1.50 +// $Id: SoundTouch.cpp 195 2014-04-06 15:57:21Z oparviai $ 1.51 +// 1.52 +//////////////////////////////////////////////////////////////////////////////// 1.53 +// 1.54 +// License : 1.55 +// 1.56 +// SoundTouch audio processing library 1.57 +// Copyright (c) Olli Parviainen 1.58 +// 1.59 +// This library is free software; you can redistribute it and/or 1.60 +// modify it under the terms of the GNU Lesser General Public 1.61 +// License as published by the Free Software Foundation; either 1.62 +// version 2.1 of the License, or (at your option) any later version. 1.63 +// 1.64 +// This library is distributed in the hope that it will be useful, 1.65 +// but WITHOUT ANY WARRANTY; without even the implied warranty of 1.66 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.67 +// Lesser General Public License for more details. 1.68 +// 1.69 +// You should have received a copy of the GNU Lesser General Public 1.70 +// License along with this library; if not, write to the Free Software 1.71 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.72 +// 1.73 +//////////////////////////////////////////////////////////////////////////////// 1.74 + 1.75 +#include <assert.h> 1.76 +#include <stdlib.h> 1.77 +#include <memory.h> 1.78 +#include <math.h> 1.79 +#include <stdio.h> 1.80 + 1.81 +#include "SoundTouch.h" 1.82 +#include "TDStretch.h" 1.83 +#include "RateTransposer.h" 1.84 +#include "cpu_detect.h" 1.85 + 1.86 +#ifdef _MSC_VER 1.87 +#include <malloc.h> 1.88 +#define alloca _alloca 1.89 +#endif 1.90 + 1.91 +using namespace soundtouch; 1.92 + 1.93 +/// test if two floating point numbers are equal 1.94 +#define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10) 1.95 + 1.96 + 1.97 +/// Print library version string for autoconf 1.98 +extern "C" void soundtouch_ac_test() 1.99 +{ 1.100 + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); 1.101 +} 1.102 + 1.103 + 1.104 +SoundTouch::SoundTouch() 1.105 +{ 1.106 + // Initialize rate transposer and tempo changer instances 1.107 + 1.108 + pRateTransposer = new RateTransposer(); 1.109 + pTDStretch = TDStretch::newInstance(); 1.110 + 1.111 + setOutPipe(pTDStretch); 1.112 + 1.113 + rate = tempo = 0; 1.114 + 1.115 + virtualPitch = 1.116 + virtualRate = 1.117 + virtualTempo = 1.0; 1.118 + 1.119 + calcEffectiveRateAndTempo(); 1.120 + 1.121 + channels = 0; 1.122 + bSrateSet = false; 1.123 +} 1.124 + 1.125 + 1.126 + 1.127 +SoundTouch::~SoundTouch() 1.128 +{ 1.129 + delete pRateTransposer; 1.130 + delete pTDStretch; 1.131 +} 1.132 + 1.133 + 1.134 + 1.135 +/// Get SoundTouch library version string 1.136 +const char *SoundTouch::getVersionString() 1.137 +{ 1.138 + static const char *_version = SOUNDTOUCH_VERSION; 1.139 + 1.140 + return _version; 1.141 +} 1.142 + 1.143 + 1.144 +/// Get SoundTouch library version Id 1.145 +uint SoundTouch::getVersionId() 1.146 +{ 1.147 + return SOUNDTOUCH_VERSION_ID; 1.148 +} 1.149 + 1.150 + 1.151 +// Sets the number of channels, 1 = mono, 2 = stereo 1.152 +void SoundTouch::setChannels(uint numChannels) 1.153 +{ 1.154 + /*if (numChannels != 1 && numChannels != 2) 1.155 + { 1.156 + //ST_THROW_RT_ERROR("Illegal number of channels"); 1.157 + return; 1.158 + }*/ 1.159 + channels = numChannels; 1.160 + pRateTransposer->setChannels((int)numChannels); 1.161 + pTDStretch->setChannels((int)numChannels); 1.162 +} 1.163 + 1.164 + 1.165 + 1.166 +// Sets new rate control value. Normal rate = 1.0, smaller values 1.167 +// represent slower rate, larger faster rates. 1.168 +void SoundTouch::setRate(float newRate) 1.169 +{ 1.170 + virtualRate = newRate; 1.171 + calcEffectiveRateAndTempo(); 1.172 +} 1.173 + 1.174 + 1.175 + 1.176 +// Sets new rate control value as a difference in percents compared 1.177 +// to the original rate (-50 .. +100 %) 1.178 +void SoundTouch::setRateChange(float newRate) 1.179 +{ 1.180 + virtualRate = 1.0f + 0.01f * newRate; 1.181 + calcEffectiveRateAndTempo(); 1.182 +} 1.183 + 1.184 + 1.185 + 1.186 +// Sets new tempo control value. Normal tempo = 1.0, smaller values 1.187 +// represent slower tempo, larger faster tempo. 1.188 +void SoundTouch::setTempo(float newTempo) 1.189 +{ 1.190 + virtualTempo = newTempo; 1.191 + calcEffectiveRateAndTempo(); 1.192 +} 1.193 + 1.194 + 1.195 + 1.196 +// Sets new tempo control value as a difference in percents compared 1.197 +// to the original tempo (-50 .. +100 %) 1.198 +void SoundTouch::setTempoChange(float newTempo) 1.199 +{ 1.200 + virtualTempo = 1.0f + 0.01f * newTempo; 1.201 + calcEffectiveRateAndTempo(); 1.202 +} 1.203 + 1.204 + 1.205 + 1.206 +// Sets new pitch control value. Original pitch = 1.0, smaller values 1.207 +// represent lower pitches, larger values higher pitch. 1.208 +void SoundTouch::setPitch(float newPitch) 1.209 +{ 1.210 + virtualPitch = newPitch; 1.211 + calcEffectiveRateAndTempo(); 1.212 +} 1.213 + 1.214 + 1.215 + 1.216 +// Sets pitch change in octaves compared to the original pitch 1.217 +// (-1.00 .. +1.00) 1.218 +void SoundTouch::setPitchOctaves(float newPitch) 1.219 +{ 1.220 + virtualPitch = (float)exp(0.69314718056f * newPitch); 1.221 + calcEffectiveRateAndTempo(); 1.222 +} 1.223 + 1.224 + 1.225 + 1.226 +// Sets pitch change in semi-tones compared to the original pitch 1.227 +// (-12 .. +12) 1.228 +void SoundTouch::setPitchSemiTones(int newPitch) 1.229 +{ 1.230 + setPitchOctaves((float)newPitch / 12.0f); 1.231 +} 1.232 + 1.233 + 1.234 + 1.235 +void SoundTouch::setPitchSemiTones(float newPitch) 1.236 +{ 1.237 + setPitchOctaves(newPitch / 12.0f); 1.238 +} 1.239 + 1.240 + 1.241 +// Calculates 'effective' rate and tempo values from the 1.242 +// nominal control values. 1.243 +void SoundTouch::calcEffectiveRateAndTempo() 1.244 +{ 1.245 + float oldTempo = tempo; 1.246 + float oldRate = rate; 1.247 + 1.248 + tempo = virtualTempo / virtualPitch; 1.249 + rate = virtualPitch * virtualRate; 1.250 + 1.251 + if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); 1.252 + if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); 1.253 + 1.254 +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1.255 + if (rate <= 1.0f) 1.256 + { 1.257 + if (output != pTDStretch) 1.258 + { 1.259 + FIFOSamplePipe *tempoOut; 1.260 + 1.261 + assert(output == pRateTransposer); 1.262 + // move samples in the current output buffer to the output of pTDStretch 1.263 + tempoOut = pTDStretch->getOutput(); 1.264 + tempoOut->moveSamples(*output); 1.265 + // move samples in pitch transposer's store buffer to tempo changer's input 1.266 + // deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore()); 1.267 + 1.268 + output = pTDStretch; 1.269 + } 1.270 + } 1.271 + else 1.272 +#endif 1.273 + { 1.274 + if (output != pRateTransposer) 1.275 + { 1.276 + FIFOSamplePipe *transOut; 1.277 + 1.278 + assert(output == pTDStretch); 1.279 + // move samples in the current output buffer to the output of pRateTransposer 1.280 + transOut = pRateTransposer->getOutput(); 1.281 + transOut->moveSamples(*output); 1.282 + // move samples in tempo changer's input to pitch transposer's input 1.283 + pRateTransposer->moveSamples(*pTDStretch->getInput()); 1.284 + 1.285 + output = pRateTransposer; 1.286 + } 1.287 + } 1.288 +} 1.289 + 1.290 + 1.291 +// Sets sample rate. 1.292 +void SoundTouch::setSampleRate(uint srate) 1.293 +{ 1.294 + bSrateSet = true; 1.295 + // set sample rate, leave other tempo changer parameters as they are. 1.296 + pTDStretch->setParameters((int)srate); 1.297 +} 1.298 + 1.299 + 1.300 +// Adds 'numSamples' pcs of samples from the 'samples' memory position into 1.301 +// the input of the object. 1.302 +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) 1.303 +{ 1.304 + if (bSrateSet == false) 1.305 + { 1.306 + ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined"); 1.307 + } 1.308 + else if (channels == 0) 1.309 + { 1.310 + ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined"); 1.311 + } 1.312 + 1.313 + // Transpose the rate of the new samples if necessary 1.314 + /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... 1.315 + if (rate == 1.0f) 1.316 + { 1.317 + // The rate value is same as the original, simply evaluate the tempo changer. 1.318 + assert(output == pTDStretch); 1.319 + if (pRateTransposer->isEmpty() == 0) 1.320 + { 1.321 + // yet flush the last samples in the pitch transposer buffer 1.322 + // (may happen if 'rate' changes from a non-zero value to zero) 1.323 + pTDStretch->moveSamples(*pRateTransposer); 1.324 + } 1.325 + pTDStretch->putSamples(samples, nSamples); 1.326 + } 1.327 + */ 1.328 +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1.329 + else if (rate <= 1.0f) 1.330 + { 1.331 + // transpose the rate down, output the transposed sound to tempo changer buffer 1.332 + assert(output == pTDStretch); 1.333 + pRateTransposer->putSamples(samples, nSamples); 1.334 + pTDStretch->moveSamples(*pRateTransposer); 1.335 + } 1.336 + else 1.337 +#endif 1.338 + { 1.339 + // evaluate the tempo changer, then transpose the rate up, 1.340 + assert(output == pRateTransposer); 1.341 + pTDStretch->putSamples(samples, nSamples); 1.342 + pRateTransposer->moveSamples(*pTDStretch); 1.343 + } 1.344 +} 1.345 + 1.346 + 1.347 +// Flushes the last samples from the processing pipeline to the output. 1.348 +// Clears also the internal processing buffers. 1.349 +// 1.350 +// Note: This function is meant for extracting the last samples of a sound 1.351 +// stream. This function may introduce additional blank samples in the end 1.352 +// of the sound stream, and thus it's not recommended to call this function 1.353 +// in the middle of a sound stream. 1.354 +void SoundTouch::flush() 1.355 +{ 1.356 + int i; 1.357 + int nUnprocessed; 1.358 + int nOut; 1.359 + SAMPLETYPE *buff=(SAMPLETYPE*)alloca(64*channels*sizeof(SAMPLETYPE)); 1.360 + 1.361 + // check how many samples still await processing, and scale 1.362 + // that by tempo & rate to get expected output sample count 1.363 + nUnprocessed = numUnprocessedSamples(); 1.364 + nUnprocessed = (int)((double)nUnprocessed / (tempo * rate) + 0.5); 1.365 + 1.366 + nOut = numSamples(); // ready samples currently in buffer ... 1.367 + nOut += nUnprocessed; // ... and how many we expect there to be in the end 1.368 + 1.369 + memset(buff, 0, 64 * channels * sizeof(SAMPLETYPE)); 1.370 + // "Push" the last active samples out from the processing pipeline by 1.371 + // feeding blank samples into the processing pipeline until new, 1.372 + // processed samples appear in the output (not however, more than 1.373 + // 8ksamples in any case) 1.374 + for (i = 0; i < 128; i ++) 1.375 + { 1.376 + putSamples(buff, 64); 1.377 + if ((int)numSamples() >= nOut) 1.378 + { 1.379 + // Enough new samples have appeared into the output! 1.380 + // As samples come from processing with bigger chunks, now truncate it 1.381 + // back to maximum "nOut" samples to improve duration accuracy 1.382 + adjustAmountOfSamples(nOut); 1.383 + 1.384 + // finish 1.385 + break; 1.386 + } 1.387 + } 1.388 + 1.389 + // Clear working buffers 1.390 + pRateTransposer->clear(); 1.391 + pTDStretch->clearInput(); 1.392 + // yet leave the 'tempoChanger' output intouched as that's where the 1.393 + // flushed samples are! 1.394 +} 1.395 + 1.396 + 1.397 +// Changes a setting controlling the processing system behaviour. See the 1.398 +// 'SETTING_...' defines for available setting ID's. 1.399 +bool SoundTouch::setSetting(int settingId, int value) 1.400 +{ 1.401 + int sampleRate, sequenceMs, seekWindowMs, overlapMs; 1.402 + 1.403 + // read current tdstretch routine parameters 1.404 + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); 1.405 + 1.406 + switch (settingId) 1.407 + { 1.408 + case SETTING_USE_AA_FILTER : 1.409 + // enables / disabless anti-alias filter 1.410 + pRateTransposer->enableAAFilter((value != 0) ? true : false); 1.411 + return true; 1.412 + 1.413 + case SETTING_AA_FILTER_LENGTH : 1.414 + // sets anti-alias filter length 1.415 + pRateTransposer->getAAFilter()->setLength(value); 1.416 + return true; 1.417 + 1.418 + case SETTING_USE_QUICKSEEK : 1.419 + // enables / disables tempo routine quick seeking algorithm 1.420 + pTDStretch->enableQuickSeek((value != 0) ? true : false); 1.421 + return true; 1.422 + 1.423 + case SETTING_SEQUENCE_MS: 1.424 + // change time-stretch sequence duration parameter 1.425 + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); 1.426 + return true; 1.427 + 1.428 + case SETTING_SEEKWINDOW_MS: 1.429 + // change time-stretch seek window length parameter 1.430 + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); 1.431 + return true; 1.432 + 1.433 + case SETTING_OVERLAP_MS: 1.434 + // change time-stretch overlap length parameter 1.435 + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); 1.436 + return true; 1.437 + 1.438 + default : 1.439 + return false; 1.440 + } 1.441 +} 1.442 + 1.443 + 1.444 +// Reads a setting controlling the processing system behaviour. See the 1.445 +// 'SETTING_...' defines for available setting ID's. 1.446 +// 1.447 +// Returns the setting value. 1.448 +int SoundTouch::getSetting(int settingId) const 1.449 +{ 1.450 + int temp; 1.451 + 1.452 + switch (settingId) 1.453 + { 1.454 + case SETTING_USE_AA_FILTER : 1.455 + return (uint)pRateTransposer->isAAFilterEnabled(); 1.456 + 1.457 + case SETTING_AA_FILTER_LENGTH : 1.458 + return pRateTransposer->getAAFilter()->getLength(); 1.459 + 1.460 + case SETTING_USE_QUICKSEEK : 1.461 + return (uint) pTDStretch->isQuickSeekEnabled(); 1.462 + 1.463 + case SETTING_SEQUENCE_MS: 1.464 + pTDStretch->getParameters(NULL, &temp, NULL, NULL); 1.465 + return temp; 1.466 + 1.467 + case SETTING_SEEKWINDOW_MS: 1.468 + pTDStretch->getParameters(NULL, NULL, &temp, NULL); 1.469 + return temp; 1.470 + 1.471 + case SETTING_OVERLAP_MS: 1.472 + pTDStretch->getParameters(NULL, NULL, NULL, &temp); 1.473 + return temp; 1.474 + 1.475 + case SETTING_NOMINAL_INPUT_SEQUENCE : 1.476 + return pTDStretch->getInputSampleReq(); 1.477 + 1.478 + case SETTING_NOMINAL_OUTPUT_SEQUENCE : 1.479 + return pTDStretch->getOutputBatchSize(); 1.480 + 1.481 + default : 1.482 + return 0; 1.483 + } 1.484 +} 1.485 + 1.486 + 1.487 +// Clears all the samples in the object's output and internal processing 1.488 +// buffers. 1.489 +void SoundTouch::clear() 1.490 +{ 1.491 + pRateTransposer->clear(); 1.492 + pTDStretch->clear(); 1.493 +} 1.494 + 1.495 + 1.496 + 1.497 +/// Returns number of samples currently unprocessed. 1.498 +uint SoundTouch::numUnprocessedSamples() const 1.499 +{ 1.500 + FIFOSamplePipe * psp; 1.501 + if (pTDStretch) 1.502 + { 1.503 + psp = pTDStretch->getInput(); 1.504 + if (psp) 1.505 + { 1.506 + return psp->numSamples(); 1.507 + } 1.508 + } 1.509 + return 0; 1.510 +}