SoundTouch.cpp | SoundTouch.cpp | |||
---|---|---|---|---|
skipping to change at line 44 | skipping to change at line 44 | |||
/// tempo and pitch in the same ratio) of the sound. The third available control | /// tempo and pitch in the same ratio) of the sound. The third available control | |||
/// 'pitch' (change pitch but maintain tempo) is produced by a combinatio n of | /// 'pitch' (change pitch but maintain tempo) is produced by a combinatio n of | |||
/// combining the two other controls. | /// combining the two other controls. | |||
/// | /// | |||
/// Author : Copyright (c) Olli Parviainen | /// Author : Copyright (c) Olli Parviainen | |||
/// Author e-mail : oparviai 'at' iki.fi | /// Author e-mail : oparviai 'at' iki.fi | |||
/// SoundTouch WWW: http://www.surina.net/soundtouch | /// SoundTouch WWW: http://www.surina.net/soundtouch | |||
/// | /// | |||
/////////////////////////////////////////////////////////////////////////// ///// | /////////////////////////////////////////////////////////////////////////// ///// | |||
// | // | |||
// Last changed : $Date: 2014-10-08 15:26:57 +0000 (Wed, 08 Oct 2014) $ | // Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ | |||
// File revision : $Revision: 4 $ | // File revision : $Revision: 4 $ | |||
// | // | |||
// $Id: SoundTouch.cpp 201 2014-10-08 15:26:57Z oparviai $ | // $Id: SoundTouch.cpp 225 2015-07-26 14:45:48Z oparviai $ | |||
// | // | |||
/////////////////////////////////////////////////////////////////////////// ///// | /////////////////////////////////////////////////////////////////////////// ///// | |||
// | // | |||
// License : | // License : | |||
// | // | |||
// SoundTouch audio processing library | // SoundTouch audio processing library | |||
// Copyright (c) Olli Parviainen | // Copyright (c) Olli Parviainen | |||
// | // | |||
// This library is free software; you can redistribute it and/or | // This library is free software; you can redistribute it and/or | |||
// modify it under the terms of the GNU Lesser General Public | // modify it under the terms of the GNU Lesser General Public | |||
skipping to change at line 111 | skipping to change at line 111 | |||
setOutPipe(pTDStretch); | setOutPipe(pTDStretch); | |||
rate = tempo = 0; | rate = tempo = 0; | |||
virtualPitch = | virtualPitch = | |||
virtualRate = | virtualRate = | |||
virtualTempo = 1.0; | virtualTempo = 1.0; | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
samplesExpectedOut = 0; | ||||
samplesOutput = 0; | ||||
channels = 0; | channels = 0; | |||
bSrateSet = false; | bSrateSet = false; | |||
} | } | |||
SoundTouch::~SoundTouch() | SoundTouch::~SoundTouch() | |||
{ | { | |||
delete pRateTransposer; | delete pRateTransposer; | |||
delete pTDStretch; | delete pTDStretch; | |||
} | } | |||
skipping to change at line 150 | skipping to change at line 153 | |||
//ST_THROW_RT_ERROR("Illegal number of channels"); | //ST_THROW_RT_ERROR("Illegal number of channels"); | |||
return; | return; | |||
}*/ | }*/ | |||
channels = numChannels; | channels = numChannels; | |||
pRateTransposer->setChannels((int)numChannels); | pRateTransposer->setChannels((int)numChannels); | |||
pTDStretch->setChannels((int)numChannels); | pTDStretch->setChannels((int)numChannels); | |||
} | } | |||
// Sets new rate control value. Normal rate = 1.0, smaller values | // Sets new rate control value. Normal rate = 1.0, smaller values | |||
// represent slower rate, larger faster rates. | // represent slower rate, larger faster rates. | |||
void SoundTouch::setRate(float newRate) | void SoundTouch::setRate(double newRate) | |||
{ | { | |||
virtualRate = newRate; | virtualRate = newRate; | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
} | } | |||
// Sets new rate control value as a difference in percents compared | // Sets new rate control value as a difference in percents compared | |||
// to the original rate (-50 .. +100 %) | // to the original rate (-50 .. +100 %) | |||
void SoundTouch::setRateChange(float newRate) | void SoundTouch::setRateChange(double newRate) | |||
{ | { | |||
virtualRate = 1.0f + 0.01f * newRate; | virtualRate = 1.0 + 0.01 * newRate; | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
} | } | |||
// Sets new tempo control value. Normal tempo = 1.0, smaller values | // Sets new tempo control value. Normal tempo = 1.0, smaller values | |||
// represent slower tempo, larger faster tempo. | // represent slower tempo, larger faster tempo. | |||
void SoundTouch::setTempo(float newTempo) | void SoundTouch::setTempo(double newTempo) | |||
{ | { | |||
virtualTempo = newTempo; | virtualTempo = newTempo; | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
} | } | |||
// Sets new tempo control value as a difference in percents compared | // Sets new tempo control value as a difference in percents compared | |||
// to the original tempo (-50 .. +100 %) | // to the original tempo (-50 .. +100 %) | |||
void SoundTouch::setTempoChange(float newTempo) | void SoundTouch::setTempoChange(double newTempo) | |||
{ | { | |||
virtualTempo = 1.0f + 0.01f * newTempo; | virtualTempo = 1.0 + 0.01 * newTempo; | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
} | } | |||
// Sets new pitch control value. Original pitch = 1.0, smaller values | // Sets new pitch control value. Original pitch = 1.0, smaller values | |||
// represent lower pitches, larger values higher pitch. | // represent lower pitches, larger values higher pitch. | |||
void SoundTouch::setPitch(float newPitch) | void SoundTouch::setPitch(double newPitch) | |||
{ | { | |||
virtualPitch = newPitch; | virtualPitch = newPitch; | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
} | } | |||
// Sets pitch change in octaves compared to the original pitch | // Sets pitch change in octaves compared to the original pitch | |||
// (-1.00 .. +1.00) | // (-1.00 .. +1.00) | |||
void SoundTouch::setPitchOctaves(float newPitch) | void SoundTouch::setPitchOctaves(double newPitch) | |||
{ | { | |||
virtualPitch = (float)exp(0.69314718056f * newPitch); | virtualPitch = exp(0.69314718056 * newPitch); | |||
calcEffectiveRateAndTempo(); | calcEffectiveRateAndTempo(); | |||
} | } | |||
// Sets pitch change in semi-tones compared to the original pitch | // Sets pitch change in semi-tones compared to the original pitch | |||
// (-12 .. +12) | // (-12 .. +12) | |||
void SoundTouch::setPitchSemiTones(int newPitch) | void SoundTouch::setPitchSemiTones(int newPitch) | |||
{ | { | |||
setPitchOctaves((float)newPitch / 12.0f); | setPitchOctaves((double)newPitch / 12.0); | |||
} | } | |||
void SoundTouch::setPitchSemiTones(float newPitch) | void SoundTouch::setPitchSemiTones(double newPitch) | |||
{ | { | |||
setPitchOctaves(newPitch / 12.0f); | setPitchOctaves(newPitch / 12.0); | |||
} | } | |||
// Calculates 'effective' rate and tempo values from the | // Calculates 'effective' rate and tempo values from the | |||
// nominal control values. | // nominal control values. | |||
void SoundTouch::calcEffectiveRateAndTempo() | void SoundTouch::calcEffectiveRateAndTempo() | |||
{ | { | |||
float oldTempo = tempo; | double oldTempo = tempo; | |||
float oldRate = rate; | double oldRate = rate; | |||
tempo = virtualTempo / virtualPitch; | tempo = virtualTempo / virtualPitch; | |||
rate = virtualPitch * virtualRate; | rate = virtualPitch * virtualRate; | |||
if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); | if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); | |||
if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); | if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); | |||
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER | #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER | |||
if (rate <= 1.0f) | if (rate <= 1.0f) | |||
{ | { | |||
if (output != pTDStretch) | if (output != pTDStretch) | |||
{ | { | |||
FIFOSamplePipe *tempoOut; | FIFOSamplePipe *tempoOut; | |||
assert(output == pRateTransposer); | assert(output == pRateTransposer); | |||
// move samples in the current output buffer to the output of p TDStretch | // move samples in the current output buffer to the output of p TDStretch | |||
skipping to change at line 293 | skipping to change at line 296 | |||
assert(output == pTDStretch); | assert(output == pTDStretch); | |||
if (pRateTransposer->isEmpty() == 0) | if (pRateTransposer->isEmpty() == 0) | |||
{ | { | |||
// yet flush the last samples in the pitch transposer buffer | // yet flush the last samples in the pitch transposer buffer | |||
// (may happen if 'rate' changes from a non-zero value to zero) | // (may happen if 'rate' changes from a non-zero value to zero) | |||
pTDStretch->moveSamples(*pRateTransposer); | pTDStretch->moveSamples(*pRateTransposer); | |||
} | } | |||
pTDStretch->putSamples(samples, nSamples); | pTDStretch->putSamples(samples, nSamples); | |||
} | } | |||
*/ | */ | |||
// accumulate how many samples are expected out from processing, giv | ||||
en the current | ||||
// processing setting | ||||
samplesExpectedOut += (double)nSamples / ((double)rate * (double)tem | ||||
po); | ||||
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER | #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER | |||
else if (rate <= 1.0f) | if (rate <= 1.0f) | |||
{ | { | |||
// transpose the rate down, output the transposed sound to tempo ch anger buffer | // transpose the rate down, output the transposed sound to tempo ch anger buffer | |||
assert(output == pTDStretch); | assert(output == pTDStretch); | |||
pRateTransposer->putSamples(samples, nSamples); | pRateTransposer->putSamples(samples, nSamples); | |||
pTDStretch->moveSamples(*pRateTransposer); | pTDStretch->moveSamples(*pRateTransposer); | |||
} | } | |||
else | else | |||
#endif | #endif | |||
{ | { | |||
// evaluate the tempo changer, then transpose the rate up, | // evaluate the tempo changer, then transpose the rate up, | |||
skipping to change at line 321 | skipping to change at line 329 | |||
// Flushes the last samples from the processing pipeline to the output. | // Flushes the last samples from the processing pipeline to the output. | |||
// Clears also the internal processing buffers. | // Clears also the internal processing buffers. | |||
// | // | |||
// Note: This function is meant for extracting the last samples of a sound | // Note: This function is meant for extracting the last samples of a sound | |||
// stream. This function may introduce additional blank samples in the end | // stream. This function may introduce additional blank samples in the end | |||
// of the sound stream, and thus it's not recommended to call this function | // of the sound stream, and thus it's not recommended to call this function | |||
// in the middle of a sound stream. | // in the middle of a sound stream. | |||
void SoundTouch::flush() | void SoundTouch::flush() | |||
{ | { | |||
int i; | int i; | |||
int nUnprocessed; | int numStillExpected; | |||
int nOut; | SAMPLETYPE *buff = new SAMPLETYPE[128 * channels]; | |||
SAMPLETYPE *buff = new SAMPLETYPE[64 * channels]; | ||||
// check how many samples still await processing, and scale | ||||
// that by tempo & rate to get expected output sample count | ||||
nUnprocessed = numUnprocessedSamples(); | ||||
nUnprocessed = (int)((double)nUnprocessed / (tempo * rate) + 0.5); | ||||
nOut = numSamples(); // ready samples currently in buffer ... | // how many samples are still expected to output | |||
nOut += nUnprocessed; // ... and how many we expect there to be i | numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesO | |||
n the end | utput); | |||
memset(buff, 0, 64 * channels * sizeof(SAMPLETYPE)); | memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE)); | |||
// "Push" the last active samples out from the processing pipeline by | // "Push" the last active samples out from the processing pipeline by | |||
// feeding blank samples into the processing pipeline until new, | // feeding blank samples into the processing pipeline until new, | |||
// processed samples appear in the output (not however, more than | // processed samples appear in the output (not however, more than | |||
// 8ksamples in any case) | // 24ksamples in any case) | |||
for (i = 0; i < 128; i ++) | for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i + | |||
{ | +) | |||
putSamples(buff, 64); | { | |||
if ((int)numSamples() >= nOut) | putSamples(buff, 128); | |||
{ | } | |||
// Enough new samples have appeared into the output! | ||||
// As samples come from processing with bigger chunks, now trun | ||||
cate it | ||||
// back to maximum "nOut" samples to improve duration accuracy | ||||
adjustAmountOfSamples(nOut); | ||||
// finish | adjustAmountOfSamples(numStillExpected); | |||
break; | ||||
} | ||||
} | ||||
delete[] buff; | delete[] buff; | |||
// Clear working buffers | // Clear input buffers | |||
pRateTransposer->clear(); | // pRateTransposer->clearInput(); | |||
pTDStretch->clearInput(); | pTDStretch->clearInput(); | |||
// yet leave the 'tempoChanger' output intouched as that's where the | // yet leave the output intouched as that's where the | |||
// flushed samples are! | // flushed samples are! | |||
} | } | |||
// Changes a setting controlling the processing system behaviour. See the | // Changes a setting controlling the processing system behaviour. See the | |||
// 'SETTING_...' defines for available setting ID's. | // 'SETTING_...' defines for available setting ID's. | |||
bool SoundTouch::setSetting(int settingId, int value) | bool SoundTouch::setSetting(int settingId, int value) | |||
{ | { | |||
int sampleRate, sequenceMs, seekWindowMs, overlapMs; | int sampleRate, sequenceMs, seekWindowMs, overlapMs; | |||
// read current tdstretch routine parameters | // read current tdstretch routine parameters | |||
skipping to change at line 454 | skipping to change at line 448 | |||
default : | default : | |||
return 0; | return 0; | |||
} | } | |||
} | } | |||
// Clears all the samples in the object's output and internal processing | // Clears all the samples in the object's output and internal processing | |||
// buffers. | // buffers. | |||
void SoundTouch::clear() | void SoundTouch::clear() | |||
{ | { | |||
samplesExpectedOut = 0; | ||||
pRateTransposer->clear(); | pRateTransposer->clear(); | |||
pTDStretch->clear(); | pTDStretch->clear(); | |||
} | } | |||
/// Returns number of samples currently unprocessed. | /// Returns number of samples currently unprocessed. | |||
uint SoundTouch::numUnprocessedSamples() const | uint SoundTouch::numUnprocessedSamples() const | |||
{ | { | |||
FIFOSamplePipe * psp; | FIFOSamplePipe * psp; | |||
if (pTDStretch) | if (pTDStretch) | |||
{ | { | |||
psp = pTDStretch->getInput(); | psp = pTDStretch->getInput(); | |||
if (psp) | if (psp) | |||
{ | { | |||
return psp->numSamples(); | return psp->numSamples(); | |||
} | } | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
/// Output samples from beginning of the sample buffer. Copies requested sa | ||||
mples to | ||||
/// output buffer and removes them from the sample buffer. If there are les | ||||
s than | ||||
/// 'numsample' samples in the buffer, returns all that available. | ||||
/// | ||||
/// \return Number of samples returned. | ||||
uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples) | ||||
{ | ||||
uint ret = FIFOProcessor::receiveSamples(output, maxSamples); | ||||
samplesOutput += (long)ret; | ||||
return ret; | ||||
} | ||||
/// Adjusts book-keeping so that given number of samples are removed from b | ||||
eginning of the | ||||
/// sample buffer without copying them anywhere. | ||||
/// | ||||
/// Used to reduce the number of samples in the buffer when accessing the s | ||||
ample buffer directly | ||||
/// with 'ptrBegin' function. | ||||
uint SoundTouch::receiveSamples(uint maxSamples) | ||||
{ | ||||
uint ret = FIFOProcessor::receiveSamples(maxSamples); | ||||
samplesOutput += (long)ret; | ||||
return ret; | ||||
} | ||||
End of changes. 29 change blocks. | ||||
50 lines changed or deleted | 47 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |