From 1883dc623333265046f29e05d6b7adf036874b98 Mon Sep 17 00:00:00 2001 From: Mystro256 Date: Apr 05 2020 22:55:13 +0000 Subject: Update soundtouch to 2.1.2 Potentially fixes some security issues. --- diff --git a/0001-soundtounch-update-to-2.1.2.patch b/0001-soundtounch-update-to-2.1.2.patch new file mode 100644 index 0000000..9103dd5 --- /dev/null +++ b/0001-soundtounch-update-to-2.1.2.patch @@ -0,0 +1,4822 @@ +From 24025eecc52314c0ccc1d70ca549a95e20165876 Mon Sep 17 00:00:00 2001 +From: Mystro256 +Date: Sun, 5 Apr 2020 10:56:07 -0400 +Subject: [PATCH 1/3] soundtounch: update to 2.1.2 + +Note that soundtouch_config.h is a custom file. +--- + Externals/soundtouch/AAFilter.cpp | 16 +- + Externals/soundtouch/AAFilter.h | 7 - + Externals/soundtouch/BPMDetect.cpp | 400 +++++++++---- + Externals/soundtouch/BPMDetect.h | 241 ++++---- + Externals/soundtouch/FIFOSampleBuffer.cpp | 15 +- + Externals/soundtouch/FIFOSampleBuffer.h | 9 +- + Externals/soundtouch/FIFOSamplePipe.h | 28 +- + Externals/soundtouch/FIRFilter.cpp | 20 +- + Externals/soundtouch/FIRFilter.h | 7 - + Externals/soundtouch/InterpolateCubic.cpp | 396 +++++++------ + Externals/soundtouch/InterpolateCubic.h | 130 +++-- + Externals/soundtouch/InterpolateLinear.cpp | 596 ++++++++++---------- + Externals/soundtouch/InterpolateLinear.h | 180 +++--- + Externals/soundtouch/InterpolateShannon.cpp | 366 ++++++------ + Externals/soundtouch/InterpolateShannon.h | 140 +++-- + Externals/soundtouch/PeakFinder.cpp | 19 +- + Externals/soundtouch/PeakFinder.h | 11 +- + Externals/soundtouch/RateTransposer.cpp | 35 +- + Externals/soundtouch/RateTransposer.h | 22 +- + Externals/soundtouch/STTypes.h | 32 +- + Externals/soundtouch/SoundTouch.cpp | 154 ++--- + Externals/soundtouch/SoundTouch.h | 91 ++- + Externals/soundtouch/SoundTouch.vcxproj | 424 +++++++++++--- + Externals/soundtouch/TDStretch.cpp | 131 +++-- + Externals/soundtouch/TDStretch.h | 16 +- + Externals/soundtouch/cpu_detect.h | 7 - + Externals/soundtouch/cpu_detect_x86.cpp | 8 - + Externals/soundtouch/mmx_optimized.cpp | 21 +- + Externals/soundtouch/soundtouch_config.h | 2 + + Externals/soundtouch/sse_optimized.cpp | 7 - + 30 files changed, 2000 insertions(+), 1531 deletions(-) + create mode 100644 Externals/soundtouch/soundtouch_config.h + +diff --git a/Externals/soundtouch/AAFilter.cpp b/Externals/soundtouch/AAFilter.cpp +index c69f356f68..76a3da65d4 100644 +--- a/Externals/soundtouch/AAFilter.cpp ++++ b/Externals/soundtouch/AAFilter.cpp +@@ -12,13 +12,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -49,7 +42,7 @@ + + using namespace soundtouch; + +-#define PI 3.141592655357989 ++#define PI 3.14159265358979323846 + #define TWOPI (2 * PI) + + // define this to save AA filter coefficients to a file +@@ -75,7 +68,6 @@ using namespace soundtouch; + #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) + #endif + +- + /***************************************************************************** + * + * Implementation of the class 'AAFilter' +@@ -90,14 +82,12 @@ AAFilter::AAFilter(uint len) + } + + +- + AAFilter::~AAFilter() + { + delete pFIR; + } + + +- + // Sets new anti-alias filter cut-off edge frequency, scaled to + // sampling frequency (nyquist frequency = 0.5). + // The filter will cut frequencies higher than the given frequency. +@@ -108,7 +98,6 @@ void AAFilter::setCutoffFreq(double newCutoffFreq) + } + + +- + // Sets number of FIR filter taps + void AAFilter::setLength(uint newLength) + { +@@ -117,7 +106,6 @@ void AAFilter::setLength(uint newLength) + } + + +- + // Calculates coefficients for a low-pass FIR filter using Hamming window + void AAFilter::calculateCoeffs() + { +@@ -177,12 +165,10 @@ void AAFilter::calculateCoeffs() + for (i = 0; i < length; i ++) + { + temp = work[i] * scaleCoeff; +-//#if SOUNDTOUCH_INTEGER_SAMPLES + // scale & round to nearest integer + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); +-//#endif + coeffs[i] = (SAMPLETYPE)temp; + } + +diff --git a/Externals/soundtouch/AAFilter.h b/Externals/soundtouch/AAFilter.h +index 33e96948ec..8e5697f796 100644 +--- a/Externals/soundtouch/AAFilter.h ++++ b/Externals/soundtouch/AAFilter.h +@@ -13,13 +13,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2014-01-07 21:41:23 +0200 (Tue, 07 Jan 2014) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +diff --git a/Externals/soundtouch/BPMDetect.cpp b/Externals/soundtouch/BPMDetect.cpp +index 39dae83761..5ad19269dd 100644 +--- a/Externals/soundtouch/BPMDetect.cpp ++++ b/Externals/soundtouch/BPMDetect.cpp +@@ -26,13 +26,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: BPMDetect.cpp 202 2015-02-21 21:24:29Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -54,45 +47,62 @@ + // + //////////////////////////////////////////////////////////////////////////////// + ++#define _USE_MATH_DEFINES ++ + #include + #include + #include + #include ++#include + #include "FIFOSampleBuffer.h" + #include "PeakFinder.h" + #include "BPMDetect.h" + + using namespace soundtouch; + +-#define INPUT_BLOCK_SAMPLES 2048 +-#define DECIMATED_BLOCK_SAMPLES 256 ++// algorithm input sample block size ++static const int INPUT_BLOCK_SIZE = 2048; ++ ++// decimated sample block size ++static const int DECIMATED_BLOCK_SIZE = 256; ++ ++/// Target sample rate after decimation ++static const int TARGET_SRATE = 1000; ++ ++/// XCorr update sequence size, update in about 200msec chunks ++static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5); + +-/// decay constant for calculating RMS volume sliding average approximation +-/// (time constant is about 10 sec) +-const float avgdecay = 0.99986f; ++/// Moving average N size ++static const int MOVING_AVERAGE_N = 15; + +-/// Normalization coefficient for calculating RMS sliding average approximation. +-const float avgnorm = (1 - avgdecay); ++/// XCorr decay time constant, decay to half in 30 seconds ++/// If it's desired to have the system adapt quicker to beat rate ++/// changes within a continuing music stream, then the ++/// 'xcorr_decay_time_constant' value can be reduced, yet that ++/// can increase possibility of glitches in bpm detection. ++static const double XCORR_DECAY_TIME_CONSTANT = 30.0; + ++/// Data overlap factor for beat detection algorithm ++static const int OVERLAP_FACTOR = 4; ++ ++static const double TWOPI = (2 * M_PI); + + //////////////////////////////////////////////////////////////////////////////// + + // Enable following define to create bpm analysis file: + +-// #define _CREATE_BPM_DEBUG_FILE ++//#define _CREATE_BPM_DEBUG_FILE + + #ifdef _CREATE_BPM_DEBUG_FILE + +- #define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt" +- +- static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff) ++ static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff) + { +- FILE *fptr = fopen(DEBUGFILE_NAME, "wt"); ++ FILE *fptr = fopen(name, "wt"); + int i; + + if (fptr) + { +- printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n"); ++ printf("\nWriting BPM debug data into file %s\n", name); + for (i = minpos; i < maxpos; i ++) + { + fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]); +@@ -100,42 +110,90 @@ const float avgnorm = (1 - avgdecay); + fclose(fptr); + } + } ++ ++ void _SaveDebugBeatPos(const char *name, const std::vector &beats) ++ { ++ printf("\nWriting beat detections data into file %s\n", name); ++ ++ FILE *fptr = fopen(name, "wt"); ++ if (fptr) ++ { ++ for (uint i = 0; i < beats.size(); i++) ++ { ++ BEAT b = beats[i]; ++ fprintf(fptr, "%lf\t%lf\n", b.pos, b.strength); ++ } ++ fclose(fptr); ++ } ++ } + #else +- #define _SaveDebugData(a,b,c,d) ++ #define _SaveDebugData(name, a,b,c,d) ++ #define _SaveDebugBeatPos(name, b) + #endif + ++// Hamming window ++void hamming(float *w, int N) ++{ ++ for (int i = 0; i < N; i++) ++ { ++ w[i] = (float)(0.54 - 0.46 * cos(TWOPI * i / (N - 1))); ++ } ++ ++} ++ + //////////////////////////////////////////////////////////////////////////////// ++// ++// IIR2_filter - 2nd order IIR filter ++ ++IIR2_filter::IIR2_filter(const double *lpf_coeffs) ++{ ++ memcpy(coeffs, lpf_coeffs, 5 * sizeof(double)); ++ memset(prev, 0, sizeof(prev)); ++} ++ + ++float IIR2_filter::update(float x) ++{ ++ prev[0] = x; ++ double y = x * coeffs[0]; ++ ++ for (int i = 4; i >= 1; i--) ++ { ++ y += coeffs[i] * prev[i]; ++ prev[i] = prev[i - 1]; ++ } ++ ++ prev[3] = y; ++ return (float)y; ++} ++ ++ ++// IIR low-pass filter coefficients, calculated with matlab/octave cheby2(2,40,0.05) ++const double _LPF_coeffs[5] = { 0.00996655391939, -0.01944529148401, 0.00996655391939, 1.96867605796247, -0.96916387431724 }; + +-BPMDetect::BPMDetect(int numChannels, int aSampleRate) ++//////////////////////////////////////////////////////////////////////////////// ++ ++BPMDetect::BPMDetect(int numChannels, int aSampleRate) : ++ beat_lpf(_LPF_coeffs) + { ++ beats.reserve(250); // initial reservation to prevent frequent reallocation ++ + this->sampleRate = aSampleRate; + this->channels = numChannels; + + decimateSum = 0; + decimateCount = 0; + +- envelopeAccu = 0; +- +- // Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's +- // safe initial RMS signal level value for song data. This value is then adapted +- // to the actual level during processing. +-#ifdef SOUNDTOUCH_INTEGER_SAMPLES +- // integer samples +- RMSVolumeAccu = (1500 * 1500) / avgnorm; +-#else +- // float samples, scaled to range [-1..+1[ +- RMSVolumeAccu = (0.045f * 0.045f) / avgnorm; +-#endif +- + // choose decimation factor so that result is approx. 1000 Hz +- decimateBy = sampleRate / 1000; +- assert(decimateBy > 0); +- assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); ++ decimateBy = sampleRate / TARGET_SRATE; ++ if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE)) ++ { ++ ST_THROW_RT_ERROR("Too small samplerate"); ++ } + + // Calculate window length & starting item according to desired min & max bpms + windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); +- windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM); ++ windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE); + + assert(windowLen > windowStart); + +@@ -143,23 +201,38 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate) + xcorr = new float[windowLen]; + memset(xcorr, 0, windowLen * sizeof(float)); + ++ pos = 0; ++ peakPos = 0; ++ peakVal = 0; ++ init_scaler = 1; ++ beatcorr_ringbuffpos = 0; ++ beatcorr_ringbuff = new float[windowLen]; ++ memset(beatcorr_ringbuff, 0, windowLen * sizeof(float)); ++ + // allocate processing buffer + buffer = new FIFOSampleBuffer(); + // we do processing in mono mode + buffer->setChannels(1); + buffer->clear(); +-} + ++ // calculate hamming windows ++ hamw = new float[XCORR_UPDATE_SEQUENCE]; ++ hamming(hamw, XCORR_UPDATE_SEQUENCE); ++ hamw2 = new float[XCORR_UPDATE_SEQUENCE / 2]; ++ hamming(hamw2, XCORR_UPDATE_SEQUENCE / 2); ++} + + + BPMDetect::~BPMDetect() + { + delete[] xcorr; ++ delete[] beatcorr_ringbuff; ++ delete[] hamw; ++ delete[] hamw2; + delete buffer; + } + + +- + /// convert to mono, low-pass filter & decimate to about 500 Hz. + /// return number of outputted samples. + /// +@@ -216,7 +289,6 @@ int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) + } + + +- + // Calculates autocorrelation function of the sample history buffer + void BPMDetect::updateXCorr(int process_samples) + { +@@ -224,72 +296,124 @@ void BPMDetect::updateXCorr(int process_samples) + SAMPLETYPE *pBuffer; + + assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); ++ assert(process_samples == XCORR_UPDATE_SEQUENCE); + + pBuffer = buffer->ptrBegin(); ++ ++ // calculate decay factor for xcorr filtering ++ float xcorr_decay = (float)pow(0.5, 1.0 / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE / process_samples)); ++ ++ // prescale pbuffer ++ float tmp[XCORR_UPDATE_SEQUENCE]; ++ for (int i = 0; i < process_samples; i++) ++ { ++ tmp[i] = hamw[i] * hamw[i] * pBuffer[i]; ++ } ++ + #pragma omp parallel for + for (offs = windowStart; offs < windowLen; offs ++) + { +- LONG_SAMPLETYPE sum; ++ float sum; + int i; + + sum = 0; + for (i = 0; i < process_samples; i ++) + { +- sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary ++ sum += tmp[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary + } +-// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients +- // if it's desired that the system adapts automatically to +- // various bpms, e.g. in processing continouos music stream. +- // The 'xcorr_decay' should be a value that's smaller than but +- // close to one, and should also depend on 'process_samples' value. ++ xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable time constant. + +- xcorr[offs] += (float)sum; ++ xcorr[offs] += (float)fabs(sum); + } + } + + +-// Calculates envelope of the sample data +-void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) ++// Detect individual beat positions ++void BPMDetect::updateBeatPos(int process_samples) + { +- const static double decay = 0.7f; // decay constant for smoothing the envelope +- const static double norm = (1 - decay); ++ SAMPLETYPE *pBuffer; + +- int i; +- LONG_SAMPLETYPE out; +- double val; ++ assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); ++ ++ pBuffer = buffer->ptrBegin(); ++ assert(process_samples == XCORR_UPDATE_SEQUENCE / 2); ++ ++ // static double thr = 0.0003; ++ double posScale = (double)this->decimateBy / (double)this->sampleRate; ++ int resetDur = (int)(0.12 / posScale + 0.5); ++ ++ // prescale pbuffer ++ float tmp[XCORR_UPDATE_SEQUENCE / 2]; ++ for (int i = 0; i < process_samples; i++) ++ { ++ tmp[i] = hamw2[i] * hamw2[i] * pBuffer[i]; ++ } + +- for (i = 0; i < numsamples; i ++) ++ #pragma omp parallel for ++ for (int offs = windowStart; offs < windowLen; offs++) + { +- // calc average RMS volume +- RMSVolumeAccu *= avgdecay; +- val = (float)fabs((float)samples[i]); +- RMSVolumeAccu += val * val; +- +- // cut amplitudes that are below cutoff ~2 times RMS volume +- // (we're interested in peak values, not the silent moments) +- if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm)) ++ float sum = 0; ++ for (int i = 0; i < process_samples; i++) + { +- val = 0; ++ sum += tmp[i] * pBuffer[offs + i]; + } ++ beatcorr_ringbuff[(beatcorr_ringbuffpos + offs) % windowLen] += (float)((sum > 0) ? sum : 0); // accumulate only positive correlations ++ } + +- // smooth amplitude envelope +- envelopeAccu *= decay; +- envelopeAccu += val; +- out = (LONG_SAMPLETYPE)(envelopeAccu * norm); ++ int skipstep = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR; + +-#ifdef SOUNDTOUCH_INTEGER_SAMPLES +- // cut peaks (shouldn't be necessary though) +- if (out > 32767) out = 32767; +-#endif // SOUNDTOUCH_INTEGER_SAMPLES +- samples[i] = (SAMPLETYPE)out; ++ // compensate empty buffer at beginning by scaling coefficient ++ float scale = (float)windowLen / (float)(skipstep * init_scaler); ++ if (scale > 1.0f) ++ { ++ init_scaler++; ++ } ++ else ++ { ++ scale = 1.0f; ++ } ++ ++ // detect beats ++ for (int i = 0; i < skipstep; i++) ++ { ++ LONG_SAMPLETYPE max = 0; ++ ++ float sum = beatcorr_ringbuff[beatcorr_ringbuffpos]; ++ sum -= beat_lpf.update(sum); ++ ++ if (sum > peakVal) ++ { ++ // found new local largest value ++ peakVal = sum; ++ peakPos = pos; ++ } ++ if (pos > peakPos + resetDur) ++ { ++ // largest value not updated for 200msec => accept as beat ++ peakPos += skipstep; ++ if (peakVal > 0) ++ { ++ // add detected beat to end of "beats" vector ++ BEAT temp = { (float)(peakPos * posScale), (float)(peakVal * scale) }; ++ beats.push_back(temp); ++ } ++ ++ peakVal = 0; ++ peakPos = pos; ++ } ++ ++ beatcorr_ringbuff[beatcorr_ringbuffpos] = 0; ++ pos++; ++ beatcorr_ringbuffpos = (beatcorr_ringbuffpos + 1) % windowLen; + } + } + + ++#define max(x,y) ((x) > (y) ? (x) : (y)) + + void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) + { +- SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; ++ SAMPLETYPE decimated[DECIMATED_BLOCK_SIZE]; + + // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration + while (numSamples > 0) +@@ -297,48 +421,70 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) + int block; + int decSamples; + +- block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples; ++ block = (numSamples > INPUT_BLOCK_SIZE) ? INPUT_BLOCK_SIZE : numSamples; + + // decimate. note that converts to mono at the same time + decSamples = decimate(decimated, samples, block); + samples += block * channels; + numSamples -= block; + +- // envelope new samples and add them to buffer +- calcEnvelope(decimated, decSamples); + buffer->putSamples(decimated, decSamples); + } + +- // when the buffer has enought samples for processing... +- if ((int)buffer->numSamples() > windowLen) ++ // when the buffer has enough samples for processing... ++ int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE); ++ while ((int)buffer->numSamples() >= req) + { +- int processLength; +- +- // how many samples are processed +- processLength = (int)buffer->numSamples() - windowLen; +- +- // ... calculate autocorrelations for oldest samples... +- updateXCorr(processLength); +- // ... and remove them from the buffer +- buffer->receiveSamples(processLength); ++ // ... update autocorrelations... ++ updateXCorr(XCORR_UPDATE_SEQUENCE); ++ // ...update beat position calculation... ++ updateBeatPos(XCORR_UPDATE_SEQUENCE / 2); ++ // ... and remove proceessed samples from the buffer ++ int n = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR; ++ buffer->receiveSamples(n); + } + } + + +- + void BPMDetect::removeBias() + { + int i; +- float minval = 1e12f; // arbitrary large number + ++ // Remove linear bias: calculate linear regression coefficient ++ // 1. calc mean of 'xcorr' and 'i' ++ double mean_i = 0; ++ double mean_x = 0; ++ for (i = windowStart; i < windowLen; i++) ++ { ++ mean_x += xcorr[i]; ++ } ++ mean_x /= (windowLen - windowStart); ++ mean_i = 0.5 * (windowLen - 1 + windowStart); ++ ++ // 2. calculate linear regression coefficient ++ double b = 0; ++ double div = 0; ++ for (i = windowStart; i < windowLen; i++) ++ { ++ double xt = xcorr[i] - mean_x; ++ double xi = i - mean_i; ++ b += xt * xi; ++ div += xi * xi; ++ } ++ b /= div; ++ ++ // subtract linear regression and resolve min. value bias ++ float minval = FLT_MAX; // arbitrary large number + for (i = windowStart; i < windowLen; i ++) + { ++ xcorr[i] -= (float)(b * i); + if (xcorr[i] < minval) + { + minval = xcorr[i]; + } + } + ++ // subtract min.value + for (i = windowStart; i < windowLen; i ++) + { + xcorr[i] -= minval; +@@ -346,26 +492,82 @@ void BPMDetect::removeBias() + } + + ++// Calculate N-point moving average for "source" values ++void MAFilter(float *dest, const float *source, int start, int end, int N) ++{ ++ for (int i = start; i < end; i++) ++ { ++ int i1 = i - N / 2; ++ int i2 = i + N / 2 + 1; ++ if (i1 < start) i1 = start; ++ if (i2 > end) i2 = end; ++ ++ double sum = 0; ++ for (int j = i1; j < i2; j ++) ++ { ++ sum += source[j]; ++ } ++ dest[i] = (float)(sum / (i2 - i1)); ++ } ++} ++ ++ + float BPMDetect::getBpm() + { + double peakPos; + double coeff; + PeakFinder peakFinder; + ++ // remove bias from xcorr data ++ removeBias(); ++ + coeff = 60.0 * ((double)sampleRate / (double)decimateBy); + +- // save bpm debug analysis data if debug data enabled +- _SaveDebugData(xcorr, windowStart, windowLen, coeff); ++ // save bpm debug data if debug data writing enabled ++ _SaveDebugData("soundtouch-bpm-xcorr.txt", xcorr, windowStart, windowLen, coeff); + +- // remove bias from xcorr data +- removeBias(); ++ // Smoothen by N-point moving-average ++ float *data = new float[windowLen]; ++ memset(data, 0, sizeof(float) * windowLen); ++ MAFilter(data, xcorr, windowStart, windowLen, MOVING_AVERAGE_N); + + // find peak position +- peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); ++ peakPos = peakFinder.detectPeak(data, windowStart, windowLen); ++ ++ // save bpm debug data if debug data writing enabled ++ _SaveDebugData("soundtouch-bpm-smoothed.txt", data, windowStart, windowLen, coeff); ++ ++ delete[] data; + + assert(decimateBy != 0); + if (peakPos < 1e-9) return 0.0; // detection failed. + ++ _SaveDebugBeatPos("soundtouch-detected-beats.txt", beats); ++ + // calculate BPM +- return (float) (coeff / peakPos); ++ float bpm = (float)(coeff / peakPos); ++ return (bpm >= MIN_BPM && bpm <= MAX_BPM_VALID) ? bpm : 0; ++} ++ ++ ++/// Get beat position arrays. Note: The array includes also really low beat detection values ++/// in absence of clear strong beats. Consumer may wish to filter low values away. ++/// - "pos" receive array of beat positions ++/// - "values" receive array of beat detection strengths ++/// - max_num indicates max.size of "pos" and "values" array. ++/// ++/// You can query a suitable array sized by calling this with NULL in "pos" & "values". ++/// ++/// \return number of beats in the arrays. ++int BPMDetect::getBeats(float *pos, float *values, int max_num) ++{ ++ int num = beats.size(); ++ if ((!pos) || (!values)) return num; // pos or values NULL, return just size ++ ++ for (int i = 0; (i < num) && (i < max_num); i++) ++ { ++ pos[i] = beats[i].pos; ++ values[i] = beats[i].strength; ++ } ++ return num; + } +diff --git a/Externals/soundtouch/BPMDetect.h b/Externals/soundtouch/BPMDetect.h +index 69d98143a7..8ece78448d 100644 +--- a/Externals/soundtouch/BPMDetect.h ++++ b/Externals/soundtouch/BPMDetect.h +@@ -26,13 +26,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2012-08-30 22:53:44 +0300 (Thu, 30 Aug 2012) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: BPMDetect.h 150 2012-08-30 19:53:44Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -57,108 +50,156 @@ + #ifndef _BPMDetect_H_ + #define _BPMDetect_H_ + ++#include + #include "STTypes.h" + #include "FIFOSampleBuffer.h" + + namespace soundtouch + { + +-/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. +-#define MIN_BPM 29 ++ /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. ++ #define MIN_BPM 45 + +-/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. +-#define MAX_BPM 200 ++ /// Maximum allowed BPM rate range. Used for calculating algorithm parametrs ++ #define MAX_BPM_RANGE 200 + ++ /// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit. ++ #define MAX_BPM_VALID 190 + +-/// Class for calculating BPM rate for audio data. +-class BPMDetect +-{ +-protected: +- /// Auto-correlation accumulator bins. +- float *xcorr; +- +- /// Amplitude envelope sliding average approximation level accumulator +- double envelopeAccu; +- +- /// RMS volume sliding average approximation level accumulator +- double RMSVolumeAccu; +- +- /// Sample average counter. +- int decimateCount; +- +- /// Sample average accumulator for FIFO-like decimation. +- soundtouch::LONG_SAMPLETYPE decimateSum; +- +- /// Decimate sound by this coefficient to reach approx. 500 Hz. +- int decimateBy; +- +- /// Auto-correlation window length +- int windowLen; +- +- /// Number of channels (1 = mono, 2 = stereo) +- int channels; +- +- /// sample rate +- int sampleRate; +- +- /// Beginning of auto-correlation window: Autocorrelation isn't being updated for +- /// the first these many correlation bins. +- int windowStart; +- +- /// FIFO-buffer for decimated processing samples. +- soundtouch::FIFOSampleBuffer *buffer; +- +- /// Updates auto-correlation function for given number of decimated samples that +- /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe +- /// though). +- void updateXCorr(int process_samples /// How many samples are processed. +- ); +- +- /// Decimates samples to approx. 500 Hz. +- /// +- /// \return Number of output samples. +- int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer +- const soundtouch::SAMPLETYPE *src, ///< Source sample buffer +- int numsamples ///< Number of source samples. +- ); +- +- /// Calculates amplitude envelope for the buffer of samples. +- /// Result is output to 'samples'. +- void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer +- int numsamples ///< Number of samples in buffer +- ); +- +- /// remove constant bias from xcorr data +- void removeBias(); +- +-public: +- /// Constructor. +- BPMDetect(int numChannels, ///< Number of channels in sample data. +- int sampleRate ///< Sample rate in Hz. +- ); +- +- /// Destructor. +- virtual ~BPMDetect(); +- +- /// Inputs a block of samples for analyzing: Envelopes the samples and then +- /// updates the autocorrelation estimation. When whole song data has been input +- /// in smaller blocks using this function, read the resulting bpm with 'getBpm' +- /// function. +- /// +- /// Notice that data in 'samples' array can be disrupted in processing. +- void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer +- int numSamples ///< Number of samples in buffer +- ); +- +- +- /// Analyzes the results and returns the BPM rate. Use this function to read result +- /// after whole song data has been input to the class by consecutive calls of +- /// 'inputSamples' function. +- /// +- /// \return Beats-per-minute rate, or zero if detection failed. +- float getBpm(); +-}; ++//////////////////////////////////////////////////////////////////////////////// + +-} ++ typedef struct ++ { ++ float pos; ++ float strength; ++ } BEAT; + ++ ++ class IIR2_filter ++ { ++ double coeffs[5]; ++ double prev[5]; ++ ++ public: ++ IIR2_filter(const double *lpf_coeffs); ++ float update(float x); ++ }; ++ ++ ++ /// Class for calculating BPM rate for audio data. ++ class BPMDetect ++ { ++ protected: ++ /// Auto-correlation accumulator bins. ++ float *xcorr; ++ ++ /// Sample average counter. ++ int decimateCount; ++ ++ /// Sample average accumulator for FIFO-like decimation. ++ soundtouch::LONG_SAMPLETYPE decimateSum; ++ ++ /// Decimate sound by this coefficient to reach approx. 500 Hz. ++ int decimateBy; ++ ++ /// Auto-correlation window length ++ int windowLen; ++ ++ /// Number of channels (1 = mono, 2 = stereo) ++ int channels; ++ ++ /// sample rate ++ int sampleRate; ++ ++ /// Beginning of auto-correlation window: Autocorrelation isn't being updated for ++ /// the first these many correlation bins. ++ int windowStart; ++ ++ /// window functions for data preconditioning ++ float *hamw; ++ float *hamw2; ++ ++ // beat detection variables ++ int pos; ++ int peakPos; ++ int beatcorr_ringbuffpos; ++ int init_scaler; ++ float peakVal; ++ float *beatcorr_ringbuff; ++ ++ /// FIFO-buffer for decimated processing samples. ++ soundtouch::FIFOSampleBuffer *buffer; ++ ++ /// Collection of detected beat positions ++ //BeatCollection beats; ++ std::vector beats; ++ ++ // 2nd order low-pass-filter ++ IIR2_filter beat_lpf; ++ ++ /// Updates auto-correlation function for given number of decimated samples that ++ /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe ++ /// though). ++ void updateXCorr(int process_samples /// How many samples are processed. ++ ); ++ ++ /// Decimates samples to approx. 500 Hz. ++ /// ++ /// \return Number of output samples. ++ int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer ++ const soundtouch::SAMPLETYPE *src, ///< Source sample buffer ++ int numsamples ///< Number of source samples. ++ ); ++ ++ /// Calculates amplitude envelope for the buffer of samples. ++ /// Result is output to 'samples'. ++ void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer ++ int numsamples ///< Number of samples in buffer ++ ); ++ ++ /// remove constant bias from xcorr data ++ void removeBias(); ++ ++ // Detect individual beat positions ++ void updateBeatPos(int process_samples); ++ ++ ++ public: ++ /// Constructor. ++ BPMDetect(int numChannels, ///< Number of channels in sample data. ++ int sampleRate ///< Sample rate in Hz. ++ ); ++ ++ /// Destructor. ++ virtual ~BPMDetect(); ++ ++ /// Inputs a block of samples for analyzing: Envelopes the samples and then ++ /// updates the autocorrelation estimation. When whole song data has been input ++ /// in smaller blocks using this function, read the resulting bpm with 'getBpm' ++ /// function. ++ /// ++ /// Notice that data in 'samples' array can be disrupted in processing. ++ void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer ++ int numSamples ///< Number of samples in buffer ++ ); ++ ++ /// Analyzes the results and returns the BPM rate. Use this function to read result ++ /// after whole song data has been input to the class by consecutive calls of ++ /// 'inputSamples' function. ++ /// ++ /// \return Beats-per-minute rate, or zero if detection failed. ++ float getBpm(); ++ ++ /// Get beat position arrays. Note: The array includes also really low beat detection values ++ /// in absence of clear strong beats. Consumer may wish to filter low values away. ++ /// - "pos" receive array of beat positions ++ /// - "values" receive array of beat detection strengths ++ /// - max_num indicates max.size of "pos" and "values" array. ++ /// ++ /// You can query a suitable array sized by calling this with NULL in "pos" & "values". ++ /// ++ /// \return number of beats in the arrays. ++ int getBeats(float *pos, float *strength, int max_num); ++ }; ++} + #endif // _BPMDetect_H_ +diff --git a/Externals/soundtouch/FIFOSampleBuffer.cpp b/Externals/soundtouch/FIFOSampleBuffer.cpp +index 5f5ec4b7db..8341163a60 100644 +--- a/Externals/soundtouch/FIFOSampleBuffer.cpp ++++ b/Externals/soundtouch/FIFOSampleBuffer.cpp +@@ -15,13 +15,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -80,7 +73,8 @@ void FIFOSampleBuffer::setChannels(int numChannels) + { + uint usedBytes; + +- assert(numChannels > 0); ++ if (!verifyNumberOfChannels(numChannels)) return; ++ + usedBytes = channels * samplesInBuffer; + channels = (uint)numChannels; + samplesInBuffer = usedBytes / channels; +@@ -131,7 +125,7 @@ void FIFOSampleBuffer::putSamples(uint nSamples) + // + // Parameter 'slackCapacity' tells the function how much free capacity (in + // terms of samples) there _at least_ should be, in order to the caller to +-// succesfully insert all the required samples to the buffer. When necessary, ++// successfully insert all the required samples to the buffer. When necessary, + // the function grows the buffer size to comply with this requirement. + // + // When using this function as means for inserting new samples, also remember +@@ -158,7 +152,7 @@ SAMPLETYPE *FIFOSampleBuffer::ptrBegin() + } + + +-// Ensures that the buffer has enought capacity, i.e. space for _at least_ ++// Ensures that the buffer has enough capacity, i.e. space for _at least_ + // 'capacityRequirement' number of samples. The buffer is grown in steps of + // 4 kilobytes to eliminate the need for frequently growing up the buffer, + // as well as to round the buffer size up to the virtual memory page size. +@@ -271,4 +265,3 @@ uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) + } + return samplesInBuffer; + } +- +diff --git a/Externals/soundtouch/FIFOSampleBuffer.h b/Externals/soundtouch/FIFOSampleBuffer.h +index 6f33df3daa..de298dd82b 100644 +--- a/Externals/soundtouch/FIFOSampleBuffer.h ++++ b/Externals/soundtouch/FIFOSampleBuffer.h +@@ -15,13 +15,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: FIFOSampleBuffer.h 177 2014-01-05 21:40:22Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -119,7 +112,7 @@ public: + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ +- ///< should be so that the caller can succesfully insert the ++ ///< should be so that the caller can successfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); +diff --git a/Externals/soundtouch/FIFOSamplePipe.h b/Externals/soundtouch/FIFOSamplePipe.h +index 6e3105970b..38ef31a5c2 100644 +--- a/Externals/soundtouch/FIFOSamplePipe.h ++++ b/Externals/soundtouch/FIFOSamplePipe.h +@@ -17,13 +17,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2012-06-13 22:29:53 +0300 (Wed, 13 Jun 2012) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -58,6 +51,18 @@ namespace soundtouch + /// Abstract base class for FIFO (first-in-first-out) sample processing classes. + class FIFOSamplePipe + { ++protected: ++ ++ bool verifyNumberOfChannels(int nChannels) const ++ { ++ if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS)) ++ { ++ return true; ++ } ++ ST_THROW_RT_ERROR("Error: Illegal number of channels"); ++ return false; ++ } ++ + public: + // virtual default destructor + virtual ~FIFOSamplePipe() {} +@@ -122,7 +127,6 @@ public: + }; + + +- + /// Base-class for sound processing routines working in FIFO principle. With this base + /// class it's easy to implement sound processing stages that can be chained together, + /// so that samples that are fed into beginning of the pipe automatically go through +@@ -145,7 +149,6 @@ protected: + output = pOutput; + } + +- + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() +@@ -153,7 +156,6 @@ protected: + output = NULL; + } + +- + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) +@@ -161,13 +163,11 @@ protected: + output = pOutput; + } + +- + /// Destructor. + virtual ~FIFOProcessor() + { + } + +- + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! +@@ -194,7 +194,6 @@ public: + return output->receiveSamples(outBuffer, maxSamples); + } + +- + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// +@@ -206,14 +205,12 @@ public: + return output->receiveSamples(maxSamples); + } + +- + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + +- + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { +@@ -226,7 +223,6 @@ public: + { + return output->adjustAmountOfSamples(numSamples); + } +- + }; + + } +diff --git a/Externals/soundtouch/FIRFilter.cpp b/Externals/soundtouch/FIRFilter.cpp +index e56969b053..218e50ef5a 100644 +--- a/Externals/soundtouch/FIRFilter.cpp ++++ b/Externals/soundtouch/FIRFilter.cpp +@@ -2,22 +2,21 @@ + /// + /// General FIR digital filter routines with MMX optimization. + /// +-/// Note : MMX optimized functions reside in a separate, platform-specific file, ++/// Notes : MMX optimized functions reside in a separate, platform-specific file, + /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' + /// ++/// This source file contains OpenMP optimizations that allow speeding up the ++/// corss-correlation algorithm by executing it in several threads / CPU cores ++/// in parallel. See the following article link for more detailed discussion ++/// about SoundTouch OpenMP optimizations: ++/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices ++/// + /// Author : Copyright (c) Olli Parviainen + /// Author e-mail : oparviai 'at' iki.fi + /// SoundTouch WWW: http://www.surina.net/soundtouch + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: FIRFilter.cpp 202 2015-02-21 21:24:29Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -69,6 +68,7 @@ FIRFilter::~FIRFilter() + delete[] filterCoeffs; + } + ++ + // Usual C-version of the filter routine for stereo sound + uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const + { +@@ -127,8 +127,6 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui + } + + +- +- + // Usual C-version of the filter routine for mono sound + uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const + { +@@ -254,7 +252,6 @@ uint FIRFilter::getLength() const + } + + +- + // Applies the filter to the given sequence of samples. + // + // Note : The amount of outputted samples is by value of 'filter_length' +@@ -284,7 +281,6 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample + } + + +- + // Operator 'new' is overloaded so that it automatically creates a suitable instance + // depending on if we've a MMX-capable CPU available or not. + void * FIRFilter::operator new(size_t s) +diff --git a/Externals/soundtouch/FIRFilter.h b/Externals/soundtouch/FIRFilter.h +index 6b14238ce8..297b0f81ec 100644 +--- a/Externals/soundtouch/FIRFilter.h ++++ b/Externals/soundtouch/FIRFilter.h +@@ -11,13 +11,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: FIRFilter.h 202 2015-02-21 21:24:29Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +diff --git a/Externals/soundtouch/InterpolateCubic.cpp b/Externals/soundtouch/InterpolateCubic.cpp +index 8aa7374c74..fe49684817 100644 +--- a/Externals/soundtouch/InterpolateCubic.cpp ++++ b/Externals/soundtouch/InterpolateCubic.cpp +@@ -1,200 +1,196 @@ +-//////////////////////////////////////////////////////////////////////////////// +-/// +-/// Cubic interpolation routine. +-/// +-/// Author : Copyright (c) Olli Parviainen +-/// Author e-mail : oparviai 'at' iki.fi +-/// SoundTouch WWW: http://www.surina.net/soundtouch +-/// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// $Id: InterpolateCubic.cpp 179 2014-01-06 18:41:42Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// License : +-// +-// SoundTouch audio processing library +-// Copyright (c) Olli Parviainen +-// +-// This library is free software; you can redistribute it and/or +-// modify it under the terms of the GNU Lesser General Public +-// License as published by the Free Software Foundation; either +-// version 2.1 of the License, or (at your option) any later version. +-// +-// This library is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-// Lesser General Public License for more details. +-// +-// You should have received a copy of the GNU Lesser General Public +-// License along with this library; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-//////////////////////////////////////////////////////////////////////////////// +- +-#include +-#include +-#include "InterpolateCubic.h" +-#include "STTypes.h" +- +-using namespace soundtouch; +- +-// cubic interpolation coefficients +-static const float _coeffs[]= +-{ -0.5f, 1.0f, -0.5f, 0.0f, +- 1.5f, -2.5f, 0.0f, 1.0f, +- -1.5f, 2.0f, 0.5f, 0.0f, +- 0.5f, -0.5f, 0.0f, 0.0f}; +- +- +-InterpolateCubic::InterpolateCubic() +-{ +- fract = 0; +-} +- +- +-void InterpolateCubic::resetRegisters() +-{ +- fract = 0; +-} +- +- +-/// Transpose mono audio. Returns number of produced output samples, and +-/// updates "srcSamples" to amount of consumed source samples +-int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, +- const SAMPLETYPE *psrc, +- int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 4; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- float out; +- const float x3 = 1.0f; +- const float x2 = (float)fract; // x +- const float x1 = x2*x2; // x^2 +- const float x0 = x1*x2; // x^3 +- float y0, y1, y2, y3; +- +- assert(fract < 1.0); +- +- y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; +- y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; +- y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; +- y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; +- +- out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3]; +- +- pdest[i] = (SAMPLETYPE)out; +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- psrc += whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} +- +- +-/// Transpose stereo audio. Returns number of produced output samples, and +-/// updates "srcSamples" to amount of consumed source samples +-int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, +- const SAMPLETYPE *psrc, +- int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 4; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- const float x3 = 1.0f; +- const float x2 = (float)fract; // x +- const float x1 = x2*x2; // x^2 +- const float x0 = x1*x2; // x^3 +- float y0, y1, y2, y3; +- float out0, out1; +- +- assert(fract < 1.0); +- +- y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; +- y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; +- y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; +- y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; +- +- out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6]; +- out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7]; +- +- pdest[2*i] = (SAMPLETYPE)out0; +- pdest[2*i+1] = (SAMPLETYPE)out1; +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- psrc += 2*whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} +- +- +-/// Transpose multi-channel audio. Returns number of produced output samples, and +-/// updates "srcSamples" to amount of consumed source samples +-int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, +- const SAMPLETYPE *psrc, +- int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 4; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- const float x3 = 1.0f; +- const float x2 = (float)fract; // x +- const float x1 = x2*x2; // x^2 +- const float x0 = x1*x2; // x^3 +- float y0, y1, y2, y3; +- +- assert(fract < 1.0); +- +- y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; +- y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; +- y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; +- y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; +- +- for (int c = 0; c < numChannels; c ++) +- { +- float out; +- out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; +- pdest[0] = (SAMPLETYPE)out; +- pdest ++; +- } +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- psrc += numChannels*whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} ++//////////////////////////////////////////////////////////////////////////////// ++/// ++/// Cubic interpolation routine. ++/// ++/// Author : Copyright (c) Olli Parviainen ++/// Author e-mail : oparviai 'at' iki.fi ++/// SoundTouch WWW: http://www.surina.net/soundtouch ++/// ++//////////////////////////////////////////////////////////////////////////////// ++// ++// License : ++// ++// SoundTouch audio processing library ++// Copyright (c) Olli Parviainen ++// ++// This library is free software; you can redistribute it and/or ++// modify it under the terms of the GNU Lesser General Public ++// License as published by the Free Software Foundation; either ++// version 2.1 of the License, or (at your option) any later version. ++// ++// This library is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++// Lesser General Public License for more details. ++// ++// You should have received a copy of the GNU Lesser General Public ++// License along with this library; if not, write to the Free Software ++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++// ++//////////////////////////////////////////////////////////////////////////////// ++ ++#include ++#include ++#include "InterpolateCubic.h" ++#include "STTypes.h" ++ ++using namespace soundtouch; ++ ++// cubic interpolation coefficients ++static const float _coeffs[]= ++{ -0.5f, 1.0f, -0.5f, 0.0f, ++ 1.5f, -2.5f, 0.0f, 1.0f, ++ -1.5f, 2.0f, 0.5f, 0.0f, ++ 0.5f, -0.5f, 0.0f, 0.0f}; ++ ++ ++InterpolateCubic::InterpolateCubic() ++{ ++ fract = 0; ++} ++ ++ ++void InterpolateCubic::resetRegisters() ++{ ++ fract = 0; ++} ++ ++ ++/// Transpose mono audio. Returns number of produced output samples, and ++/// updates "srcSamples" to amount of consumed source samples ++int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, ++ const SAMPLETYPE *psrc, ++ int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 4; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ float out; ++ const float x3 = 1.0f; ++ const float x2 = (float)fract; // x ++ const float x1 = x2*x2; // x^2 ++ const float x0 = x1*x2; // x^3 ++ float y0, y1, y2, y3; ++ ++ assert(fract < 1.0); ++ ++ y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; ++ y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; ++ y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; ++ y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; ++ ++ out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3]; ++ ++ pdest[i] = (SAMPLETYPE)out; ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ psrc += whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} ++ ++ ++/// Transpose stereo audio. Returns number of produced output samples, and ++/// updates "srcSamples" to amount of consumed source samples ++int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, ++ const SAMPLETYPE *psrc, ++ int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 4; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ const float x3 = 1.0f; ++ const float x2 = (float)fract; // x ++ const float x1 = x2*x2; // x^2 ++ const float x0 = x1*x2; // x^3 ++ float y0, y1, y2, y3; ++ float out0, out1; ++ ++ assert(fract < 1.0); ++ ++ y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; ++ y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; ++ y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; ++ y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; ++ ++ out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6]; ++ out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7]; ++ ++ pdest[2*i] = (SAMPLETYPE)out0; ++ pdest[2*i+1] = (SAMPLETYPE)out1; ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ psrc += 2*whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} ++ ++ ++/// Transpose multi-channel audio. Returns number of produced output samples, and ++/// updates "srcSamples" to amount of consumed source samples ++int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, ++ const SAMPLETYPE *psrc, ++ int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 4; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ const float x3 = 1.0f; ++ const float x2 = (float)fract; // x ++ const float x1 = x2*x2; // x^2 ++ const float x0 = x1*x2; // x^3 ++ float y0, y1, y2, y3; ++ ++ assert(fract < 1.0); ++ ++ y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; ++ y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; ++ y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; ++ y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; ++ ++ for (int c = 0; c < numChannels; c ++) ++ { ++ float out; ++ out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; ++ pdest[0] = (SAMPLETYPE)out; ++ pdest ++; ++ } ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ psrc += numChannels*whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} +diff --git a/Externals/soundtouch/InterpolateCubic.h b/Externals/soundtouch/InterpolateCubic.h +index f98e701d7b..457821033f 100644 +--- a/Externals/soundtouch/InterpolateCubic.h ++++ b/Externals/soundtouch/InterpolateCubic.h +@@ -1,67 +1,63 @@ +-//////////////////////////////////////////////////////////////////////////////// +-/// +-/// Cubic interpolation routine. +-/// +-/// Author : Copyright (c) Olli Parviainen +-/// Author e-mail : oparviai 'at' iki.fi +-/// SoundTouch WWW: http://www.surina.net/soundtouch +-/// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// $Id: InterpolateCubic.h 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// License : +-// +-// SoundTouch audio processing library +-// Copyright (c) Olli Parviainen +-// +-// This library is free software; you can redistribute it and/or +-// modify it under the terms of the GNU Lesser General Public +-// License as published by the Free Software Foundation; either +-// version 2.1 of the License, or (at your option) any later version. +-// +-// This library is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-// Lesser General Public License for more details. +-// +-// You should have received a copy of the GNU Lesser General Public +-// License along with this library; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-//////////////////////////////////////////////////////////////////////////////// +- +-#ifndef _InterpolateCubic_H_ +-#define _InterpolateCubic_H_ +- +-#include "RateTransposer.h" +-#include "STTypes.h" +- +-namespace soundtouch +-{ +- +-class InterpolateCubic : public TransposerBase +-{ +-protected: +- virtual void resetRegisters(); +- virtual int transposeMono(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- virtual int transposeStereo(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- virtual int transposeMulti(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- +- double fract; +- +-public: +- InterpolateCubic(); +-}; +- +-} +- +-#endif ++//////////////////////////////////////////////////////////////////////////////// ++/// ++/// Cubic interpolation routine. ++/// ++/// Author : Copyright (c) Olli Parviainen ++/// Author e-mail : oparviai 'at' iki.fi ++/// SoundTouch WWW: http://www.surina.net/soundtouch ++/// ++//////////////////////////////////////////////////////////////////////////////// ++// ++// License : ++// ++// SoundTouch audio processing library ++// Copyright (c) Olli Parviainen ++// ++// This library is free software; you can redistribute it and/or ++// modify it under the terms of the GNU Lesser General Public ++// License as published by the Free Software Foundation; either ++// version 2.1 of the License, or (at your option) any later version. ++// ++// This library is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++// Lesser General Public License for more details. ++// ++// You should have received a copy of the GNU Lesser General Public ++// License along with this library; if not, write to the Free Software ++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++// ++//////////////////////////////////////////////////////////////////////////////// ++ ++#ifndef _InterpolateCubic_H_ ++#define _InterpolateCubic_H_ ++ ++#include "RateTransposer.h" ++#include "STTypes.h" ++ ++namespace soundtouch ++{ ++ ++class InterpolateCubic : public TransposerBase ++{ ++protected: ++ virtual void resetRegisters(); ++ virtual int transposeMono(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ virtual int transposeStereo(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ virtual int transposeMulti(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ ++ double fract; ++ ++public: ++ InterpolateCubic(); ++}; ++ ++} ++ ++#endif +diff --git a/Externals/soundtouch/InterpolateLinear.cpp b/Externals/soundtouch/InterpolateLinear.cpp +index 8119813857..c3aa1994cf 100644 +--- a/Externals/soundtouch/InterpolateLinear.cpp ++++ b/Externals/soundtouch/InterpolateLinear.cpp +@@ -1,300 +1,296 @@ +-//////////////////////////////////////////////////////////////////////////////// +-/// +-/// Linear interpolation algorithm. +-/// +-/// Author : Copyright (c) Olli Parviainen +-/// Author e-mail : oparviai 'at' iki.fi +-/// SoundTouch WWW: http://www.surina.net/soundtouch +-/// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// $Id: InterpolateLinear.cpp 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// License : +-// +-// SoundTouch audio processing library +-// Copyright (c) Olli Parviainen +-// +-// This library is free software; you can redistribute it and/or +-// modify it under the terms of the GNU Lesser General Public +-// License as published by the Free Software Foundation; either +-// version 2.1 of the License, or (at your option) any later version. +-// +-// This library is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-// Lesser General Public License for more details. +-// +-// You should have received a copy of the GNU Lesser General Public +-// License along with this library; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-//////////////////////////////////////////////////////////////////////////////// +- +-#include +-#include +-#include "InterpolateLinear.h" +- +-using namespace soundtouch; +- +-////////////////////////////////////////////////////////////////////////////// +-// +-// InterpolateLinearInteger - integer arithmetic implementation +-// +- +-/// fixed-point interpolation routine precision +-#define SCALE 65536 +- +- +-// Constructor +-InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() +-{ +- // Notice: use local function calling syntax for sake of clarity, +- // to indicate the fact that C++ constructor can't call virtual functions. +- resetRegisters(); +- setRate(1.0f); +-} +- +- +-void InterpolateLinearInteger::resetRegisters() +-{ +- iFract = 0; +-} +- +- +-// Transposes the sample rate of the given samples using linear interpolation. +-// 'Mono' version of the routine. Returns the number of samples returned in +-// the "dest" buffer +-int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 1; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- LONG_SAMPLETYPE temp; +- +- assert(iFract < SCALE); +- +- temp = (SCALE - iFract) * src[0] + iFract * src[1]; +- dest[i] = (SAMPLETYPE)(temp / SCALE); +- i++; +- +- iFract += iRate; +- +- int iWhole = iFract / SCALE; +- iFract -= iWhole * SCALE; +- srcCount += iWhole; +- src += iWhole; +- } +- srcSamples = srcCount; +- +- return i; +-} +- +- +-// Transposes the sample rate of the given samples using linear interpolation. +-// 'Stereo' version of the routine. Returns the number of samples returned in +-// the "dest" buffer +-int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 1; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- LONG_SAMPLETYPE temp0; +- LONG_SAMPLETYPE temp1; +- +- assert(iFract < SCALE); +- +- temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; +- temp1 = (SCALE - iFract) * src[1] + iFract * src[3]; +- dest[0] = (SAMPLETYPE)(temp0 / SCALE); +- dest[1] = (SAMPLETYPE)(temp1 / SCALE); +- dest += 2; +- i++; +- +- iFract += iRate; +- +- int iWhole = iFract / SCALE; +- iFract -= iWhole * SCALE; +- srcCount += iWhole; +- src += 2*iWhole; +- } +- srcSamples = srcCount; +- +- return i; +-} +- +- +-int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 1; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- LONG_SAMPLETYPE temp, vol1; +- +- assert(iFract < SCALE); +- vol1 = (SCALE - iFract); +- for (int c = 0; c < numChannels; c ++) +- { +- temp = vol1 * src[c] + iFract * src[c + numChannels]; +- dest[0] = (SAMPLETYPE)(temp / SCALE); +- dest ++; +- } +- i++; +- +- iFract += iRate; +- +- int iWhole = iFract / SCALE; +- iFract -= iWhole * SCALE; +- srcCount += iWhole; +- src += iWhole * numChannels; +- } +- srcSamples = srcCount; +- +- return i; +-} +- +- +-// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower +-// iRate, larger faster iRates. +-void InterpolateLinearInteger::setRate(double newRate) +-{ +- iRate = (int)(newRate * SCALE + 0.5); +- TransposerBase::setRate(newRate); +-} +- +- +-////////////////////////////////////////////////////////////////////////////// +-// +-// InterpolateLinearFloat - floating point arithmetic implementation +-// +-////////////////////////////////////////////////////////////////////////////// +- +- +-// Constructor +-InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() +-{ +- // Notice: use local function calling syntax for sake of clarity, +- // to indicate the fact that C++ constructor can't call virtual functions. +- resetRegisters(); +- setRate(1.0); +-} +- +- +-void InterpolateLinearFloat::resetRegisters() +-{ +- fract = 0; +-} +- +- +-// Transposes the sample rate of the given samples using linear interpolation. +-// 'Mono' version of the routine. Returns the number of samples returned in +-// the "dest" buffer +-int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 1; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- double out; +- assert(fract < 1.0); +- +- out = (1.0 - fract) * src[0] + fract * src[1]; +- dest[i] = (SAMPLETYPE)out; +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- src += whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} +- +- +-// Transposes the sample rate of the given samples using linear interpolation. +-// 'Mono' version of the routine. Returns the number of samples returned in +-// the "dest" buffer +-int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 1; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- double out0, out1; +- assert(fract < 1.0); +- +- out0 = (1.0 - fract) * src[0] + fract * src[2]; +- out1 = (1.0 - fract) * src[1] + fract * src[3]; +- dest[2*i] = (SAMPLETYPE)out0; +- dest[2*i+1] = (SAMPLETYPE)out1; +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- src += 2*whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} +- +- +-int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 1; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- float temp, vol1, fract_float; +- +- vol1 = (float)(1.0 - fract); +- fract_float = (float)fract; +- for (int c = 0; c < numChannels; c ++) +- { +- temp = vol1 * src[c] + fract_float * src[c + numChannels]; +- *dest = (SAMPLETYPE)temp; +- dest ++; +- } +- i++; +- +- fract += rate; +- +- int iWhole = (int)fract; +- fract -= iWhole; +- srcCount += iWhole; +- src += iWhole * numChannels; +- } +- srcSamples = srcCount; +- +- return i; +-} ++//////////////////////////////////////////////////////////////////////////////// ++/// ++/// Linear interpolation algorithm. ++/// ++/// Author : Copyright (c) Olli Parviainen ++/// Author e-mail : oparviai 'at' iki.fi ++/// SoundTouch WWW: http://www.surina.net/soundtouch ++/// ++//////////////////////////////////////////////////////////////////////////////// ++// ++// License : ++// ++// SoundTouch audio processing library ++// Copyright (c) Olli Parviainen ++// ++// This library is free software; you can redistribute it and/or ++// modify it under the terms of the GNU Lesser General Public ++// License as published by the Free Software Foundation; either ++// version 2.1 of the License, or (at your option) any later version. ++// ++// This library is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++// Lesser General Public License for more details. ++// ++// You should have received a copy of the GNU Lesser General Public ++// License along with this library; if not, write to the Free Software ++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++// ++//////////////////////////////////////////////////////////////////////////////// ++ ++#include ++#include ++#include "InterpolateLinear.h" ++ ++using namespace soundtouch; ++ ++////////////////////////////////////////////////////////////////////////////// ++// ++// InterpolateLinearInteger - integer arithmetic implementation ++// ++ ++/// fixed-point interpolation routine precision ++#define SCALE 65536 ++ ++ ++// Constructor ++InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() ++{ ++ // Notice: use local function calling syntax for sake of clarity, ++ // to indicate the fact that C++ constructor can't call virtual functions. ++ resetRegisters(); ++ setRate(1.0f); ++} ++ ++ ++void InterpolateLinearInteger::resetRegisters() ++{ ++ iFract = 0; ++} ++ ++ ++// Transposes the sample rate of the given samples using linear interpolation. ++// 'Mono' version of the routine. Returns the number of samples returned in ++// the "dest" buffer ++int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 1; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ LONG_SAMPLETYPE temp; ++ ++ assert(iFract < SCALE); ++ ++ temp = (SCALE - iFract) * src[0] + iFract * src[1]; ++ dest[i] = (SAMPLETYPE)(temp / SCALE); ++ i++; ++ ++ iFract += iRate; ++ ++ int iWhole = iFract / SCALE; ++ iFract -= iWhole * SCALE; ++ srcCount += iWhole; ++ src += iWhole; ++ } ++ srcSamples = srcCount; ++ ++ return i; ++} ++ ++ ++// Transposes the sample rate of the given samples using linear interpolation. ++// 'Stereo' version of the routine. Returns the number of samples returned in ++// the "dest" buffer ++int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 1; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ LONG_SAMPLETYPE temp0; ++ LONG_SAMPLETYPE temp1; ++ ++ assert(iFract < SCALE); ++ ++ temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; ++ temp1 = (SCALE - iFract) * src[1] + iFract * src[3]; ++ dest[0] = (SAMPLETYPE)(temp0 / SCALE); ++ dest[1] = (SAMPLETYPE)(temp1 / SCALE); ++ dest += 2; ++ i++; ++ ++ iFract += iRate; ++ ++ int iWhole = iFract / SCALE; ++ iFract -= iWhole * SCALE; ++ srcCount += iWhole; ++ src += 2*iWhole; ++ } ++ srcSamples = srcCount; ++ ++ return i; ++} ++ ++ ++int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 1; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ LONG_SAMPLETYPE temp, vol1; ++ ++ assert(iFract < SCALE); ++ vol1 = (SCALE - iFract); ++ for (int c = 0; c < numChannels; c ++) ++ { ++ temp = vol1 * src[c] + iFract * src[c + numChannels]; ++ dest[0] = (SAMPLETYPE)(temp / SCALE); ++ dest ++; ++ } ++ i++; ++ ++ iFract += iRate; ++ ++ int iWhole = iFract / SCALE; ++ iFract -= iWhole * SCALE; ++ srcCount += iWhole; ++ src += iWhole * numChannels; ++ } ++ srcSamples = srcCount; ++ ++ return i; ++} ++ ++ ++// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower ++// iRate, larger faster iRates. ++void InterpolateLinearInteger::setRate(double newRate) ++{ ++ iRate = (int)(newRate * SCALE + 0.5); ++ TransposerBase::setRate(newRate); ++} ++ ++ ++////////////////////////////////////////////////////////////////////////////// ++// ++// InterpolateLinearFloat - floating point arithmetic implementation ++// ++////////////////////////////////////////////////////////////////////////////// ++ ++ ++// Constructor ++InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() ++{ ++ // Notice: use local function calling syntax for sake of clarity, ++ // to indicate the fact that C++ constructor can't call virtual functions. ++ resetRegisters(); ++ setRate(1.0); ++} ++ ++ ++void InterpolateLinearFloat::resetRegisters() ++{ ++ fract = 0; ++} ++ ++ ++// Transposes the sample rate of the given samples using linear interpolation. ++// 'Mono' version of the routine. Returns the number of samples returned in ++// the "dest" buffer ++int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 1; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ double out; ++ assert(fract < 1.0); ++ ++ out = (1.0 - fract) * src[0] + fract * src[1]; ++ dest[i] = (SAMPLETYPE)out; ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ src += whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} ++ ++ ++// Transposes the sample rate of the given samples using linear interpolation. ++// 'Mono' version of the routine. Returns the number of samples returned in ++// the "dest" buffer ++int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 1; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ double out0, out1; ++ assert(fract < 1.0); ++ ++ out0 = (1.0 - fract) * src[0] + fract * src[2]; ++ out1 = (1.0 - fract) * src[1] + fract * src[3]; ++ dest[2*i] = (SAMPLETYPE)out0; ++ dest[2*i+1] = (SAMPLETYPE)out1; ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ src += 2*whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} ++ ++ ++int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 1; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ float temp, vol1, fract_float; ++ ++ vol1 = (float)(1.0 - fract); ++ fract_float = (float)fract; ++ for (int c = 0; c < numChannels; c ++) ++ { ++ temp = vol1 * src[c] + fract_float * src[c + numChannels]; ++ *dest = (SAMPLETYPE)temp; ++ dest ++; ++ } ++ i++; ++ ++ fract += rate; ++ ++ int iWhole = (int)fract; ++ fract -= iWhole; ++ srcCount += iWhole; ++ src += iWhole * numChannels; ++ } ++ srcSamples = srcCount; ++ ++ return i; ++} +diff --git a/Externals/soundtouch/InterpolateLinear.h b/Externals/soundtouch/InterpolateLinear.h +index 6a7e11d18b..faa2e2c5a5 100644 +--- a/Externals/soundtouch/InterpolateLinear.h ++++ b/Externals/soundtouch/InterpolateLinear.h +@@ -1,92 +1,88 @@ +-//////////////////////////////////////////////////////////////////////////////// +-/// +-/// Linear interpolation routine. +-/// +-/// Author : Copyright (c) Olli Parviainen +-/// Author e-mail : oparviai 'at' iki.fi +-/// SoundTouch WWW: http://www.surina.net/soundtouch +-/// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// $Id: InterpolateLinear.h 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// License : +-// +-// SoundTouch audio processing library +-// Copyright (c) Olli Parviainen +-// +-// This library is free software; you can redistribute it and/or +-// modify it under the terms of the GNU Lesser General Public +-// License as published by the Free Software Foundation; either +-// version 2.1 of the License, or (at your option) any later version. +-// +-// This library is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-// Lesser General Public License for more details. +-// +-// You should have received a copy of the GNU Lesser General Public +-// License along with this library; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-//////////////////////////////////////////////////////////////////////////////// +- +-#ifndef _InterpolateLinear_H_ +-#define _InterpolateLinear_H_ +- +-#include "RateTransposer.h" +-#include "STTypes.h" +- +-namespace soundtouch +-{ +- +-/// Linear transposer class that uses integer arithmetics +-class InterpolateLinearInteger : public TransposerBase +-{ +-protected: +- int iFract; +- int iRate; +- +- virtual void resetRegisters(); +- +- virtual int transposeMono(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- virtual int transposeStereo(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); +-public: +- InterpolateLinearInteger(); +- +- /// Sets new target rate. Normal rate = 1.0, smaller values represent slower +- /// rate, larger faster rates. +- virtual void setRate(double newRate); +-}; +- +- +-/// Linear transposer class that uses floating point arithmetics +-class InterpolateLinearFloat : public TransposerBase +-{ +-protected: +- double fract; +- +- virtual void resetRegisters(); +- +- virtual int transposeMono(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- virtual int transposeStereo(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); +- +-public: +- InterpolateLinearFloat(); +-}; +- +-} +- +-#endif ++//////////////////////////////////////////////////////////////////////////////// ++/// ++/// Linear interpolation routine. ++/// ++/// Author : Copyright (c) Olli Parviainen ++/// Author e-mail : oparviai 'at' iki.fi ++/// SoundTouch WWW: http://www.surina.net/soundtouch ++/// ++//////////////////////////////////////////////////////////////////////////////// ++// ++// License : ++// ++// SoundTouch audio processing library ++// Copyright (c) Olli Parviainen ++// ++// This library is free software; you can redistribute it and/or ++// modify it under the terms of the GNU Lesser General Public ++// License as published by the Free Software Foundation; either ++// version 2.1 of the License, or (at your option) any later version. ++// ++// This library is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++// Lesser General Public License for more details. ++// ++// You should have received a copy of the GNU Lesser General Public ++// License along with this library; if not, write to the Free Software ++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++// ++//////////////////////////////////////////////////////////////////////////////// ++ ++#ifndef _InterpolateLinear_H_ ++#define _InterpolateLinear_H_ ++ ++#include "RateTransposer.h" ++#include "STTypes.h" ++ ++namespace soundtouch ++{ ++ ++/// Linear transposer class that uses integer arithmetic ++class InterpolateLinearInteger : public TransposerBase ++{ ++protected: ++ int iFract; ++ int iRate; ++ ++ virtual void resetRegisters(); ++ ++ virtual int transposeMono(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ virtual int transposeStereo(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); ++public: ++ InterpolateLinearInteger(); ++ ++ /// Sets new target rate. Normal rate = 1.0, smaller values represent slower ++ /// rate, larger faster rates. ++ virtual void setRate(double newRate); ++}; ++ ++ ++/// Linear transposer class that uses floating point arithmetic ++class InterpolateLinearFloat : public TransposerBase ++{ ++protected: ++ double fract; ++ ++ virtual void resetRegisters(); ++ ++ virtual int transposeMono(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ virtual int transposeStereo(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); ++ ++public: ++ InterpolateLinearFloat(); ++}; ++ ++} ++ ++#endif +diff --git a/Externals/soundtouch/InterpolateShannon.cpp b/Externals/soundtouch/InterpolateShannon.cpp +index 1085fd14cb..1d69a2e884 100644 +--- a/Externals/soundtouch/InterpolateShannon.cpp ++++ b/Externals/soundtouch/InterpolateShannon.cpp +@@ -1,185 +1,181 @@ +-//////////////////////////////////////////////////////////////////////////////// +-/// +-/// Sample interpolation routine using 8-tap band-limited Shannon interpolation +-/// with kaiser window. +-/// +-/// Notice. This algorithm is remarkably much heavier than linear or cubic +-/// interpolation, and not remarkably better than cubic algorithm. Thus mostly +-/// for experimental purposes +-/// +-/// Author : Copyright (c) Olli Parviainen +-/// Author e-mail : oparviai 'at' iki.fi +-/// SoundTouch WWW: http://www.surina.net/soundtouch +-/// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// $Id: InterpolateShannon.cpp 195 2014-04-06 15:57:21Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// License : +-// +-// SoundTouch audio processing library +-// Copyright (c) Olli Parviainen +-// +-// This library is free software; you can redistribute it and/or +-// modify it under the terms of the GNU Lesser General Public +-// License as published by the Free Software Foundation; either +-// version 2.1 of the License, or (at your option) any later version. +-// +-// This library is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-// Lesser General Public License for more details. +-// +-// You should have received a copy of the GNU Lesser General Public +-// License along with this library; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-//////////////////////////////////////////////////////////////////////////////// +- +-#include +-#include "InterpolateShannon.h" +-#include "STTypes.h" +- +-using namespace soundtouch; +- +- +-/// Kaiser window with beta = 2.0 +-/// Values scaled down by 5% to avoid overflows +-static const double _kaiser8[8] = +-{ +- 0.41778693317814, +- 0.64888025049173, +- 0.83508562409944, +- 0.93887857733412, +- 0.93887857733412, +- 0.83508562409944, +- 0.64888025049173, +- 0.41778693317814 +-}; +- +- +-InterpolateShannon::InterpolateShannon() +-{ +- fract = 0; +-} +- +- +-void InterpolateShannon::resetRegisters() +-{ +- fract = 0; +-} +- +- +-#define PI 3.1415926536 +-#define sinc(x) (sin(PI * (x)) / (PI * (x))) +- +-/// Transpose mono audio. Returns number of produced output samples, and +-/// updates "srcSamples" to amount of consumed source samples +-int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, +- const SAMPLETYPE *psrc, +- int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 8; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- double out; +- assert(fract < 1.0); +- +- out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0]; +- out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1]; +- out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2]; +- if (fract < 1e-6) +- { +- out += psrc[3] * _kaiser8[3]; // sinc(0) = 1 +- } +- else +- { +- out += psrc[3] * sinc(- fract) * _kaiser8[3]; +- } +- out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4]; +- out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5]; +- out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6]; +- out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7]; +- +- pdest[i] = (SAMPLETYPE)out; +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- psrc += whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} +- +- +-/// Transpose stereo audio. Returns number of produced output samples, and +-/// updates "srcSamples" to amount of consumed source samples +-int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, +- const SAMPLETYPE *psrc, +- int &srcSamples) +-{ +- int i; +- int srcSampleEnd = srcSamples - 8; +- int srcCount = 0; +- +- i = 0; +- while (srcCount < srcSampleEnd) +- { +- double out0, out1, w; +- assert(fract < 1.0); +- +- w = sinc(-3.0 - fract) * _kaiser8[0]; +- out0 = psrc[0] * w; out1 = psrc[1] * w; +- w = sinc(-2.0 - fract) * _kaiser8[1]; +- out0 += psrc[2] * w; out1 += psrc[3] * w; +- w = sinc(-1.0 - fract) * _kaiser8[2]; +- out0 += psrc[4] * w; out1 += psrc[5] * w; +- w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1 +- out0 += psrc[6] * w; out1 += psrc[7] * w; +- w = sinc( 1.0 - fract) * _kaiser8[4]; +- out0 += psrc[8] * w; out1 += psrc[9] * w; +- w = sinc( 2.0 - fract) * _kaiser8[5]; +- out0 += psrc[10] * w; out1 += psrc[11] * w; +- w = sinc( 3.0 - fract) * _kaiser8[6]; +- out0 += psrc[12] * w; out1 += psrc[13] * w; +- w = sinc( 4.0 - fract) * _kaiser8[7]; +- out0 += psrc[14] * w; out1 += psrc[15] * w; +- +- pdest[2*i] = (SAMPLETYPE)out0; +- pdest[2*i+1] = (SAMPLETYPE)out1; +- i ++; +- +- // update position fraction +- fract += rate; +- // update whole positions +- int whole = (int)fract; +- fract -= whole; +- psrc += 2*whole; +- srcCount += whole; +- } +- srcSamples = srcCount; +- return i; +-} +- +- +-/// Transpose stereo audio. Returns number of produced output samples, and +-/// updates "srcSamples" to amount of consumed source samples +-int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, +- const SAMPLETYPE *psrc, +- int &srcSamples) +-{ +- // not implemented +- assert(false); +- return 0; +-} ++//////////////////////////////////////////////////////////////////////////////// ++/// ++/// Sample interpolation routine using 8-tap band-limited Shannon interpolation ++/// with kaiser window. ++/// ++/// Notice. This algorithm is remarkably much heavier than linear or cubic ++/// interpolation, and not remarkably better than cubic algorithm. Thus mostly ++/// for experimental purposes ++/// ++/// Author : Copyright (c) Olli Parviainen ++/// Author e-mail : oparviai 'at' iki.fi ++/// SoundTouch WWW: http://www.surina.net/soundtouch ++/// ++//////////////////////////////////////////////////////////////////////////////// ++// ++// License : ++// ++// SoundTouch audio processing library ++// Copyright (c) Olli Parviainen ++// ++// This library is free software; you can redistribute it and/or ++// modify it under the terms of the GNU Lesser General Public ++// License as published by the Free Software Foundation; either ++// version 2.1 of the License, or (at your option) any later version. ++// ++// This library is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++// Lesser General Public License for more details. ++// ++// You should have received a copy of the GNU Lesser General Public ++// License along with this library; if not, write to the Free Software ++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++// ++//////////////////////////////////////////////////////////////////////////////// ++ ++#include ++#include "InterpolateShannon.h" ++#include "STTypes.h" ++ ++using namespace soundtouch; ++ ++ ++/// Kaiser window with beta = 2.0 ++/// Values scaled down by 5% to avoid overflows ++static const double _kaiser8[8] = ++{ ++ 0.41778693317814, ++ 0.64888025049173, ++ 0.83508562409944, ++ 0.93887857733412, ++ 0.93887857733412, ++ 0.83508562409944, ++ 0.64888025049173, ++ 0.41778693317814 ++}; ++ ++ ++InterpolateShannon::InterpolateShannon() ++{ ++ fract = 0; ++} ++ ++ ++void InterpolateShannon::resetRegisters() ++{ ++ fract = 0; ++} ++ ++ ++#define PI 3.1415926536 ++#define sinc(x) (sin(PI * (x)) / (PI * (x))) ++ ++/// Transpose mono audio. Returns number of produced output samples, and ++/// updates "srcSamples" to amount of consumed source samples ++int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, ++ const SAMPLETYPE *psrc, ++ int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 8; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ double out; ++ assert(fract < 1.0); ++ ++ out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0]; ++ out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1]; ++ out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2]; ++ if (fract < 1e-6) ++ { ++ out += psrc[3] * _kaiser8[3]; // sinc(0) = 1 ++ } ++ else ++ { ++ out += psrc[3] * sinc(- fract) * _kaiser8[3]; ++ } ++ out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4]; ++ out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5]; ++ out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6]; ++ out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7]; ++ ++ pdest[i] = (SAMPLETYPE)out; ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ psrc += whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} ++ ++ ++/// Transpose stereo audio. Returns number of produced output samples, and ++/// updates "srcSamples" to amount of consumed source samples ++int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, ++ const SAMPLETYPE *psrc, ++ int &srcSamples) ++{ ++ int i; ++ int srcSampleEnd = srcSamples - 8; ++ int srcCount = 0; ++ ++ i = 0; ++ while (srcCount < srcSampleEnd) ++ { ++ double out0, out1, w; ++ assert(fract < 1.0); ++ ++ w = sinc(-3.0 - fract) * _kaiser8[0]; ++ out0 = psrc[0] * w; out1 = psrc[1] * w; ++ w = sinc(-2.0 - fract) * _kaiser8[1]; ++ out0 += psrc[2] * w; out1 += psrc[3] * w; ++ w = sinc(-1.0 - fract) * _kaiser8[2]; ++ out0 += psrc[4] * w; out1 += psrc[5] * w; ++ w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1 ++ out0 += psrc[6] * w; out1 += psrc[7] * w; ++ w = sinc( 1.0 - fract) * _kaiser8[4]; ++ out0 += psrc[8] * w; out1 += psrc[9] * w; ++ w = sinc( 2.0 - fract) * _kaiser8[5]; ++ out0 += psrc[10] * w; out1 += psrc[11] * w; ++ w = sinc( 3.0 - fract) * _kaiser8[6]; ++ out0 += psrc[12] * w; out1 += psrc[13] * w; ++ w = sinc( 4.0 - fract) * _kaiser8[7]; ++ out0 += psrc[14] * w; out1 += psrc[15] * w; ++ ++ pdest[2*i] = (SAMPLETYPE)out0; ++ pdest[2*i+1] = (SAMPLETYPE)out1; ++ i ++; ++ ++ // update position fraction ++ fract += rate; ++ // update whole positions ++ int whole = (int)fract; ++ fract -= whole; ++ psrc += 2*whole; ++ srcCount += whole; ++ } ++ srcSamples = srcCount; ++ return i; ++} ++ ++ ++/// Transpose stereo audio. Returns number of produced output samples, and ++/// updates "srcSamples" to amount of consumed source samples ++int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, ++ const SAMPLETYPE *psrc, ++ int &srcSamples) ++{ ++ // not implemented ++ assert(false); ++ return 0; ++} +diff --git a/Externals/soundtouch/InterpolateShannon.h b/Externals/soundtouch/InterpolateShannon.h +index 54703d9808..c621cf1e1d 100644 +--- a/Externals/soundtouch/InterpolateShannon.h ++++ b/Externals/soundtouch/InterpolateShannon.h +@@ -1,72 +1,68 @@ +-//////////////////////////////////////////////////////////////////////////////// +-/// +-/// Sample interpolation routine using 8-tap band-limited Shannon interpolation +-/// with kaiser window. +-/// +-/// Notice. This algorithm is remarkably much heavier than linear or cubic +-/// interpolation, and not remarkably better than cubic algorithm. Thus mostly +-/// for experimental purposes +-/// +-/// Author : Copyright (c) Olli Parviainen +-/// Author e-mail : oparviai 'at' iki.fi +-/// SoundTouch WWW: http://www.surina.net/soundtouch +-/// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// $Id: InterpolateShannon.h 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// +-// License : +-// +-// SoundTouch audio processing library +-// Copyright (c) Olli Parviainen +-// +-// This library is free software; you can redistribute it and/or +-// modify it under the terms of the GNU Lesser General Public +-// License as published by the Free Software Foundation; either +-// version 2.1 of the License, or (at your option) any later version. +-// +-// This library is distributed in the hope that it will be useful, +-// but WITHOUT ANY WARRANTY; without even the implied warranty of +-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-// Lesser General Public License for more details. +-// +-// You should have received a copy of the GNU Lesser General Public +-// License along with this library; if not, write to the Free Software +-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +-// +-//////////////////////////////////////////////////////////////////////////////// +- +-#ifndef _InterpolateShannon_H_ +-#define _InterpolateShannon_H_ +- +-#include "RateTransposer.h" +-#include "STTypes.h" +- +-namespace soundtouch +-{ +- +-class InterpolateShannon : public TransposerBase +-{ +-protected: +- void resetRegisters(); +- int transposeMono(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- int transposeStereo(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- int transposeMulti(SAMPLETYPE *dest, +- const SAMPLETYPE *src, +- int &srcSamples); +- +- double fract; +- +-public: +- InterpolateShannon(); +-}; +- +-} +- +-#endif ++//////////////////////////////////////////////////////////////////////////////// ++/// ++/// Sample interpolation routine using 8-tap band-limited Shannon interpolation ++/// with kaiser window. ++/// ++/// Notice. This algorithm is remarkably much heavier than linear or cubic ++/// interpolation, and not remarkably better than cubic algorithm. Thus mostly ++/// for experimental purposes ++/// ++/// Author : Copyright (c) Olli Parviainen ++/// Author e-mail : oparviai 'at' iki.fi ++/// SoundTouch WWW: http://www.surina.net/soundtouch ++/// ++//////////////////////////////////////////////////////////////////////////////// ++// ++// License : ++// ++// SoundTouch audio processing library ++// Copyright (c) Olli Parviainen ++// ++// This library is free software; you can redistribute it and/or ++// modify it under the terms of the GNU Lesser General Public ++// License as published by the Free Software Foundation; either ++// version 2.1 of the License, or (at your option) any later version. ++// ++// This library is distributed in the hope that it will be useful, ++// but WITHOUT ANY WARRANTY; without even the implied warranty of ++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++// Lesser General Public License for more details. ++// ++// You should have received a copy of the GNU Lesser General Public ++// License along with this library; if not, write to the Free Software ++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++// ++//////////////////////////////////////////////////////////////////////////////// ++ ++#ifndef _InterpolateShannon_H_ ++#define _InterpolateShannon_H_ ++ ++#include "RateTransposer.h" ++#include "STTypes.h" ++ ++namespace soundtouch ++{ ++ ++class InterpolateShannon : public TransposerBase ++{ ++protected: ++ void resetRegisters(); ++ int transposeMono(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ int transposeStereo(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ int transposeMulti(SAMPLETYPE *dest, ++ const SAMPLETYPE *src, ++ int &srcSamples); ++ ++ double fract; ++ ++public: ++ InterpolateShannon(); ++}; ++ ++} ++ ++#endif +diff --git a/Externals/soundtouch/PeakFinder.cpp b/Externals/soundtouch/PeakFinder.cpp +index 111cc88bbd..34db39bc23 100644 +--- a/Externals/soundtouch/PeakFinder.cpp ++++ b/Externals/soundtouch/PeakFinder.cpp +@@ -11,13 +11,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-05-18 18:22:02 +0300 (Mon, 18 May 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: PeakFinder.cpp 213 2015-05-18 15:22:02Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -64,7 +57,7 @@ int PeakFinder::findTop(const float *data, int peakpos) const + + refvalue = data[peakpos]; + +- // seek within �10 points ++ // seek within �10 points + start = peakpos - 10; + if (start < minPos) start = minPos; + end = peakpos + 10; +@@ -149,7 +142,7 @@ int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, i + peaklevel = data[peakpos]; + assert(peaklevel >= level); + pos = peakpos; +- while ((pos >= minPos) && (pos < maxPos)) ++ while ((pos >= minPos) && (pos + direction < maxPos)) + { + if (data[pos + direction] < level) return pos; // crossing found + pos += direction; +@@ -178,7 +171,6 @@ double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) + } + + +- + /// get exact center of peak near given position by calculating local mass of center + double PeakFinder::getPeakCenter(const float *data, int peakpos) const + { +@@ -218,7 +210,6 @@ double PeakFinder::getPeakCenter(const float *data, int peakpos) const + } + + +- + double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) + { + +@@ -249,12 +240,12 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) + // - sometimes the highest peak can be Nth harmonic of the true base peak yet + // just a slightly higher than the true base + +- for (i = 3; i < 10; i ++) ++ for (i = 1; i < 3; i ++) + { + double peaktmp, harmonic; + int i1,i2; + +- harmonic = (double)i * 0.5; ++ harmonic = (double)pow(2.0, i); + peakpos = (int)(highPeak / harmonic + 0.5f); + if (peakpos < minPos) break; + peakpos = findTop(data, peakpos); // seek true local maximum index +@@ -265,7 +256,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) + + // accept harmonic peak if + // (a) it is found +- // (b) is within �4% of the expected harmonic interval ++ // (b) is within �4% of the expected harmonic interval + // (c) has at least half x-corr value of the max. peak + + double diff = harmonic * peaktmp / highPeak; +diff --git a/Externals/soundtouch/PeakFinder.h b/Externals/soundtouch/PeakFinder.h +index 594f230882..9fe66adac5 100644 +--- a/Externals/soundtouch/PeakFinder.h ++++ b/Externals/soundtouch/PeakFinder.h +@@ -9,13 +9,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2011-12-30 22:33:46 +0200 (Fri, 30 Dec 2011) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: PeakFinder.h 132 2011-12-30 20:33:46Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -51,8 +44,8 @@ protected: + + /// Calculates the mass center between given vector items. + double calcMassCenter(const float *data, ///< Data vector. +- int firstPos, ///< Index of first vector item beloging to the peak. +- int lastPos ///< Index of last vector item beloging to the peak. ++ int firstPos, ///< Index of first vector item belonging to the peak. ++ int lastPos ///< Index of last vector item belonging to the peak. + ) const; + + /// Finds the data vector index where the monotoniously decreasing signal crosses the +diff --git a/Externals/soundtouch/RateTransposer.cpp b/Externals/soundtouch/RateTransposer.cpp +index 95b9437a24..2efaf0424d 100644 +--- a/Externals/soundtouch/RateTransposer.cpp ++++ b/Externals/soundtouch/RateTransposer.cpp +@@ -10,13 +10,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: RateTransposer.cpp 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -57,7 +50,13 @@ TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC; + // Constructor + RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) + { +- bUseAAFilter = true; ++ bUseAAFilter = ++#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER ++ true; ++#else ++ // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover ++ false; ++#endif + + // Instantiates the anti-alias filter + pAAFilter = new AAFilter(64); +@@ -65,7 +64,6 @@ RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) + } + + +- + RateTransposer::~RateTransposer() + { + delete pAAFilter; +@@ -73,11 +71,13 @@ RateTransposer::~RateTransposer() + } + + +- + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void RateTransposer::enableAAFilter(bool newMode) + { ++#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER ++ // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover + bUseAAFilter = newMode; ++#endif + } + + +@@ -94,7 +94,6 @@ AAFilter *RateTransposer::getAAFilter() + } + + +- + // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower + // iRate, larger faster iRates. + void RateTransposer::setRate(double newRate) +@@ -177,11 +176,10 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) + // Sets the number of channels, 1 = mono, 2 = stereo + void RateTransposer::setChannels(int nChannels) + { +- assert(nChannels > 0); ++ if (!verifyNumberOfChannels(nChannels) || ++ (pTransposer->numChannels == nChannels)) return; + +- if (pTransposer->numChannels == nChannels) return; + pTransposer->setChannels(nChannels); +- + inputBuffer.setChannels(nChannels); + midBuffer.setChannels(nChannels); + outputBuffer.setChannels(nChannels); +@@ -208,6 +206,13 @@ int RateTransposer::isEmpty() const + } + + ++/// Return approximate initial input-output latency ++int RateTransposer::getLatency() const ++{ ++ return (bUseAAFilter) ? pAAFilter->getLength() : 0; ++} ++ ++ + ////////////////////////////////////////////////////////////////////////////// + // + // TransposerBase - Base class for interpolation +@@ -280,7 +285,7 @@ void TransposerBase::setRate(double newRate) + TransposerBase *TransposerBase::newInstance() + { + #ifdef SOUNDTOUCH_INTEGER_SAMPLES +- // Notice: For integer arithmetics support only linear algorithm (due to simplest calculus) ++ // Notice: For integer arithmetic support only linear algorithm (due to simplest calculus) + return ::new InterpolateLinearInteger; + #else + switch (algorithm) +diff --git a/Externals/soundtouch/RateTransposer.h b/Externals/soundtouch/RateTransposer.h +index e9cedfac9c..52b7441b89 100644 +--- a/Externals/soundtouch/RateTransposer.h ++++ b/Externals/soundtouch/RateTransposer.h +@@ -14,13 +14,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: RateTransposer.h 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -132,21 +125,9 @@ public: + RateTransposer(); + virtual ~RateTransposer(); + +- /// Operator 'new' is overloaded so that it automatically creates a suitable instance +- /// depending on if we're to use integer or floating point arithmetics. +-// static void *operator new(size_t s); +- +- /// Use this function instead of "new" operator to create a new instance of this class. +- /// This function automatically chooses a correct implementation, depending on if +- /// integer ot floating point arithmetics are to be used. +-// static RateTransposer *newInstance(); +- + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + +- /// Returns the store buffer object +-// FIFOSamplePipe *getStore() { return &storeBuffer; }; +- + /// Return anti-alias filter object + AAFilter *getAAFilter(); + +@@ -172,6 +153,9 @@ public: + + /// Returns nonzero if there aren't any samples available for outputting. + int isEmpty() const; ++ ++ /// Return approximate initial input-output latency ++ int getLatency() const; + }; + + } +diff --git a/Externals/soundtouch/STTypes.h b/Externals/soundtouch/STTypes.h +index a07bc3dcea..862505e769 100644 +--- a/Externals/soundtouch/STTypes.h ++++ b/Externals/soundtouch/STTypes.h +@@ -8,13 +8,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-05-18 18:25:07 +0300 (Mon, 18 May 2015) $ +-// File revision : $Revision: 3 $ +-// +-// $Id: STTypes.h 215 2015-05-18 15:25:07Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -57,16 +50,19 @@ typedef unsigned long ulong; + #if (defined(__GNUC__) && !defined(ANDROID)) + // In GCC, include soundtouch_config.h made by config scritps. + // Skip this in Android compilation that uses GCC but without configure scripts. +- //#include "soundtouch_config.h" ++ #include "soundtouch_config.h" + #endif + + + namespace soundtouch + { ++ /// Max allowed number of channels ++ #define SOUNDTOUCH_MAX_CHANNELS 16 ++ + /// Activate these undef's to overrule the possible sampletype + /// setting inherited from some other header file: +- #undef SOUNDTOUCH_INTEGER_SAMPLES +- #undef SOUNDTOUCH_FLOAT_SAMPLES ++ //#undef SOUNDTOUCH_INTEGER_SAMPLES ++ //#undef SOUNDTOUCH_FLOAT_SAMPLES + + /// If following flag is defined, always uses multichannel processing + /// routines also for mono and stero sound. This is for routine testing +@@ -75,7 +71,7 @@ namespace soundtouch + /// runtime performance so recommendation is to keep this off. + // #define USE_MULTICH_ALWAYS + +- #if (defined(__SOFTFP__)) ++ #if (defined(__SOFTFP__) && defined(ANDROID)) + // For Android compilation: Force use of Integer samples in case that + // compilation uses soft-floating point emulation - soft-fp is way too slow + #undef SOUNDTOUCH_FLOAT_SAMPLES +@@ -98,8 +94,8 @@ namespace soundtouch + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. +- #define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples +- //#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples ++ //#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples ++ #define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + +@@ -110,7 +106,7 @@ namespace soundtouch + /// routines compiled for whatever reason, you may disable these optimizations + /// to make the library compile. + +- //#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 ++ #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 + + /// In GNU environment, allow the user to override this setting by + /// giving the following switch to the configure script: +@@ -143,8 +139,10 @@ namespace soundtouch + #endif // SOUNDTOUCH_FLOAT_SAMPLES + + #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS +- // Allow MMX optimizations +- #define SOUNDTOUCH_ALLOW_MMX 1 ++ // Allow MMX optimizations (not available in X64 mode) ++ #if (!_M_X64) ++ #define SOUNDTOUCH_ALLOW_MMX 1 ++ #endif + #endif + + #else +@@ -164,7 +162,7 @@ namespace soundtouch + }; + + // define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: +- #define ST_NO_EXCEPTION_HANDLING 1 ++// #define ST_NO_EXCEPTION_HANDLING 1 + #ifdef ST_NO_EXCEPTION_HANDLING + // Exceptions disabled. Throw asserts instead if enabled. + #include +diff --git a/Externals/soundtouch/SoundTouch.cpp b/Externals/soundtouch/SoundTouch.cpp +index edccce238d..1618884cf5 100644 +--- a/Externals/soundtouch/SoundTouch.cpp ++++ b/Externals/soundtouch/SoundTouch.cpp +@@ -41,13 +41,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: SoundTouch.cpp 225 2015-07-26 14:45:48Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -110,15 +103,14 @@ SoundTouch::SoundTouch() + + calcEffectiveRateAndTempo(); + +- samplesExpectedOut = 0; +- samplesOutput = 0; ++ samplesExpectedOut = 0; ++ samplesOutput = 0; + + channels = 0; + bSrateSet = false; + } + + +- + SoundTouch::~SoundTouch() + { + delete pRateTransposer; +@@ -126,7 +118,6 @@ SoundTouch::~SoundTouch() + } + + +- + /// Get SoundTouch library version string + const char *SoundTouch::getVersionString() + { +@@ -146,18 +137,14 @@ uint SoundTouch::getVersionId() + // Sets the number of channels, 1 = mono, 2 = stereo + void SoundTouch::setChannels(uint numChannels) + { +- /*if (numChannels != 1 && numChannels != 2) +- { +- //ST_THROW_RT_ERROR("Illegal number of channels"); +- return; +- }*/ ++ if (!verifyNumberOfChannels(numChannels)) return; ++ + channels = numChannels; + pRateTransposer->setChannels((int)numChannels); + pTDStretch->setChannels((int)numChannels); + } + + +- + // Sets new rate control value. Normal rate = 1.0, smaller values + // represent slower rate, larger faster rates. + void SoundTouch::setRate(double newRate) +@@ -167,7 +154,6 @@ void SoundTouch::setRate(double newRate) + } + + +- + // Sets new rate control value as a difference in percents compared + // to the original rate (-50 .. +100 %) + void SoundTouch::setRateChange(double newRate) +@@ -177,7 +163,6 @@ void SoundTouch::setRateChange(double newRate) + } + + +- + // Sets new tempo control value. Normal tempo = 1.0, smaller values + // represent slower tempo, larger faster tempo. + void SoundTouch::setTempo(double newTempo) +@@ -187,7 +172,6 @@ void SoundTouch::setTempo(double newTempo) + } + + +- + // Sets new tempo control value as a difference in percents compared + // to the original tempo (-50 .. +100 %) + void SoundTouch::setTempoChange(double newTempo) +@@ -197,7 +181,6 @@ void SoundTouch::setTempoChange(double newTempo) + } + + +- + // Sets new pitch control value. Original pitch = 1.0, smaller values + // represent lower pitches, larger values higher pitch. + void SoundTouch::setPitch(double newPitch) +@@ -207,7 +190,6 @@ void SoundTouch::setPitch(double newPitch) + } + + +- + // Sets pitch change in octaves compared to the original pitch + // (-1.00 .. +1.00) + void SoundTouch::setPitchOctaves(double newPitch) +@@ -217,7 +199,6 @@ void SoundTouch::setPitchOctaves(double newPitch) + } + + +- + // Sets pitch change in semi-tones compared to the original pitch + // (-12 .. +12) + void SoundTouch::setPitchSemiTones(int newPitch) +@@ -226,7 +207,6 @@ void SoundTouch::setPitchSemiTones(int newPitch) + } + + +- + void SoundTouch::setPitchSemiTones(double newPitch) + { + setPitchOctaves(newPitch / 12.0); +@@ -240,11 +220,11 @@ void SoundTouch::calcEffectiveRateAndTempo() + double oldTempo = tempo; + double oldRate = rate; + +- tempo = virtualTempo / virtualPitch; +- rate = virtualPitch * virtualRate; ++ tempo = virtualTempo / virtualPitch; ++ rate = virtualPitch * virtualRate; + + 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 + if (rate <= 1.0f) +@@ -286,9 +266,9 @@ void SoundTouch::calcEffectiveRateAndTempo() + // Sets sample rate. + void SoundTouch::setSampleRate(uint srate) + { +- bSrateSet = true; + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters((int)srate); ++ bSrateSet = true; + } + + +@@ -305,25 +285,9 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) + ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined"); + } + +- // Transpose the rate of the new samples if necessary +- /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... +- if (rate == 1.0f) +- { +- // The rate value is same as the original, simply evaluate the tempo changer. +- assert(output == pTDStretch); +- if (pRateTransposer->isEmpty() == 0) +- { +- // yet flush the last samples in the pitch transposer buffer +- // (may happen if 'rate' changes from a non-zero value to zero) +- pTDStretch->moveSamples(*pRateTransposer); +- } +- pTDStretch->putSamples(samples, nSamples); +- } +- */ +- +- // accumulate how many samples are expected out from processing, given the current +- // processing setting +- samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo); ++ // accumulate how many samples are expected out from processing, given the current ++ // processing setting ++ samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo); + + #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + if (rate <= 1.0f) +@@ -354,28 +318,28 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) + void SoundTouch::flush() + { + int i; +- int numStillExpected; ++ int numStillExpected; + SAMPLETYPE *buff = new SAMPLETYPE[128 * channels]; + +- // how many samples are still expected to output +- numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput); ++ // how many samples are still expected to output ++ numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput); ++ if (numStillExpected < 0) numStillExpected = 0; + + memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 24ksamples in any case) +- for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++) +- { +- putSamples(buff, 128); +- } ++ for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++) ++ { ++ putSamples(buff, 128); ++ } + +- adjustAmountOfSamples(numStillExpected); ++ adjustAmountOfSamples(numStillExpected); + + delete[] buff; + + // Clear input buffers +- // pRateTransposer->clearInput(); + pTDStretch->clearInput(); + // yet leave the output intouched as that's where the + // flushed samples are! +@@ -446,7 +410,7 @@ int SoundTouch::getSetting(int settingId) const + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : +- return (uint) pTDStretch->isQuickSeekEnabled(); ++ return (uint)pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); +@@ -460,13 +424,53 @@ int SoundTouch::getSetting(int settingId) const + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + +- case SETTING_NOMINAL_INPUT_SEQUENCE : +- return pTDStretch->getInputSampleReq(); ++ case SETTING_NOMINAL_INPUT_SEQUENCE : ++ { ++ int size = pTDStretch->getInputSampleReq(); ++ ++#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER ++ if (rate <= 1.0) ++ { ++ // transposing done before timestretch, which impacts latency ++ return (int)(size * rate + 0.5); ++ } ++#endif ++ return size; ++ } ++ ++ case SETTING_NOMINAL_OUTPUT_SEQUENCE : ++ { ++ int size = pTDStretch->getOutputBatchSize(); ++ ++ if (rate > 1.0) ++ { ++ // transposing done after timestretch, which impacts latency ++ return (int)(size / rate + 0.5); ++ } ++ return size; ++ } ++ ++ case SETTING_INITIAL_LATENCY: ++ { ++ double latency = pTDStretch->getLatency(); ++ int latency_tr = pRateTransposer->getLatency(); ++ ++#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER ++ if (rate <= 1.0) ++ { ++ // transposing done before timestretch, which impacts latency ++ latency = (latency + latency_tr) * rate; ++ } ++ else ++#endif ++ { ++ latency += (double)latency_tr / rate; ++ } + +- case SETTING_NOMINAL_OUTPUT_SEQUENCE : +- return pTDStretch->getOutputBatchSize(); ++ return (int)(latency + 0.5); ++ } + +- default : ++ default : + return 0; + } + } +@@ -476,13 +480,13 @@ int SoundTouch::getSetting(int settingId) const + // buffers. + void SoundTouch::clear() + { +- samplesExpectedOut = 0; ++ samplesExpectedOut = 0; ++ samplesOutput = 0; + pRateTransposer->clear(); + pTDStretch->clear(); + } + + +- + /// Returns number of samples currently unprocessed. + uint SoundTouch::numUnprocessedSamples() const + { +@@ -499,7 +503,6 @@ uint SoundTouch::numUnprocessedSamples() const + } + + +- + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. +@@ -507,9 +510,9 @@ uint SoundTouch::numUnprocessedSamples() const + /// \return Number of samples returned. + uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples) + { +- uint ret = FIFOProcessor::receiveSamples(output, maxSamples); +- samplesOutput += (long)ret; +- return ret; ++ uint ret = FIFOProcessor::receiveSamples(output, maxSamples); ++ samplesOutput += (long)ret; ++ return ret; + } + + +@@ -520,7 +523,16 @@ uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples) + /// with 'ptrBegin' function. + uint SoundTouch::receiveSamples(uint maxSamples) + { +- uint ret = FIFOProcessor::receiveSamples(maxSamples); +- samplesOutput += (long)ret; +- return ret; ++ uint ret = FIFOProcessor::receiveSamples(maxSamples); ++ samplesOutput += (long)ret; ++ return ret; ++} ++ ++ ++/// Get ratio between input and output audio durations, useful for calculating ++/// processed output duration: if you'll process a stream of N samples, then ++/// you can expect to get out N * getInputOutputSampleRatio() samples. ++double SoundTouch::getInputOutputSampleRatio() ++{ ++ return 1.0 / (tempo * rate); + } +diff --git a/Externals/soundtouch/SoundTouch.h b/Externals/soundtouch/SoundTouch.h +index 24e8716e04..e963ddfde8 100644 +--- a/Externals/soundtouch/SoundTouch.h ++++ b/Externals/soundtouch/SoundTouch.h +@@ -41,13 +41,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-09-20 10:38:32 +0300 (Sun, 20 Sep 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: SoundTouch.h 230 2015-09-20 07:38:32Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -79,10 +72,10 @@ namespace soundtouch + { + + /// Soundtouch library version string +-#define SOUNDTOUCH_VERSION "1.9.2" ++#define SOUNDTOUCH_VERSION "2.1.3" + + /// SoundTouch library version id +-#define SOUNDTOUCH_VERSION_ID (10902) ++#define SOUNDTOUCH_VERSION_ID (20103) + + // + // Available setting IDs for the 'setSetting' & 'get_setting' functions: +@@ -116,30 +109,61 @@ namespace soundtouch + #define SETTING_OVERLAP_MS 5 + + +-/// Call "getSetting" with this ID to query nominal average processing sequence +-/// size in samples. This value tells approcimate value how many input samples +-/// SoundTouch needs to gather before it does DSP processing run for the sample batch. ++/// Call "getSetting" with this ID to query processing sequence size in samples. ++/// This value gives approximate value of how many input samples you'll need to ++/// feed into SoundTouch after initial buffering to get out a new batch of ++/// output samples. ++/// ++/// This value does not include initial buffering at beginning of a new processing ++/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size. + /// + /// Notices: + /// - This is read-only parameter, i.e. setSetting ignores this parameter +-/// - Returned value is approximate average value, exact processing batch +-/// size may wary from time to time +-/// - This parameter value is not constant but may change depending on ++/// - This parameter value is not constant but change depending on + /// tempo/pitch/rate/samplerate settings. +-#define SETTING_NOMINAL_INPUT_SEQUENCE 6 ++#define SETTING_NOMINAL_INPUT_SEQUENCE 6 + + + /// Call "getSetting" with this ID to query nominal average processing output + /// size in samples. This value tells approcimate value how many output samples + /// SoundTouch outputs once it does DSP processing run for a batch of input samples. +-/// ++/// + /// Notices: + /// - This is read-only parameter, i.e. setSetting ignores this parameter +-/// - Returned value is approximate average value, exact processing batch +-/// size may wary from time to time +-/// - This parameter value is not constant but may change depending on ++/// - This parameter value is not constant but change depending on + /// tempo/pitch/rate/samplerate settings. +-#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 ++#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 ++ ++ ++/// Call "getSetting" with this ID to query initial processing latency, i.e. ++/// approx. how many samples you'll need to enter to SoundTouch pipeline before ++/// you can expect to get first batch of ready output samples out. ++/// ++/// After the first output batch, you can then expect to get approx. ++/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every ++/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch. ++/// ++/// Example: ++/// processing with parameter -tempo=5 ++/// => initial latency = 5509 samples ++/// input sequence = 4167 samples ++/// output sequence = 3969 samples ++/// ++/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of ++/// the stream, and then you'll get out the first 3969 samples. After that, for ++/// every approx. 4167 samples that you'll put in, you'll receive again approx. ++/// 3969 samples out. ++/// ++/// This also means that average latency during stream processing is ++/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2 ++/// = 3524 samples ++/// ++/// Notices: ++/// - This is read-only parameter, i.e. setSetting ignores this parameter ++/// - This parameter value is not constant but change depending on ++/// tempo/pitch/rate/samplerate settings. ++#define SETTING_INITIAL_LATENCY 8 ++ + + class SoundTouch : public FIFOProcessor + { +@@ -228,6 +252,24 @@ public: + /// Sets sample rate. + void setSampleRate(uint srate); + ++ /// Get ratio between input and output audio durations, useful for calculating ++ /// processed output duration: if you'll process a stream of N samples, then ++ /// you can expect to get out N * getInputOutputSampleRatio() samples. ++ /// ++ /// This ratio will give accurate target duration ratio for a full audio track, ++ /// given that the the whole track is processed with same processing parameters. ++ /// ++ /// If this ratio is applied to calculate intermediate offsets inside a processing ++ /// stream, then this ratio is approximate and can deviate +- some tens of milliseconds ++ /// from ideal offset, yet by end of the audio stream the duration ratio will become ++ /// exact. ++ /// ++ /// Example: if processing with parameters "-tempo=15 -pitch=-3", the function ++ /// will return value 0.8695652... Now, if processing an audio stream whose duration ++ /// is exactly one million audio samples, then you can expect the processed ++ /// output duration be 0.869565 * 1000000 = 869565 samples. ++ double getInputOutputSampleRatio(); ++ + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // +@@ -271,7 +313,7 @@ public: + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// +- /// \return 'true' if the setting was succesfully changed ++ /// \return 'true' if the setting was successfully changed + bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. + int value ///< New setting value. + ); +@@ -286,6 +328,11 @@ public: + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + ++ /// Return number of channels ++ uint numChannels() const ++ { ++ return channels; ++ } + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') +diff --git a/Externals/soundtouch/SoundTouch.vcxproj b/Externals/soundtouch/SoundTouch.vcxproj +index bc99698372..32d23def4e 100644 +--- a/Externals/soundtouch/SoundTouch.vcxproj ++++ b/Externals/soundtouch/SoundTouch.vcxproj +@@ -1,84 +1,342 @@ +- +- +- +- +- Debug +- ARM64 +- +- +- Debug +- x64 +- +- +- Release +- ARM64 +- +- +- Release +- x64 +- +- +- +- {EC082900-B4D8-42E9-9663-77F02F6936AE} +- 10.0 +- +- +- +- StaticLibrary +- v142 +- Unicode +- +- +- true +- +- +- false +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ++ ++ Debug ++ Win32 ++ ++ ++ Debug ++ x64 ++ ++ ++ Release ++ Win32 ++ ++ ++ Release ++ x64 ++ ++ ++ ++ {68A5DD20-7057-448B-8FE0-B6AC8D205509} ++ 10.0 ++ ++ ++ ++ StaticLibrary ++ v142 ++ false ++ MultiByte ++ ++ ++ StaticLibrary ++ v142 ++ false ++ MultiByte ++ ++ ++ StaticLibrary ++ v142 ++ false ++ MultiByte ++ ++ ++ StaticLibrary ++ v142 ++ false ++ MultiByte ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ <_ProjectFileVersion>14.0.23107.0 ++ ++ ++ $(Platform)\$(Configuration)\ ++ $(Platform)\$(Configuration)\ ++ ++ ++ $(Platform)\$(Configuration)\ ++ $(Platform)\$(Configuration)\ ++ $(ProjectName)_x64 ++ ++ ++ $(Platform)\$(Configuration)\ ++ $(Platform)\$(Configuration)\ ++ $(ProjectName)D ++ ++ ++ $(Platform)\$(Configuration)\ ++ $(Platform)\$(Configuration)\ ++ $(ProjectName)D_x64 ++ ++ ++ ++ Full ++ AnySuitable ++ true ++ ..\..\include;%(AdditionalIncludeDirectories) ++ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ++ true ++ MultiThreaded ++ true ++ Fast ++ ++ $(OutDir)$(TargetName).pch ++ $(OutDir) ++ $(OutDir) ++ $(OutDir) ++ Level3 ++ true ++ ++ Default ++ StreamingSIMDExtensions2 ++ $(IntDir) ++ $(IntDir) ++ true ++ ++ ++ NDEBUG;%(PreprocessorDefinitions) ++ 0x040b ++ ++ ++ $(OutDir)$(TargetName)$(TargetExt) ++ true ++ ++ ++ if not exist ..\..\lib mkdir ..\..\lib ++copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib ++ ++ ++ ++ ++ X64 ++ ++ ++ Full ++ AnySuitable ++ true ++ ..\..\include;%(AdditionalIncludeDirectories) ++ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ++ true ++ MultiThreaded ++ true ++ Fast ++ ++ $(OutDir)$(TargetName).pch ++ $(OutDir) ++ $(OutDir) ++ $(OutDir) ++ Level3 ++ true ++ ++ Default ++ ++ ++ $(IntDir) ++ $(IntDir) ++ true ++ ++ ++ NDEBUG;%(PreprocessorDefinitions) ++ 0x040b ++ ++ ++ $(OutDir)$(TargetName)$(TargetExt) ++ true ++ ++ ++ if not exist ..\..\lib mkdir ..\..\lib ++copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib ++ ++ ++ ++ ++ Disabled ++ ..\..\include;%(AdditionalIncludeDirectories) ++ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) ++ EnableFastChecks ++ MultiThreadedDebug ++ Fast ++ ++ $(OutDir)$(TargetName).pch ++ $(OutDir) ++ $(OutDir) ++ $(OutDir) ++ true ++ Level3 ++ true ++ EditAndContinue ++ Default ++ StreamingSIMDExtensions2 ++ $(IntDir) ++ $(IntDir) ++ true ++ ++ ++ _DEBUG;%(PreprocessorDefinitions) ++ 0x040b ++ ++ ++ $(OutDir)$(TargetName)$(TargetExt) ++ true ++ ++ ++ if not exist ..\..\lib mkdir ..\..\lib ++copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib ++ ++ ++ ++ ++ X64 ++ ++ ++ Disabled ++ ..\..\include;%(AdditionalIncludeDirectories) ++ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) ++ EnableFastChecks ++ MultiThreadedDebug ++ Fast ++ ++ $(OutDir)$(TargetName).pch ++ $(OutDir) ++ $(OutDir) ++ $(OutDir) ++ true ++ Level3 ++ true ++ ProgramDatabase ++ Default ++ ++ ++ $(IntDir) ++ $(IntDir) ++ true ++ ++ ++ _DEBUG;%(PreprocessorDefinitions) ++ 0x040b ++ ++ ++ $(OutDir)$(TargetName)$(TargetExt) ++ true ++ ++ ++ if not exist ..\..\lib mkdir ..\..\lib ++copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib ++ ++ ++ ++ ++ Disabled ++ EnableFastChecks ++ true ++ Disabled ++ EnableFastChecks ++ true ++ MaxSpeed ++ MaxSpeed ++ ++ ++ 4996 ++ 4996 ++ 4996 ++ 4996 ++ ++ ++ ++ Disabled ++ EnableFastChecks ++ true ++ Disabled ++ EnableFastChecks ++ true ++ MaxSpeed ++ MaxSpeed ++ ++ ++ Disabled ++ EnableFastChecks ++ true ++ Disabled ++ EnableFastChecks ++ true ++ MaxSpeed ++ MaxSpeed ++ ++ ++ ++ ++ ++ ++ ++ Disabled ++ EnableFastChecks ++ true ++ Disabled ++ EnableFastChecks ++ true ++ MaxSpeed ++ MaxSpeed ++ ++ ++ Disabled ++ EnableFastChecks ++ true ++ Disabled ++ EnableFastChecks ++ true ++ MaxSpeed ++ MaxSpeed ++ ++ ++ ++ Disabled ++ EnableFastChecks ++ true ++ Disabled ++ EnableFastChecks ++ true ++ MaxSpeed ++ MaxSpeed ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +\ No newline at end of file +diff --git a/Externals/soundtouch/TDStretch.cpp b/Externals/soundtouch/TDStretch.cpp +index bb473a9f63..ce49310900 100644 +--- a/Externals/soundtouch/TDStretch.cpp ++++ b/Externals/soundtouch/TDStretch.cpp +@@ -4,8 +4,14 @@ + /// while maintaining the original pitch by using a time domain WSOLA-like + /// method with several performance-increasing tweaks. + /// +-/// Note : MMX optimized functions reside in a separate, platform-specific +-/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' ++/// Notes : MMX optimized functions reside in a separate, platform-specific ++/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'. ++/// ++/// This source file contains OpenMP optimizations that allow speeding up the ++/// corss-correlation algorithm by executing it in several threads / CPU cores ++/// in parallel. See the following article link for more detailed discussion ++/// about SoundTouch OpenMP optimizations: ++/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices + /// + /// Author : Copyright (c) Olli Parviainen + /// Author e-mail : oparviai 'at' iki.fi +@@ -13,13 +19,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ +-// File revision : $Revision: 1.12 $ +-// +-// $Id: TDStretch.cpp 226 2015-08-08 21:00:15Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -128,8 +127,13 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS, + int aSeekWindowMS, int 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; ++ if (aSampleRate > 0) ++ { ++ if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate"); ++ this->sampleRate = aSampleRate; ++ } ++ ++ if (aOverlapMS > 0) this->overlapMs = aOverlapMS; + + if (aSequenceMS > 0) + { +@@ -219,6 +223,7 @@ void TDStretch::clearInput() + { + inputBuffer.clear(); + clearMidBuffer(); ++ isBeginning = true; + } + + +@@ -297,12 +302,13 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) + int i; + double norm; + +- bestCorr = FLT_MIN; ++ bestCorr = -FLT_MAX; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + bestCorr = calcCrossCorr(refPos, pMidBuffer, norm); ++ bestCorr = (bestCorr + 0.1) * 0.75; + + #pragma omp parallel for + for (i = 1; i < seekLength; i ++) +@@ -354,7 +360,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) + // with improved precision + // + // Based on testing: +-// - This algorithm gives on average 99% as good match as the full algorith ++// - This algorithm gives on average 99% as good match as the full algorithm + // - this quick seek algorithm finds the best match on ~90% of cases + // - on those 10% of cases when this algorithm doesn't find best match, + // it still finds on average ~90% match vs. the best possible match +@@ -373,12 +379,10 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) + + // note: 'float' types used in this function in case that the platform would need to use software-fp + +- bestCorr = FLT_MIN; +- bestOffs = SCANWIND; +- bestCorr2 = FLT_MIN; +- bestOffs2 = 0; +- +- int best = 0; ++ bestCorr = ++ bestCorr2 = -FLT_MAX; ++ bestOffs = ++ bestOffs2 = SCANWIND; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. Look for two best matches on the first pass to +@@ -436,7 +440,6 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) + { + bestCorr = corr; + bestOffs = i; +- best = 1; + } + } + +@@ -458,7 +461,6 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) + { + bestCorr = corr; + bestOffs = i; +- best = 2; + } + } + +@@ -515,18 +517,18 @@ void TDStretch::clearCrossCorrState() + 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 ++ // at various 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_AT_MIN 90.0 ++ #define AUTOSEQ_AT_MAX 40.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 tempoq +- #define AUTOSEEK_AT_MIN 25.0 ++ #define AUTOSEEK_AT_MIN 20.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)) +@@ -586,9 +588,8 @@ void TDStretch::setTempo(double newTempo) + // Sets the number of channels, 1 = mono, 2 = stereo + void TDStretch::setChannels(int numChannels) + { +- assert(numChannels > 0); +- if (channels == numChannels) return; +-// assert(numChannels == 1 || numChannels == 2); ++ if (!verifyNumberOfChannels(numChannels) || ++ (channels == numChannels)) return; + + channels = numChannels; + inputBuffer.setChannels(channels); +@@ -637,7 +638,8 @@ void TDStretch::processNominalTempo() + // the result into 'outputBuffer' + void TDStretch::processSamples() + { +- int ovlSkip, offset; ++ int ovlSkip; ++ int offset = 0; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting +@@ -654,35 +656,61 @@ void TDStretch::processSamples() + // to form a processing frame. + while ((int)inputBuffer.numSamples() >= sampleReq) + { +- // If tempo differs from the normal ('SCALE'), scan for the best overlapping +- // position +- offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); +- +- // Mix the samples in the 'inputBuffer' at position of 'offset' with the +- // samples in 'midBuffer' using sliding overlapping +- // ... first partially overlap with the end of the previous sequence +- // (that's in 'midBuffer') +- overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset); +- outputBuffer.putSamples((uint)overlapLength); ++ if (isBeginning == false) ++ { ++ // apart from the very beginning of the track, ++ // scan for the best overlapping position & do overlap-add ++ offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); ++ ++ // Mix the samples in the 'inputBuffer' at position of 'offset' with the ++ // samples in 'midBuffer' using sliding overlapping ++ // ... first partially overlap with the end of the previous sequence ++ // (that's in 'midBuffer') ++ overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset); ++ outputBuffer.putSamples((uint)overlapLength); ++ offset += overlapLength; ++ } ++ else ++ { ++ // Adjust processing offset at beginning of track by not perform initial overlapping ++ // and compensating that in the 'input buffer skip' calculation ++ isBeginning = false; ++ int skip = (int)(tempo * overlapLength + 0.5); ++ ++ #ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION ++ #ifdef SOUNDTOUCH_ALLOW_SSE ++ // if SSE mode, round the skip amount to value corresponding to aligned memory address ++ if (channels == 1) ++ { ++ skip &= -4; ++ } ++ else if (channels == 2) ++ { ++ skip &= -2; ++ } ++ #endif ++ #endif ++ skipFract -= skip; ++ assert(nominalSkip >= -skipFract); ++ } + + // ... then copy sequence samples from 'inputBuffer' to output: + +- // length of sequence +- temp = (seekWindowLength - 2 * overlapLength); +- + // crosscheck that we don't have buffer overflow... +- if ((int)inputBuffer.numSamples() < (offset + temp + overlapLength * 2)) ++ if ((int)inputBuffer.numSamples() < (offset + seekWindowLength - overlapLength)) + { + continue; // just in case, shouldn't really happen + } + +- outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), (uint)temp); ++ // length of sequence ++ temp = (seekWindowLength - 2 * overlapLength); ++ outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp); + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on +- assert((offset + temp + overlapLength * 2) <= (int)inputBuffer.numSamples()); +- memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp + overlapLength), ++ assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples()); ++ memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp), + channels * sizeof(SAMPLETYPE) * overlapLength); + + // Remove the processed samples from the input buffer. Update +@@ -776,7 +804,7 @@ TDStretch * TDStretch::newInstance() + + ////////////////////////////////////////////////////////////////////////////// + // +-// Integer arithmetics specific algorithm implementations. ++// Integer arithmetic specific algorithm implementations. + // + ////////////////////////////////////////////////////////////////////////////// + +@@ -879,7 +907,12 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do + + if (lnorm > maxnorm) + { +- maxnorm = lnorm; ++ // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode ++ #pragma omp critical ++ if (lnorm > maxnorm) ++ { ++ maxnorm = lnorm; ++ } + } + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation +@@ -936,7 +969,7 @@ double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *c + + ////////////////////////////////////////////////////////////////////////////// + // +-// Floating point arithmetics specific algorithm implementations. ++// Floating point arithmetic specific algorithm implementations. + // + + #ifdef SOUNDTOUCH_FLOAT_SAMPLES +diff --git a/Externals/soundtouch/TDStretch.h b/Externals/soundtouch/TDStretch.h +index 213304c982..4118f9f474 100644 +--- a/Externals/soundtouch/TDStretch.h ++++ b/Externals/soundtouch/TDStretch.h +@@ -13,13 +13,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: TDStretch.h 226 2015-08-08 21:00:15Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -134,6 +127,7 @@ protected: + bool bQuickSeek; + bool bAutoSeqSetting; + bool bAutoSeekSetting; ++ bool isBeginning; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pMidBufferUnaligned; +@@ -163,7 +157,6 @@ protected: + void calcSeqParameters(); + void adaptNormalizer(); + +- + /// 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 +@@ -247,8 +240,13 @@ public: + { + return seekWindowLength - overlapLength; + } +-}; + ++ /// return approximate initial input-output latency ++ int getLatency() const ++ { ++ return sampleReq; ++ } ++}; + + + // Implementation-specific class declarations: +diff --git a/Externals/soundtouch/cpu_detect.h b/Externals/soundtouch/cpu_detect.h +index 025781dae1..0cdc22356f 100644 +--- a/Externals/soundtouch/cpu_detect.h ++++ b/Externals/soundtouch/cpu_detect.h +@@ -12,13 +12,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +diff --git a/Externals/soundtouch/cpu_detect_x86.cpp b/Externals/soundtouch/cpu_detect_x86.cpp +index 5ef0246216..b1286106eb 100644 +--- a/Externals/soundtouch/cpu_detect_x86.cpp ++++ b/Externals/soundtouch/cpu_detect_x86.cpp +@@ -11,13 +11,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2014-01-07 20:24:28 +0200 (Tue, 07 Jan 2014) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -75,7 +68,6 @@ void disableExtensions(uint dwDisableMask) + } + + +- + /// Checks which instruction set extensions are supported by the CPU. + uint detectCPUextensions(void) + { +diff --git a/Externals/soundtouch/mmx_optimized.cpp b/Externals/soundtouch/mmx_optimized.cpp +index 8ad2811b9a..741ba4f22e 100644 +--- a/Externals/soundtouch/mmx_optimized.cpp ++++ b/Externals/soundtouch/mmx_optimized.cpp +@@ -20,13 +20,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: mmx_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +@@ -125,7 +118,12 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &d + + if (norm > (long)maxnorm) + { +- maxnorm = norm; ++ // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode ++ #pragma omp critical ++ if (norm > (long)maxnorm) ++ { ++ maxnorm = norm; ++ } + } + + // Normalize result by dividing by sqrt(norm) - this step is easiest +@@ -219,7 +217,6 @@ void TDStretchMMX::clearCrossCorrState() + } + + +- + // MMX-optimized version of the function overlapStereo + void TDStretchMMX::overlapStereo(short *output, const short *input) const + { +@@ -335,7 +332,6 @@ void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uRe + } + + +- + // mmx-optimized version of the filter routine for stereo sound + uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const + { +@@ -392,4 +388,9 @@ uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numS + return (numSamples & 0xfffffffe) - length; + } + ++#else ++ ++// workaround to not complain about empty module ++bool _dontcomplain_mmx_empty; ++ + #endif // SOUNDTOUCH_ALLOW_MMX +diff --git a/Externals/soundtouch/soundtouch_config.h b/Externals/soundtouch/soundtouch_config.h +new file mode 100644 +index 0000000000..950e3353e2 +--- /dev/null ++++ b/Externals/soundtouch/soundtouch_config.h +@@ -0,0 +1,2 @@ ++#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples ++//#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples +diff --git a/Externals/soundtouch/sse_optimized.cpp b/Externals/soundtouch/sse_optimized.cpp +index 490d0d2080..0dc637015f 100644 +--- a/Externals/soundtouch/sse_optimized.cpp ++++ b/Externals/soundtouch/sse_optimized.cpp +@@ -23,13 +23,6 @@ + /// + //////////////////////////////////////////////////////////////////////////////// + // +-// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ +-// File revision : $Revision: 4 $ +-// +-// $Id: sse_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $ +-// +-//////////////////////////////////////////////////////////////////////////////// +-// + // License : + // + // SoundTouch audio processing library +-- +2.21.1 + diff --git a/0002-soundtouch-Use-shorts-instead-of-floats-for-samples.patch b/0002-soundtouch-Use-shorts-instead-of-floats-for-samples.patch new file mode 100644 index 0000000..b9fa0c1 --- /dev/null +++ b/0002-soundtouch-Use-shorts-instead-of-floats-for-samples.patch @@ -0,0 +1,37 @@ +From 754697d56ec7df1930bbacaf5832b883bfa5a1db Mon Sep 17 00:00:00 2001 +From: Mystro256 +Date: Sun, 5 Apr 2020 11:03:31 -0400 +Subject: [PATCH 2/3] soundtouch: Use shorts instead of floats for samples + +This reapplies commit 8ff26a6 after the soundtouch 2.1.2 update. +--- + Externals/soundtouch/STTypes.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Externals/soundtouch/STTypes.h b/Externals/soundtouch/STTypes.h +index 862505e769..0f98c889fb 100644 +--- a/Externals/soundtouch/STTypes.h ++++ b/Externals/soundtouch/STTypes.h +@@ -94,8 +94,8 @@ namespace soundtouch + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. +- //#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples +- #define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples ++ #define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples ++ //#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + +@@ -106,7 +106,7 @@ namespace soundtouch + /// routines compiled for whatever reason, you may disable these optimizations + /// to make the library compile. + +- #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 ++ //#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 + + /// In GNU environment, allow the user to override this setting by + /// giving the following switch to the configure script: +-- +2.21.1 + diff --git a/0003-soundtounch-disable-exceptions.patch b/0003-soundtounch-disable-exceptions.patch new file mode 100644 index 0000000..903dc61 --- /dev/null +++ b/0003-soundtounch-disable-exceptions.patch @@ -0,0 +1,25 @@ +From 5afd3c046dfea7662394d6ac7994a964455d55ff Mon Sep 17 00:00:00 2001 +From: Mystro256 +Date: Sun, 5 Apr 2020 17:46:52 -0400 +Subject: [PATCH 3/3] soundtounch: disable exceptions + +--- + Externals/soundtouch/STTypes.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Externals/soundtouch/STTypes.h b/Externals/soundtouch/STTypes.h +index 0f98c889fb..d5440c3b74 100644 +--- a/Externals/soundtouch/STTypes.h ++++ b/Externals/soundtouch/STTypes.h +@@ -162,7 +162,7 @@ namespace soundtouch + }; + + // define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: +-// #define ST_NO_EXCEPTION_HANDLING 1 ++#define ST_NO_EXCEPTION_HANDLING 1 + #ifdef ST_NO_EXCEPTION_HANDLING + // Exceptions disabled. Throw asserts instead if enabled. + #include +-- +2.21.1 + diff --git a/dolphin-emu.spec b/dolphin-emu.spec index 98a5f1b..f9b14dd 100644 --- a/dolphin-emu.spec +++ b/dolphin-emu.spec @@ -11,7 +11,7 @@ Name: dolphin-emu Version: 5.0.%{snapnumber} -Release: 3%{?dist} +Release: 4%{?dist} Summary: GameCube / Wii / Triforce Emulator Url: https://dolphin-emu.org/ @@ -36,6 +36,11 @@ Patch0: 0001-Allow-using-shared-minizip.patch Patch1: 0002-Allow-using-shared-fmt.patch #Not upstream-able for now: Patch2: 0001-Use-system-headers-for-Vulkan.patch +#Update soundtouch: +#https://github.com/dolphin-emu/dolphin/pull/8725 +Patch3: 0001-soundtounch-update-to-2.1.2.patch +Patch4: 0002-soundtouch-Use-shorts-instead-of-floats-for-samples.patch +Patch5: 0003-soundtounch-disable-exceptions.patch ##Bundled code ahoy #The following isn't in Fedora yet: @@ -44,7 +49,7 @@ Provides: bundled(cubeb) Provides: bundled(imgui) = 1.70 Provides: bundled(cpp-argparse) #soundtouch cannot be unbundled easily, as it requires compile time changes: -Provides: bundled(soundtouch) = 1.9.2 +Provides: bundled(soundtouch) = 2.1.2 BuildRequires: gcc BuildRequires: gcc-c++ @@ -214,6 +219,9 @@ appstream-util validate-relax --nonet \ %{_udevrulesdir}/51-dolphin-usb-device.rules %changelog +* Sun Apr 05 2020 Jeremy Newton - 5.0.11617-4 +- Update bundled soundtouch to 2.1.2 + * Wed Mar 18 2020 Jeremy Newton - 5.0.11617-3 - Unbundle glslang