diff --git a/source/SoundTouch/TDStretch.cpp b/source/SoundTouch/TDStretch.cpp index 6221bcb..1332974 100644 --- a/source/SoundTouch/TDStretch.cpp +++ b/source/SoundTouch/TDStretch.cpp @@ -14,7 +14,7 @@ //////////////////////////////////////////////////////////////////////////////// // // Last changed : $Date$ -// File revision : $Revision: 4 $ +// File revision : $Revision: 1.12 $ // // $Id$ // @@ -87,7 +87,7 @@ static const int _scanOffsets[4][24]={ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) { - bQuickseek = FALSE; + bQuickSeek = FALSE; channels = 2; bMidBufferDirty = FALSE; @@ -95,6 +95,9 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) pRefMidBufferUnaligned = NULL; overlapLength = 0; + bAutoSeqSetting = TRUE; + bAutoSeekSetting = TRUE; + tempo = 1.0f; setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); setTempo(1.0f); @@ -102,7 +105,6 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) - TDStretch::~TDStretch() { delete[] pMidBuffer; @@ -111,7 +113,6 @@ TDStretch::~TDStretch() - // Sets routine control parameters. These control are certain time constants // defining how the sound is stretched to the desired duration. // @@ -124,16 +125,29 @@ TDStretch::~TDStretch() void TDStretch::setParameters(int aSampleRate, int aSequenceMS, int aSeekWindowMS, int aOverlapMS) { - // accept only positive parameter values - if negative, use old values instead - if (aSampleRate >= 0) this->sampleRate = aSampleRate; - if (aSequenceMS >= 0) this->sequenceMs = aSequenceMS; - if (aSeekWindowMS >= 0) this->seekWindowMs = aSeekWindowMS; - if (aOverlapMS >= 0) this->overlapMs = aOverlapMS; + // accept only positive parameter values - if zero or negative, use old values instead + if (aSampleRate > 0) this->sampleRate = aSampleRate; + if (aOverlapMS > 0) this->overlapMs = aOverlapMS; - seekLength = (sampleRate * seekWindowMs) / 1000; - seekWindowLength = (sampleRate * sequenceMs) / 1000; + if (aSequenceMS > 0) + { + this->sequenceMs = aSequenceMS; + bAutoSeqSetting = FALSE; + } else { + // zero or below, use automatic setting + bAutoSeqSetting = TRUE; + } - maxOffset = seekLength; + if (aSeekWindowMS > 0) + { + this->seekWindowMs = aSeekWindowMS; + bAutoSeekSetting = FALSE; + } else { + // zero or below, use automatic setting + bAutoSeekSetting = TRUE; + } + + calcSeqParameters(); calculateOverlapLength(overlapMs); @@ -156,12 +170,12 @@ void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWind if (pSequenceMs) { - *pSequenceMs = sequenceMs; + *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN) : sequenceMs; } if (pSeekWindowMs) { - *pSeekWindowMs = seekWindowMs; + *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN) : seekWindowMs; } if (pOverlapMs) @@ -216,14 +230,14 @@ void TDStretch::clear() // to enable void TDStretch::enableQuickSeek(BOOL enable) { - bQuickseek = enable; + bQuickSeek = enable; } // Returns nonzero if the quick seeking algorithm is enabled. BOOL TDStretch::isQuickSeekEnabled() const { - return bQuickseek; + return bQuickSeek; } @@ -233,7 +247,7 @@ int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) if (channels == 2) { // stereo sound - if (bQuickseek) + if (bQuickSeek) { return seekBestOverlapPositionStereoQuick(refPos); } @@ -245,7 +259,7 @@ int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) else { // mono sound - if (bQuickseek) + if (bQuickSeek) { return seekBestOverlapPositionMonoQuick(refPos); } @@ -479,6 +493,51 @@ void TDStretch::clearCrossCorrState() } +/// Calculates processing sequence length according to tempo setting +void TDStretch::calcSeqParameters() +{ + // Adjust tempo param according to tempo, so that variating processing sequence length is used + // at varius tempo settings, between the given low...top limits + #define AUTOSEQ_TEMPO_LOW 0.5 // auto setting low tempo range (-50%) + #define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%) + + // sequence-ms setting values at above low & top tempo + #define AUTOSEQ_AT_MIN 125.0 + #define AUTOSEQ_AT_MAX 50.0 + #define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) + #define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW)) + + // seek-window-ms setting values at above low & top tempo + #define AUTOSEEK_AT_MIN 25.0 + #define AUTOSEEK_AT_MAX 15.0 + #define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) + #define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW)) + + #define CHECK_LIMITS(x, mi, ma) ((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x)) + + double seq, seek; + + if (bAutoSeqSetting) + { + seq = AUTOSEQ_C + AUTOSEQ_K * tempo; + seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN); + sequenceMs = (int)(seq + 0.5); + } + + if (bAutoSeekSetting) + { + seek = AUTOSEEK_C + AUTOSEEK_K * tempo; + seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN); + seekWindowMs = (int)(seek + 0.5); + } + + // Update seek window lengths + seekWindowLength = (sampleRate * sequenceMs) / 1000; + seekLength = (sampleRate * seekWindowMs) / 1000; +} + + + // Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower // tempo, larger faster tempo. void TDStretch::setTempo(float newTempo) @@ -487,6 +546,9 @@ void TDStretch::setTempo(float newTempo) tempo = newTempo; + // Calculate new sequence duration + calcSeqParameters(); + // Calculate ideal skip length (according to tempo value) nominalSkip = tempo * (seekWindowLength - overlapLength); skipFract = 0; @@ -494,7 +556,7 @@ void TDStretch::setTempo(float newTempo) // Calculate how many samples are needed in the 'inputBuffer' to // process another batch of samples - sampleReq = max(intskip + overlapLength, seekWindowLength) + maxOffset; + sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength; } diff --git a/source/SoundTouch/TDStretch.h b/source/SoundTouch/TDStretch.h index 129e568..ec464bf 100644 --- a/source/SoundTouch/TDStretch.h +++ b/source/SoundTouch/TDStretch.h @@ -61,7 +61,12 @@ namespace soundtouch /// and vice versa. /// /// Increasing this value reduces computational burden & vice versa. -#define DEFAULT_SEQUENCE_MS 130 +//#define DEFAULT_SEQUENCE_MS 130 +#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN + +/// Giving this value for the sequence length sets automatic parameter value +/// according to tempo setting (recommended) +#define USE_AUTO_SEQUENCE_LEN 0 /// Seeking window default length in milliseconds for algorithm that finds the best possible /// overlapping location. This determines from how wide window the algorithm may look for an @@ -75,7 +80,12 @@ namespace soundtouch /// around, try reducing this setting. /// /// Increasing this value increases computational burden & vice versa. -#define DEFAULT_SEEKWINDOW_MS 25 +//#define DEFAULT_SEEKWINDOW_MS 25 +#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN + +/// Giving this value for the seek window length sets automatic parameter value +/// according to tempo setting (recommended) +#define USE_AUTO_SEEKWINDOW_LEN 0 /// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, /// to form a continuous sound stream, this parameter defines over how long period the two @@ -110,13 +120,15 @@ protected: float skipFract; FIFOSampleBuffer outputBuffer; FIFOSampleBuffer inputBuffer; - BOOL bQuickseek; + BOOL bQuickSeek; BOOL bMidBufferDirty; int sampleRate; int sequenceMs; int seekWindowMs; int overlapMs; + BOOL bAutoSeqSetting; + BOOL bAutoSeekSetting; void acceptNewOverlapLength(int newOverlapLength); @@ -141,6 +153,8 @@ protected: void precalcCorrReferenceMono(); void precalcCorrReferenceStereo(); + void calcSeqParameters(); + /// Changes the tempo of the given sound samples. /// Returns amount of samples returned in the "output" buffer. /// The maximum amount of samples that can be returned at a time is set by