From 28f64f98f7f158afca1a4bd9b4d81466e25b5de9 Mon Sep 17 00:00:00 2001 From: Dragios Date: Sat, 16 Apr 2016 01:32:48 +0800 Subject: [PATCH] Revert "Audio Core (#2)" This reverts commit a8d0c51c695693cd39aea611c7b163022147fd57. --- .gitmodules | 3 - CMakeLists.txt | 7 +- externals/boost | 2 +- externals/rubberband/CMakeLists.txt | 79 -- externals/rubberband/rubberband | 1 - externals/soundtouch/AAFilter.cpp | 236 ---- externals/soundtouch/AAFilter.h | 100 -- externals/soundtouch/BPMDetect.cpp | 371 ------ externals/soundtouch/BPMDetect.h | 164 --- externals/soundtouch/CMakeLists.txt | 18 - externals/soundtouch/FIFOSampleBuffer.cpp | 274 ----- externals/soundtouch/FIFOSampleBuffer.h | 184 --- externals/soundtouch/FIFOSamplePipe.h | 234 ---- externals/soundtouch/FIRFilter.cpp | 328 ----- externals/soundtouch/FIRFilter.h | 146 --- externals/soundtouch/InterpolateCubic.cpp | 200 --- externals/soundtouch/InterpolateCubic.h | 67 - externals/soundtouch/InterpolateLinear.cpp | 300 ----- externals/soundtouch/InterpolateLinear.h | 92 -- externals/soundtouch/InterpolateShannon.cpp | 185 --- externals/soundtouch/InterpolateShannon.h | 72 -- externals/soundtouch/PeakFinder.cpp | 286 ----- externals/soundtouch/PeakFinder.h | 97 -- externals/soundtouch/RateTransposer.cpp | 302 ----- externals/soundtouch/RateTransposer.h | 179 --- externals/soundtouch/STTypes.h | 185 --- externals/soundtouch/SoundTouch.cpp | 526 -------- externals/soundtouch/SoundTouch.h | 301 ----- externals/soundtouch/SoundTouch.vcxproj | 75 -- externals/soundtouch/TDStretch.cpp | 1078 ----------------- externals/soundtouch/TDStretch.h | 281 ----- externals/soundtouch/cpu_detect.h | 62 - externals/soundtouch/cpu_detect_x86.cpp | 138 --- externals/soundtouch/mmx_optimized.cpp | 395 ------ externals/soundtouch/sse_optimized.cpp | 372 ------ src/audio_core/CMakeLists.txt | 28 +- src/audio_core/audio_core.cpp | 1 - src/audio_core/audio_core.h | 8 +- src/audio_core/codec.cpp | 4 +- src/audio_core/hle/common.cpp | 0 src/audio_core/hle/dsp.cpp | 107 +- src/audio_core/hle/dsp.h | 37 +- src/audio_core/hle/effects.cpp | 44 - src/audio_core/hle/effects.h | 20 - src/audio_core/hle/final.cpp | 62 - src/audio_core/hle/final.h | 19 - src/audio_core/hle/pipe.cpp | 2 +- src/audio_core/hle/pipe.h | 2 - src/audio_core/hle/source.cpp | 334 ----- src/audio_core/hle/source.h | 35 - src/audio_core/interpolate.cpp | 237 ---- src/audio_core/interpolate.h | 28 - src/audio_core/null_sink.cpp | 3 - src/audio_core/null_sink.h | 9 - src/audio_core/sdl2_sink.cpp | 118 -- src/audio_core/sdl2_sink.h | 46 - src/audio_core/sink.h | 3 - src/audio_core/time_stretch.cpp | 83 -- src/audio_core/time_stretch.h | 24 - src/citra_qt/CMakeLists.txt | 2 - src/common/logging/backend.cpp | 1 - src/common/logging/log.h | 1 - src/core/hle/service/dsp_dsp.cpp | 128 +- src/core/hle/service/dsp_dsp.h | 3 - .../renderer_opengl/renderer_opengl.cpp | 3 +- 65 files changed, 52 insertions(+), 8680 deletions(-) delete mode 100644 externals/rubberband/CMakeLists.txt delete mode 160000 externals/rubberband/rubberband delete mode 100644 externals/soundtouch/AAFilter.cpp delete mode 100644 externals/soundtouch/AAFilter.h delete mode 100644 externals/soundtouch/BPMDetect.cpp delete mode 100644 externals/soundtouch/BPMDetect.h delete mode 100644 externals/soundtouch/CMakeLists.txt delete mode 100644 externals/soundtouch/FIFOSampleBuffer.cpp delete mode 100644 externals/soundtouch/FIFOSampleBuffer.h delete mode 100644 externals/soundtouch/FIFOSamplePipe.h delete mode 100644 externals/soundtouch/FIRFilter.cpp delete mode 100644 externals/soundtouch/FIRFilter.h delete mode 100644 externals/soundtouch/InterpolateCubic.cpp delete mode 100644 externals/soundtouch/InterpolateCubic.h delete mode 100644 externals/soundtouch/InterpolateLinear.cpp delete mode 100644 externals/soundtouch/InterpolateLinear.h delete mode 100644 externals/soundtouch/InterpolateShannon.cpp delete mode 100644 externals/soundtouch/InterpolateShannon.h delete mode 100644 externals/soundtouch/PeakFinder.cpp delete mode 100644 externals/soundtouch/PeakFinder.h delete mode 100644 externals/soundtouch/RateTransposer.cpp delete mode 100644 externals/soundtouch/RateTransposer.h delete mode 100644 externals/soundtouch/STTypes.h delete mode 100644 externals/soundtouch/SoundTouch.cpp delete mode 100644 externals/soundtouch/SoundTouch.h delete mode 100644 externals/soundtouch/SoundTouch.vcxproj delete mode 100644 externals/soundtouch/TDStretch.cpp delete mode 100644 externals/soundtouch/TDStretch.h delete mode 100644 externals/soundtouch/cpu_detect.h delete mode 100644 externals/soundtouch/cpu_detect_x86.cpp delete mode 100644 externals/soundtouch/mmx_optimized.cpp delete mode 100644 externals/soundtouch/sse_optimized.cpp delete mode 100644 src/audio_core/hle/common.cpp delete mode 100644 src/audio_core/hle/effects.cpp delete mode 100644 src/audio_core/hle/effects.h delete mode 100644 src/audio_core/hle/final.cpp delete mode 100644 src/audio_core/hle/final.h delete mode 100644 src/audio_core/hle/source.cpp delete mode 100644 src/audio_core/hle/source.h delete mode 100644 src/audio_core/interpolate.cpp delete mode 100644 src/audio_core/interpolate.h delete mode 100644 src/audio_core/null_sink.cpp delete mode 100644 src/audio_core/null_sink.h delete mode 100644 src/audio_core/sdl2_sink.cpp delete mode 100644 src/audio_core/sdl2_sink.h delete mode 100644 src/audio_core/time_stretch.cpp delete mode 100644 src/audio_core/time_stretch.h diff --git a/.gitmodules b/.gitmodules index c309b9873..598e4c64d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "nihstro"] path = externals/nihstro url = https://github.com/neobrain/nihstro.git -[submodule "rubberband"] - path = externals/rubberband/rubberband - url = https://github.com/breakfastquay/rubberband.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c9561eeb..3a0a161e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,7 +148,6 @@ if (ENABLE_SDL2) download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX) endif() - set(SDL2_FOUND YES) set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers") set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library") set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll") @@ -241,15 +240,11 @@ if (MSVC) add_subdirectory(externals/getopt) endif() +# process subdirectories if(ENABLE_QT) include_directories(externals/qhexedit) add_subdirectory(externals/qhexedit) endif() - -add_subdirectory(externals/soundtouch) -add_subdirectory(externals/rubberband) - -# process subdirectories add_subdirectory(src) # Install freedesktop.org metadata files, following those specifications: diff --git a/externals/boost b/externals/boost index 2dcb9d979..d81b92699 160000 --- a/externals/boost +++ b/externals/boost @@ -1 +1 @@ -Subproject commit 2dcb9d979665b6aabb1635c617973e02914e60ec +Subproject commit d81b9269900ae183d0dc98403eea4c971590a807 diff --git a/externals/rubberband/CMakeLists.txt b/externals/rubberband/CMakeLists.txt deleted file mode 100644 index 99518ec0a..000000000 --- a/externals/rubberband/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -set(SRCS - rubberband/src/audiocurves/CompoundAudioCurve.cpp - rubberband/src/audiocurves/ConstantAudioCurve.cpp - rubberband/src/audiocurves/HighFrequencyAudioCurve.cpp - rubberband/src/audiocurves/PercussiveAudioCurve.cpp - rubberband/src/audiocurves/SilentAudioCurve.cpp - rubberband/src/audiocurves/SpectralDifferenceAudioCurve.cpp - rubberband/src/base/Profiler.cpp - rubberband/src/dsp/AudioCurveCalculator.cpp - rubberband/src/dsp/FFT.cpp - rubberband/src/dsp/Resampler.cpp - rubberband/src/kissfft/kiss_fft.c - rubberband/src/kissfft/kiss_fftr.c - rubberband/src/RubberBandStretcher.cpp - rubberband/src/speex/resample.c - rubberband/src/StretchCalculator.cpp - rubberband/src/StretcherChannelData.cpp - rubberband/src/StretcherImpl.cpp - rubberband/src/StretcherProcess.cpp - rubberband/src/system/Allocators.cpp - rubberband/src/system/sysutils.cpp - rubberband/src/system/Thread.cpp - rubberband/src/system/VectorOpsComplex.cpp - ) - -SET(HEADERS - rubberband/src/audiocurves/CompoundAudioCurve.h - rubberband/src/audiocurves/ConstantAudioCurve.h - rubberband/src/audiocurves/HighFrequencyAudioCurve.h - rubberband/src/audiocurves/PercussiveAudioCurve.h - rubberband/src/audiocurves/SilentAudioCurve.h - rubberband/src/audiocurves/SpectralDifferenceAudioCurve.h - rubberband/src/base/Profiler.h - rubberband/src/base/RingBuffer.h - rubberband/src/base/Scavenger.h - rubberband/src/dsp/AudioCurveCalculator.h - rubberband/src/dsp/FFT.h - rubberband/src/dsp/MovingMedian.h - rubberband/src/dsp/Resampler.h - rubberband/src/dsp/SampleFilter.h - rubberband/src/dsp/SincWindow.h - rubberband/src/dsp/Window.h - rubberband/src/float_cast/float_cast.h - rubberband/src/kissfft/kiss_fft.h - rubberband/src/kissfft/kiss_fftr.h - rubberband/src/kissfft/_kiss_fft_guts.h - rubberband/src/pommier/neon_mathfun.h - rubberband/src/pommier/sse_mathfun.h - rubberband/src/speex/speex_resampler.h - rubberband/src/StretchCalculator.h - rubberband/src/StretcherChannelData.h - rubberband/src/StretcherImpl.h - rubberband/src/system/Allocators.h - rubberband/src/system/sysutils.h - rubberband/src/system/Thread.h - rubberband/src/system/VectorOps.h - rubberband/src/system/VectorOpsComplex.h - rubberband/rubberband/rubberband-c.h - rubberband/rubberband/RubberBandStretcher.h - ) - -add_library(rubberband STATIC ${SRCS} ${HEADERS}) - -target_include_directories(rubberband PRIVATE rubberband/src) -target_include_directories(rubberband PRIVATE rubberband) - -set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS USE_SPEEX) -if(APPLE) - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS HAVE_VDSP) - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS USE_PTHREADS) - target_link_libraries(rubberband "-framework Accelerate") -elseif(MSVC) - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS USE_KISSFFT) - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS __MSVC__) - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS WIN32) -else() - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS USE_KISSFFT) - set_property(TARGET rubberband APPEND PROPERTY COMPILE_DEFINITIONS USE_PTHREADS) -endif() diff --git a/externals/rubberband/rubberband b/externals/rubberband/rubberband deleted file mode 160000 index c93a18535..000000000 --- a/externals/rubberband/rubberband +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c93a18535ffea1ca7b18eb41c34064b77f8419e3 diff --git a/externals/soundtouch/AAFilter.cpp b/externals/soundtouch/AAFilter.cpp deleted file mode 100644 index a25430076..000000000 --- a/externals/soundtouch/AAFilter.cpp +++ /dev/null @@ -1,236 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// FIR low-pass (anti-alias) filter with filter coefficient design routine and -/// MMX optimization. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 -#include -#include "AAFilter.h" -#include "FIRFilter.h" - -using namespace soundtouch; - -#define PI 3.141592655357989 -#define TWOPI (2 * PI) - -// define this to save AA filter coefficients to a file -// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 - -#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS - #include - - static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) - { - FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); - if (fptr == NULL) return; - - for (int i = 0; i < len; i ++) - { - double temp = coeffs[i]; - fprintf(fptr, "%lf\n", temp); - } - fclose(fptr); - } - -#else - #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) -#endif - - -/***************************************************************************** - * - * Implementation of the class 'AAFilter' - * - *****************************************************************************/ - -AAFilter::AAFilter(uint len) -{ - pFIR = FIRFilter::newInstance(); - cutoffFreq = 0.5; - setLength(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. -void AAFilter::setCutoffFreq(double newCutoffFreq) -{ - cutoffFreq = newCutoffFreq; - calculateCoeffs(); -} - - - -// Sets number of FIR filter taps -void AAFilter::setLength(uint newLength) -{ - length = newLength; - calculateCoeffs(); -} - - - -// Calculates coefficients for a low-pass FIR filter using Hamming window -void AAFilter::calculateCoeffs() -{ - uint i; - double cntTemp, temp, tempCoeff,h, w; - double wc; - double scaleCoeff, sum; - double *work; - SAMPLETYPE *coeffs; - - assert(length >= 2); - assert(length % 4 == 0); - assert(cutoffFreq >= 0); - assert(cutoffFreq <= 0.5); - - work = new double[length]; - coeffs = new SAMPLETYPE[length]; - - wc = 2.0 * PI * cutoffFreq; - tempCoeff = TWOPI / (double)length; - - sum = 0; - for (i = 0; i < length; i ++) - { - cntTemp = (double)i - (double)(length / 2); - - temp = cntTemp * wc; - if (temp != 0) - { - h = sin(temp) / temp; // sinc function - } - else - { - h = 1.0; - } - w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window - - temp = w * h; - work[i] = temp; - - // calc net sum of coefficients - sum += temp; - } - - // ensure the sum of coefficients is larger than zero - assert(sum > 0); - - // ensure we've really designed a lowpass filter... - assert(work[length/2] > 0); - assert(work[length/2 + 1] > -1e-6); - assert(work[length/2 - 1] > -1e-6); - - // Calculate a scaling coefficient in such a way that the result can be - // divided by 16384 - scaleCoeff = 16384.0f / sum; - - 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; - } - - // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 - pFIR->setCoefficients(coeffs, length, 14); - - _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); - - delete[] work; - delete[] coeffs; -} - - -// Applies the filter to the given sequence of samples. -// Note : The amount of outputted samples is by value of 'filter length' -// smaller than the amount of input samples. -uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const -{ - return pFIR->evaluate(dest, src, numSamples, numChannels); -} - - -/// Applies the filter to the given src & dest pipes, so that processed amount of -/// samples get removed from src, and produced amount added to dest -/// Note : The amount of outputted samples is by value of 'filter length' -/// smaller than the amount of input samples. -uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const -{ - SAMPLETYPE *pdest; - const SAMPLETYPE *psrc; - uint numSrcSamples; - uint result; - int numChannels = src.getChannels(); - - assert(numChannels == dest.getChannels()); - - numSrcSamples = src.numSamples(); - psrc = src.ptrBegin(); - pdest = dest.ptrEnd(numSrcSamples); - result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); - src.receiveSamples(result); - dest.putSamples(result); - - return result; -} - - -uint AAFilter::getLength() const -{ - return pFIR->getLength(); -} diff --git a/externals/soundtouch/AAFilter.h b/externals/soundtouch/AAFilter.h deleted file mode 100644 index 8c34b6b20..000000000 --- a/externals/soundtouch/AAFilter.h +++ /dev/null @@ -1,100 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when -/// transposing the sample rate with interpolation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 AAFilter_H -#define AAFilter_H - -#include "STTypes.h" -#include "FIFOSampleBuffer.h" - -namespace soundtouch -{ - -class AAFilter -{ -protected: - class FIRFilter *pFIR; - - /// Low-pass filter cut-off frequency, negative = invalid - double cutoffFreq; - - /// num of filter taps - uint length; - - /// Calculate the FIR coefficients realizing the given cutoff-frequency - void calculateCoeffs(); -public: - AAFilter(uint length); - - ~AAFilter(); - - /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling - /// frequency (nyquist frequency = 0.5). The filter will cut off the - /// frequencies than that. - void setCutoffFreq(double newCutoffFreq); - - /// Sets number of FIR filter taps, i.e. ~filter complexity - void setLength(uint newLength); - - uint getLength() const; - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter length' - /// smaller than the amount of input samples. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels) const; - - /// Applies the filter to the given src & dest pipes, so that processed amount of - /// samples get removed from src, and produced amount added to dest - /// Note : The amount of outputted samples is by value of 'filter length' - /// smaller than the amount of input samples. - uint evaluate(FIFOSampleBuffer &dest, - FIFOSampleBuffer &src) const; - -}; - -} - -#endif diff --git a/externals/soundtouch/BPMDetect.cpp b/externals/soundtouch/BPMDetect.cpp deleted file mode 100644 index 7e6fd9c4a..000000000 --- a/externals/soundtouch/BPMDetect.cpp +++ /dev/null @@ -1,371 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// 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: BPMDetect.cpp 202 2015-02-21 21:24:29Z 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 -#include -#include "FIFOSampleBuffer.h" -#include "PeakFinder.h" -#include "BPMDetect.h" - -using namespace soundtouch; - -#define INPUT_BLOCK_SAMPLES 2048 -#define DECIMATED_BLOCK_SAMPLES 256 - -/// decay constant for calculating RMS volume sliding average approximation -/// (time constant is about 10 sec) -const float avgdecay = 0.99986f; - -/// Normalization coefficient for calculating RMS sliding average approximation. -const float avgnorm = (1 - avgdecay); - - -//////////////////////////////////////////////////////////////////////////////// - -// Enable following define to create bpm analysis 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) - { - FILE *fptr = fopen(DEBUGFILE_NAME, "wt"); - int i; - - if (fptr) - { - printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n"); - for (i = minpos; i < maxpos; i ++) - { - fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]); - } - fclose(fptr); - } - } -#else - #define _SaveDebugData(a,b,c,d) -#endif - -//////////////////////////////////////////////////////////////////////////////// - - -BPMDetect::BPMDetect(int numChannels, int aSampleRate) -{ - 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); - - // Calculate window length & starting item according to desired min & max bpms - windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); - windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM); - - assert(windowLen > windowStart); - - // allocate new working objects - xcorr = new float[windowLen]; - memset(xcorr, 0, windowLen * sizeof(float)); - - // allocate processing buffer - buffer = new FIFOSampleBuffer(); - // we do processing in mono mode - buffer->setChannels(1); - buffer->clear(); -} - - - -BPMDetect::~BPMDetect() -{ - delete[] xcorr; - delete buffer; -} - - - -/// convert to mono, low-pass filter & decimate to about 500 Hz. -/// return number of outputted samples. -/// -/// Decimation is used to remove the unnecessary frequencies and thus to reduce -/// the amount of data needed to be processed as calculating autocorrelation -/// function is a very-very heavy operation. -/// -/// Anti-alias filtering is done simply by averaging the samples. This is really a -/// poor-man's anti-alias filtering, but it's not so critical in this kind of application -/// (it'd also be difficult to design a high-quality filter with steep cut-off at very -/// narrow band) -int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) -{ - int count, outcount; - LONG_SAMPLETYPE out; - - assert(channels > 0); - assert(decimateBy > 0); - outcount = 0; - for (count = 0; count < numsamples; count ++) - { - int j; - - // convert to mono and accumulate - for (j = 0; j < channels; j ++) - { - decimateSum += src[j]; - } - src += j; - - decimateCount ++; - if (decimateCount >= decimateBy) - { - // Store every Nth sample only - out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels)); - decimateSum = 0; - decimateCount = 0; -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - // check ranges for sure (shouldn't actually be necessary) - if (out > 32767) - { - out = 32767; - } - else if (out < -32768) - { - out = -32768; - } -#endif // SOUNDTOUCH_INTEGER_SAMPLES - dest[outcount] = (SAMPLETYPE)out; - outcount ++; - } - } - return outcount; -} - - - -// Calculates autocorrelation function of the sample history buffer -void BPMDetect::updateXCorr(int process_samples) -{ - int offs; - SAMPLETYPE *pBuffer; - - assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); - - pBuffer = buffer->ptrBegin(); - #pragma omp parallel for - for (offs = windowStart; offs < windowLen; offs ++) - { - LONG_SAMPLETYPE 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 - } -// 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] += (float)sum; - } -} - - -// Calculates envelope of the sample data -void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) -{ - const static double decay = 0.7f; // decay constant for smoothing the envelope - const static double norm = (1 - decay); - - int i; - LONG_SAMPLETYPE out; - double val; - - for (i = 0; i < numsamples; i ++) - { - // 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)) - { - val = 0; - } - - // smooth amplitude envelope - envelopeAccu *= decay; - envelopeAccu += val; - out = (LONG_SAMPLETYPE)(envelopeAccu * norm); - -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - // cut peaks (shouldn't be necessary though) - if (out > 32767) out = 32767; -#endif // SOUNDTOUCH_INTEGER_SAMPLES - samples[i] = (SAMPLETYPE)out; - } -} - - - -void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) -{ - SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; - - // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration - while (numSamples > 0) - { - int block; - int decSamples; - - block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : 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) - { - 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); - } -} - - - -void BPMDetect::removeBias() -{ - int i; - float minval = 1e12f; // arbitrary large number - - for (i = windowStart; i < windowLen; i ++) - { - if (xcorr[i] < minval) - { - minval = xcorr[i]; - } - } - - for (i = windowStart; i < windowLen; i ++) - { - xcorr[i] -= minval; - } -} - - -float BPMDetect::getBpm() -{ - double peakPos; - double coeff; - PeakFinder peakFinder; - - coeff = 60.0 * ((double)sampleRate / (double)decimateBy); - - // save bpm debug analysis data if debug data enabled - _SaveDebugData(xcorr, windowStart, windowLen, coeff); - - // remove bias from xcorr data - removeBias(); - - // find peak position - peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); - - assert(decimateBy != 0); - if (peakPos < 1e-9) return 0.0; // detection failed. - - // calculate BPM - return (float) (coeff / peakPos); -} diff --git a/externals/soundtouch/BPMDetect.h b/externals/soundtouch/BPMDetect.h deleted file mode 100644 index 72489894b..000000000 --- a/externals/soundtouch/BPMDetect.h +++ /dev/null @@ -1,164 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Beats-per-minute (BPM) detection routine. -/// -/// The beat detection algorithm works as follows: -/// - Use function 'inputSamples' to input a chunks of samples to the class for -/// analysis. It's a good idea to enter a large sound file or stream in smallish -/// chunks of around few kilosamples in order not to extinguish too much RAM memory. -/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, -/// which is basically ok as low (bass) frequencies mostly determine the beat rate. -/// Simple averaging is used for anti-alias filtering because the resulting signal -/// quality isn't of that high importance. -/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by -/// taking absolute value that's smoothed by sliding average. Signal levels that -/// are below a couple of times the general RMS amplitude level are cut away to -/// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term -/// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation -/// function, calculates it's precise location and converts this reading to bpm's. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 _BPMDetect_H_ -#define _BPMDetect_H_ - -#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 - -/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. -#define MAX_BPM 200 - - -/// 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(); -}; - -} - -#endif // _BPMDetect_H_ diff --git a/externals/soundtouch/CMakeLists.txt b/externals/soundtouch/CMakeLists.txt deleted file mode 100644 index b7a2e5dc0..000000000 --- a/externals/soundtouch/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(SRCS - AAFilter.cpp - BPMDetect.cpp - cpu_detect_x86.cpp - FIFOSampleBuffer.cpp - FIRFilter.cpp - InterpolateCubic.cpp - InterpolateLinear.cpp - InterpolateShannon.cpp - mmx_optimized.cpp - PeakFinder.cpp - RateTransposer.cpp - SoundTouch.cpp - sse_optimized.cpp - TDStretch.cpp - ) - -add_library(SoundTouch STATIC ${SRCS}) diff --git a/externals/soundtouch/FIFOSampleBuffer.cpp b/externals/soundtouch/FIFOSampleBuffer.cpp deleted file mode 100644 index 4d9740ae6..000000000 --- a/externals/soundtouch/FIFOSampleBuffer.cpp +++ /dev/null @@ -1,274 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// outputted samples from the buffer, as well as grows the buffer size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 -#include - -#include "FIFOSampleBuffer.h" - -using namespace soundtouch; - -// Constructor -FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) -{ - assert(numChannels > 0); - sizeInBytes = 0; // reasonable initial value - buffer = NULL; - bufferUnaligned = NULL; - samplesInBuffer = 0; - bufferPos = 0; - channels = (uint)numChannels; - ensureCapacity(32); // allocate initial capacity -} - - -// destructor -FIFOSampleBuffer::~FIFOSampleBuffer() -{ - delete[] bufferUnaligned; - bufferUnaligned = NULL; - buffer = NULL; -} - - -// Sets number of channels, 1 = mono, 2 = stereo -void FIFOSampleBuffer::setChannels(int numChannels) -{ - uint usedBytes; - - assert(numChannels > 0); - usedBytes = channels * samplesInBuffer; - channels = (uint)numChannels; - samplesInBuffer = usedBytes / channels; -} - - -// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and -// zeroes this pointer by copying samples from the 'bufferPos' pointer -// location on to the beginning of the buffer. -void FIFOSampleBuffer::rewind() -{ - if (buffer && bufferPos) - { - memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); - bufferPos = 0; - } -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position to -// the sample buffer. -void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) -{ - memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); - samplesInBuffer += nSamples; -} - - -// Increases the number of samples in the buffer without copying any actual -// samples. -// -// This function is used to update the number of samples in the sample buffer -// when accessing the buffer directly with 'ptrEnd' function. Please be -// careful though! -void FIFOSampleBuffer::putSamples(uint nSamples) -{ - uint req; - - req = samplesInBuffer + nSamples; - ensureCapacity(req); - samplesInBuffer += nSamples; -} - - -// Returns a pointer to the end of the used part of the sample buffer (i.e. -// where the new samples are to be inserted). This function may be used for -// inserting new samples into the sample buffer directly. Please be careful! -// -// 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, -// the function grows the buffer size to comply with this requirement. -// -// When using this function as means for inserting new samples, also remember -// to increase the sample count afterwards, by calling the -// 'putSamples(numSamples)' function. -SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) -{ - ensureCapacity(samplesInBuffer + slackCapacity); - return buffer + samplesInBuffer * channels; -} - - -// Returns a pointer to the beginning of the currently non-outputted samples. -// This function is provided for accessing the output samples directly. -// Please be careful! -// -// When using this function to output samples, also remember to 'remove' the -// outputted samples from the buffer by calling the -// 'receiveSamples(numSamples)' function -SAMPLETYPE *FIFOSampleBuffer::ptrBegin() -{ - assert(buffer); - return buffer + bufferPos * channels; -} - - -// Ensures that the buffer has enought 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. -void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) -{ - SAMPLETYPE *tempUnaligned, *temp; - - if (capacityRequirement > getCapacity()) - { - // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) - sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; - assert(sizeInBytes % 2 == 0); - tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; - if (tempUnaligned == NULL) - { - ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); - } - // Align the buffer to begin at 16byte cache line boundary for optimal performance - temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); - if (samplesInBuffer) - { - memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); - } - delete[] bufferUnaligned; - buffer = temp; - bufferUnaligned = tempUnaligned; - bufferPos = 0; - } - else - { - // simply rewind the buffer (if necessary) - rewind(); - } -} - - -// Returns the current buffer capacity in terms of samples -uint FIFOSampleBuffer::getCapacity() const -{ - return sizeInBytes / (channels * sizeof(SAMPLETYPE)); -} - - -// Returns the number of samples currently in the buffer -uint FIFOSampleBuffer::numSamples() const -{ - return samplesInBuffer; -} - - -// Output samples from beginning of the sample buffer. Copies demanded number -// of samples to output and removes them from the sample buffer. If there -// are less than 'numsample' samples in the buffer, returns all available. -// -// Returns number of samples copied. -uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) -{ - uint num; - - num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; - - memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); - return receiveSamples(num); -} - - -// Removes samples from the beginning of the sample buffer without copying them -// anywhere. Used to reduce the number of samples in the buffer, when accessing -// the sample buffer with the 'ptrBegin' function. -uint FIFOSampleBuffer::receiveSamples(uint maxSamples) -{ - if (maxSamples >= samplesInBuffer) - { - uint temp; - - temp = samplesInBuffer; - samplesInBuffer = 0; - return temp; - } - - samplesInBuffer -= maxSamples; - bufferPos += maxSamples; - - return maxSamples; -} - - -// Returns nonzero if the sample buffer is empty -int FIFOSampleBuffer::isEmpty() const -{ - return (samplesInBuffer == 0) ? 1 : 0; -} - - -// Clears the sample buffer -void FIFOSampleBuffer::clear() -{ - samplesInBuffer = 0; - bufferPos = 0; -} - - -/// allow trimming (downwards) amount of samples in pipeline. -/// Returns adjusted amount of samples -uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) -{ - if (numSamples < samplesInBuffer) - { - samplesInBuffer = numSamples; - } - return samplesInBuffer; -} - diff --git a/externals/soundtouch/FIFOSampleBuffer.h b/externals/soundtouch/FIFOSampleBuffer.h deleted file mode 100644 index 4b22a51e3..000000000 --- a/externals/soundtouch/FIFOSampleBuffer.h +++ /dev/null @@ -1,184 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A buffer class for temporarily storaging sound samples, operates as a -/// first-in-first-out pipe. -/// -/// Samples are added to the end of the sample buffer with the 'putSamples' -/// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// output samples from the buffer as well as grows the storage size -/// whenever necessary. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 FIFOSampleBuffer_H -#define FIFOSampleBuffer_H - -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes -/// care of storage size adjustment and data moving during input/output operations. -/// -/// Notice that in case of stereo audio, one sample is considered to consist of -/// both channel data. -class FIFOSampleBuffer : public FIFOSamplePipe -{ -private: - /// Sample buffer. - SAMPLETYPE *buffer; - - // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first - // 16-byte aligned location of this buffer - SAMPLETYPE *bufferUnaligned; - - /// Sample buffer size in bytes - uint sizeInBytes; - - /// How many samples are currently in buffer. - uint samplesInBuffer; - - /// Channels, 1=mono, 2=stereo. - uint channels; - - /// Current position pointer to the buffer. This pointer is increased when samples are - /// removed from the pipe so that it's necessary to actually rewind buffer (move data) - /// only new data when is put to the pipe. - uint bufferPos; - - /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real - /// beginning of the buffer. - void rewind(); - - /// Ensures that the buffer has capacity for at least this many samples. - void ensureCapacity(uint capacityRequirement); - - /// Returns current capacity. - uint getCapacity() const; - -public: - - /// Constructor - FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. - ///< Default is stereo. - ); - - /// destructor - ~FIFOSampleBuffer(); - - /// 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! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin(); - - /// Returns a pointer to the end of the used part of the sample buffer (i.e. - /// where the new samples are to be inserted). This function may be used for - /// inserting new samples into the sample buffer directly. Please be careful - /// not corrupt the book-keeping! - /// - /// When using this function as means for inserting new samples, also remember - /// to increase the sample count afterwards, by calling the - /// '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 - ///< desired samples to the buffer. If necessary, the function - ///< grows the buffer size to comply with this requirement. - ); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ); - - /// Adjusts the book-keeping to increase number of samples in the buffer without - /// copying any actual samples. - /// - /// This function is used to update the number of samples in the sample buffer - /// when accessing the buffer directly with 'ptrEnd' function. Please be - /// careful though! - virtual void putSamples(uint numSamples ///< Number of samples been inserted. - ); - - /// 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. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ); - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ); - - /// Returns number of samples currently available. - virtual uint numSamples() const; - - /// Sets number of channels, 1 = mono, 2 = stereo. - void setChannels(int numChannels); - - /// Get number of channels - int getChannels() - { - return channels; - } - - /// Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const; - - /// Clears all the samples. - virtual void clear(); - - /// allow trimming (downwards) amount of samples in pipeline. - /// Returns adjusted amount of samples - uint adjustAmountOfSamples(uint numSamples); -}; - -} - -#endif diff --git a/externals/soundtouch/FIFOSamplePipe.h b/externals/soundtouch/FIFOSamplePipe.h deleted file mode 100644 index f26c57b0b..000000000 --- a/externals/soundtouch/FIFOSamplePipe.h +++ /dev/null @@ -1,234 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound -/// samples by operating like a first-in-first-out pipe: New samples are fed -/// into one end of the pipe with the 'putSamples' function, and the processed -/// samples are received from the other end with the 'receiveSamples' function. -/// -/// 'FIFOProcessor' : A base class for classes the do signal processing with -/// the samples while operating like a first-in-first-out pipe. When samples -/// are input with the 'putSamples' function, the class processes them -/// and moves the processed samples to the given 'output' pipe object, which -/// may be either another processing stage, or a fifo sample buffer object. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 FIFOSamplePipe_H -#define FIFOSamplePipe_H - -#include -#include -#include "STTypes.h" - -namespace soundtouch -{ - -/// Abstract base class for FIFO (first-in-first-out) sample processing classes. -class FIFOSamplePipe -{ -public: - // virtual default destructor - virtual ~FIFOSamplePipe() {} - - - /// 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! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() = 0; - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position to - /// the sample buffer. - virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. - ) = 0; - - - // Moves samples from the 'other' pipe instance to this instance. - void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. - ) - { - int oNumSamples = other.numSamples(); - - putSamples(other.ptrBegin(), oNumSamples); - other.receiveSamples(oNumSamples); - }; - - /// 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. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) = 0; - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) = 0; - - /// Returns number of samples currently available. - virtual uint numSamples() const = 0; - - // Returns nonzero if there aren't any samples available for outputting. - virtual int isEmpty() const = 0; - - /// Clears all the samples. - virtual void clear() = 0; - - /// allow trimming (downwards) amount of samples in pipeline. - /// Returns adjusted amount of samples - virtual uint adjustAmountOfSamples(uint numSamples) = 0; - -}; - - - -/// 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 -/// all the processing stages. -/// -/// When samples are input to this class, they're first processed and then put to -/// the FIFO pipe that's defined as output of this class. This output pipe can be -/// either other processing stage or a FIFO sample buffer. -class FIFOProcessor :public FIFOSamplePipe -{ -protected: - /// Internal pipe where processed samples are put. - FIFOSamplePipe *output; - - /// Sets output pipe. - void setOutPipe(FIFOSamplePipe *pOutput) - { - assert(output == NULL); - assert(pOutput != NULL); - output = pOutput; - } - - - /// Constructor. Doesn't define output pipe; it has to be set be - /// 'setOutPipe' function. - FIFOProcessor() - { - output = NULL; - } - - - /// Constructor. Configures output pipe. - FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. - ) - { - 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! - /// - /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the - /// 'receiveSamples(numSamples)' function - virtual SAMPLETYPE *ptrBegin() - { - return output->ptrBegin(); - } - -public: - - /// 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. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ) - { - 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. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ) - { - 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 - { - return output->isEmpty(); - } - - /// allow trimming (downwards) amount of samples in pipeline. - /// Returns adjusted amount of samples - virtual uint adjustAmountOfSamples(uint numSamples) - { - return output->adjustAmountOfSamples(numSamples); - } - -}; - -} - -#endif diff --git a/externals/soundtouch/FIRFilter.cpp b/externals/soundtouch/FIRFilter.cpp deleted file mode 100644 index 456418a58..000000000 --- a/externals/soundtouch/FIRFilter.cpp +++ /dev/null @@ -1,328 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// 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 -// 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 -#include -#include "FIRFilter.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/***************************************************************************** - * - * Implementation of the class 'FIRFilter' - * - *****************************************************************************/ - -FIRFilter::FIRFilter() -{ - resultDivFactor = 0; - resultDivider = 0; - length = 0; - lengthDiv8 = 0; - filterCoeffs = NULL; -} - - -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 -{ - int j, end; -#ifdef SOUNDTOUCH_FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - assert(length != 0); - assert(src != NULL); - assert(dest != NULL); - assert(filterCoeffs != NULL); - - end = 2 * (numSamples - length); - - #pragma omp parallel for - for (j = 0; j < end; j += 2) - { - const SAMPLETYPE *ptr; - LONG_SAMPLETYPE suml, sumr; - uint i; - - suml = sumr = 0; - ptr = src + j; - - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + - ptr[2 * i + 2] * filterCoeffs[i + 1] + - ptr[2 * i + 4] * filterCoeffs[i + 2] + - ptr[2 * i + 6] * filterCoeffs[i + 3]; - sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + - ptr[2 * i + 3] * filterCoeffs[i + 1] + - ptr[2 * i + 5] * filterCoeffs[i + 2] + - ptr[2 * i + 7] * filterCoeffs[i + 3]; - } - -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - suml >>= resultDivFactor; - sumr >>= resultDivFactor; - // saturate to 16 bit integer limits - suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; - // saturate to 16 bit integer limits - sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; -#else - suml *= dScaler; - sumr *= dScaler; -#endif // SOUNDTOUCH_INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)suml; - dest[j + 1] = (SAMPLETYPE)sumr; - } - return numSamples - length; -} - - - - -// Usual C-version of the filter routine for mono sound -uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const -{ - int j, end; -#ifdef SOUNDTOUCH_FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - assert(length != 0); - - end = numSamples - length; - #pragma omp parallel for - for (j = 0; j < end; j ++) - { - const SAMPLETYPE *pSrc = src + j; - LONG_SAMPLETYPE sum; - uint i; - - sum = 0; - for (i = 0; i < length; i += 4) - { - // loop is unrolled by factor of 4 here for efficiency - sum += pSrc[i + 0] * filterCoeffs[i + 0] + - pSrc[i + 1] * filterCoeffs[i + 1] + - pSrc[i + 2] * filterCoeffs[i + 2] + - pSrc[i + 3] * filterCoeffs[i + 3]; - } -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - sum >>= resultDivFactor; - // saturate to 16 bit integer limits - sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; -#else - sum *= dScaler; -#endif // SOUNDTOUCH_INTEGER_SAMPLES - dest[j] = (SAMPLETYPE)sum; - } - return end; -} - - -uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) -{ - int j, end; - -#ifdef SOUNDTOUCH_FLOAT_SAMPLES - // when using floating point samples, use a scaler instead of a divider - // because division is much slower operation than multiplying. - double dScaler = 1.0 / (double)resultDivider; -#endif - - assert(length != 0); - assert(src != NULL); - assert(dest != NULL); - assert(filterCoeffs != NULL); - assert(numChannels < 16); - - end = numChannels * (numSamples - length); - - #pragma omp parallel for - for (j = 0; j < end; j += numChannels) - { - const SAMPLETYPE *ptr; - LONG_SAMPLETYPE sums[16]; - uint c, i; - - for (c = 0; c < numChannels; c ++) - { - sums[c] = 0; - } - - ptr = src + j; - - for (i = 0; i < length; i ++) - { - SAMPLETYPE coef=filterCoeffs[i]; - for (c = 0; c < numChannels; c ++) - { - sums[c] += ptr[0] * coef; - ptr ++; - } - } - - for (c = 0; c < numChannels; c ++) - { -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - sums[c] >>= resultDivFactor; -#else - sums[c] *= dScaler; -#endif // SOUNDTOUCH_INTEGER_SAMPLES - dest[j+c] = (SAMPLETYPE)sums[c]; - } - } - return numSamples - length; -} - - -// Set filter coeffiecients and length. -// -// Throws an exception if filter length isn't divisible by 8 -void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) -{ - assert(newLength > 0); - if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); - - lengthDiv8 = newLength / 8; - length = lengthDiv8 * 8; - assert(length == newLength); - - resultDivFactor = uResultDivFactor; - resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); - - delete[] filterCoeffs; - filterCoeffs = new SAMPLETYPE[length]; - memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); -} - - -uint FIRFilter::getLength() const -{ - return length; -} - - - -// Applies the filter to the given sequence of samples. -// -// Note : The amount of outputted samples is by value of 'filter_length' -// smaller than the amount of input samples. -uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) -{ - assert(length > 0); - assert(lengthDiv8 * 8 == length); - - if (numSamples < length) return 0; - -#ifndef USE_MULTICH_ALWAYS - if (numChannels == 1) - { - return evaluateFilterMono(dest, src, numSamples); - } - else if (numChannels == 2) - { - return evaluateFilterStereo(dest, src, numSamples); - } - else -#endif // USE_MULTICH_ALWAYS - { - assert(numChannels > 0); - return evaluateFilterMulti(dest, src, numSamples, numChannels); - } -} - - - -// 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) -{ - // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! - ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); - return newInstance(); -} - - -FIRFilter * FIRFilter::newInstance() -{ - uint uExtensions; - - uExtensions = detectCPUextensions(); - - // Check if MMX/SSE instruction set extensions supported by CPU - -#ifdef SOUNDTOUCH_ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new FIRFilterMMX; - } - else -#endif // SOUNDTOUCH_ALLOW_MMX - -#ifdef SOUNDTOUCH_ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new FIRFilterSSE; - } - else -#endif // SOUNDTOUCH_ALLOW_SSE - - { - // ISA optimizations not supported, use plain C version - return ::new FIRFilter; - } -} diff --git a/externals/soundtouch/FIRFilter.h b/externals/soundtouch/FIRFilter.h deleted file mode 100644 index 158cdd270..000000000 --- a/externals/soundtouch/FIRFilter.h +++ /dev/null @@ -1,146 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// General FIR digital filter routines with MMX optimization. -/// -/// Note : MMX optimized functions reside in a separate, platform-specific file, -/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' -/// -/// 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.h 202 2015-02-21 21:24:29Z 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 FIRFilter_H -#define FIRFilter_H - -#include -#include "STTypes.h" - -namespace soundtouch -{ - -class FIRFilter -{ -protected: - // Number of FIR filter taps - uint length; - // Number of FIR filter taps divided by 8 - uint lengthDiv8; - - // Result divider factor in 2^k format - uint resultDivFactor; - - // Result divider value. - SAMPLETYPE resultDivider; - - // Memory for filter coefficients - SAMPLETYPE *filterCoeffs; - - virtual uint evaluateFilterStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - virtual uint evaluateFilterMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) const; - virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels); - -public: - FIRFilter(); - virtual ~FIRFilter(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX-capable CPU available or not. - static void * operator new(size_t s); - - static FIRFilter *newInstance(); - - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter_length' - /// smaller than the amount of input samples. - /// - /// \return Number of samples copied to 'dest'. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, - uint numChannels); - - uint getLength() const; - - virtual void setCoefficients(const SAMPLETYPE *coeffs, - uint newLength, - uint uResultDivFactor); -}; - - -// Optional subclasses that implement CPU-specific optimizations: - -#ifdef SOUNDTOUCH_ALLOW_MMX - -/// Class that implements MMX optimized functions exclusive for 16bit integer samples type. - class FIRFilterMMX : public FIRFilter - { - protected: - short *filterCoeffsUnalign; - short *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; - public: - FIRFilterMMX(); - ~FIRFilterMMX(); - - virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // SOUNDTOUCH_ALLOW_MMX - - -#ifdef SOUNDTOUCH_ALLOW_SSE - /// Class that implements SSE optimized functions exclusive for floating point samples type. - class FIRFilterSSE : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilterSSE(); - ~FIRFilterSSE(); - - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // SOUNDTOUCH_ALLOW_SSE - -} - -#endif // FIRFilter_H diff --git a/externals/soundtouch/InterpolateCubic.cpp b/externals/soundtouch/InterpolateCubic.cpp deleted file mode 100644 index 8aa7374c7..000000000 --- a/externals/soundtouch/InterpolateCubic.cpp +++ /dev/null @@ -1,200 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 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; -} diff --git a/externals/soundtouch/InterpolateCubic.h b/externals/soundtouch/InterpolateCubic.h deleted file mode 100644 index f98e701d7..000000000 --- a/externals/soundtouch/InterpolateCubic.h +++ /dev/null @@ -1,67 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 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 diff --git a/externals/soundtouch/InterpolateLinear.cpp b/externals/soundtouch/InterpolateLinear.cpp deleted file mode 100644 index 811981385..000000000 --- a/externals/soundtouch/InterpolateLinear.cpp +++ /dev/null @@ -1,300 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 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; -} diff --git a/externals/soundtouch/InterpolateLinear.h b/externals/soundtouch/InterpolateLinear.h deleted file mode 100644 index 6a7e11d18..000000000 --- a/externals/soundtouch/InterpolateLinear.h +++ /dev/null @@ -1,92 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// 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 diff --git a/externals/soundtouch/InterpolateShannon.cpp b/externals/soundtouch/InterpolateShannon.cpp deleted file mode 100644 index 1085fd14c..000000000 --- a/externals/soundtouch/InterpolateShannon.cpp +++ /dev/null @@ -1,185 +0,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 -/// -//////////////////////////////////////////////////////////////////////////////// -// -// $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; -} diff --git a/externals/soundtouch/InterpolateShannon.h b/externals/soundtouch/InterpolateShannon.h deleted file mode 100644 index 54703d980..000000000 --- a/externals/soundtouch/InterpolateShannon.h +++ /dev/null @@ -1,72 +0,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 -/// -//////////////////////////////////////////////////////////////////////////////// -// -// $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 diff --git a/externals/soundtouch/PeakFinder.cpp b/externals/soundtouch/PeakFinder.cpp deleted file mode 100644 index 1a7290b0f..000000000 --- a/externals/soundtouch/PeakFinder.cpp +++ /dev/null @@ -1,286 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Peak detection routine. -/// -/// The routine detects highest value on an array of values and calculates the -/// precise peak location as a mass-center of the 'hump' around the peak value. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 "PeakFinder.h" - -using namespace soundtouch; - -#define max(x, y) (((x) > (y)) ? (x) : (y)) - - -PeakFinder::PeakFinder() -{ - minPos = maxPos = 0; -} - - -// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. -int PeakFinder::findTop(const float *data, int peakpos) const -{ - int i; - int start, end; - float refvalue; - - refvalue = data[peakpos]; - - // seek within ±10 points - start = peakpos - 10; - if (start < minPos) start = minPos; - end = peakpos + 10; - if (end > maxPos) end = maxPos; - - for (i = start; i <= end; i ++) - { - if (data[i] > refvalue) - { - peakpos = i; - refvalue = data[i]; - } - } - - // failure if max value is at edges of seek range => it's not peak, it's at slope. - if ((peakpos == start) || (peakpos == end)) return 0; - - return peakpos; -} - - -// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding -// to direction defined by 'direction' until next 'hump' after minimum value will -// begin -int PeakFinder::findGround(const float *data, int peakpos, int direction) const -{ - int lowpos; - int pos; - int climb_count; - float refvalue; - float delta; - - climb_count = 0; - refvalue = data[peakpos]; - lowpos = peakpos; - - pos = peakpos; - - while ((pos > minPos+1) && (pos < maxPos-1)) - { - int prevpos; - - prevpos = pos; - pos += direction; - - // calculate derivate - delta = data[pos] - data[prevpos]; - if (delta <= 0) - { - // going downhill, ok - if (climb_count) - { - climb_count --; // decrease climb count - } - - // check if new minimum found - if (data[pos] < refvalue) - { - // new minimum found - lowpos = pos; - refvalue = data[pos]; - } - } - else - { - // going uphill, increase climbing counter - climb_count ++; - if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit - } - } - return lowpos; -} - - -// Find offset where the value crosses the given level, when starting from 'peakpos' and -// proceeds to direction defined in 'direction' -int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const -{ - float peaklevel; - int pos; - - peaklevel = data[peakpos]; - assert(peaklevel >= level); - pos = peakpos; - while ((pos >= minPos) && (pos < maxPos)) - { - if (data[pos + direction] < level) return pos; // crossing found - pos += direction; - } - return -1; // not found -} - - -// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos' -double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const -{ - int i; - float sum; - float wsum; - - sum = 0; - wsum = 0; - for (i = firstPos; i <= lastPos; i ++) - { - sum += (float)i * data[i]; - wsum += data[i]; - } - - if (wsum < 1e-6) return 0; - return sum / wsum; -} - - - -/// get exact center of peak near given position by calculating local mass of center -double PeakFinder::getPeakCenter(const float *data, int peakpos) const -{ - float peakLevel; // peak level - int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level - float cutLevel; // cutting value - float groundLevel; // ground level of the peak - int gp1, gp2; // bottom positions of the peak 'hump' - - // find ground positions. - gp1 = findGround(data, peakpos, -1); - gp2 = findGround(data, peakpos, 1); - - peakLevel = data[peakpos]; - - if (gp1 == gp2) - { - // avoid rounding errors when all are equal - assert(gp1 == peakpos); - cutLevel = groundLevel = peakLevel; - } else { - // get average of the ground levels - groundLevel = 0.5f * (data[gp1] + data[gp2]); - - // calculate 70%-level of the peak - cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; - } - - // find mid-level crossings - crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1); - crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1); - - if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak.. - - // calculate mass center of the peak surroundings - return calcMassCenter(data, crosspos1, crosspos2); -} - - - -double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) -{ - - int i; - int peakpos; // position of peak level - double highPeak, peak; - - this->minPos = aminPos; - this->maxPos = amaxPos; - - // find absolute peak - peakpos = minPos; - peak = data[minPos]; - for (i = minPos + 1; i < maxPos; i ++) - { - if (data[i] > peak) - { - peak = data[i]; - peakpos = i; - } - } - - // Calculate exact location of the highest peak mass center - highPeak = getPeakCenter(data, peakpos); - peak = highPeak; - - // Now check if the highest peak were in fact harmonic of the true base beat peak - // - 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 ++) - { - double peaktmp, harmonic; - int i1,i2; - - harmonic = (double)i * 0.5; - peakpos = (int)(highPeak / harmonic + 0.5f); - if (peakpos < minPos) break; - peakpos = findTop(data, peakpos); // seek true local maximum index - if (peakpos == 0) continue; // no local max here - - // calculate mass-center of possible harmonic peak - peaktmp = getPeakCenter(data, peakpos); - - // accept harmonic peak if - // (a) it is found - // (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; - if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected - - // now compare to highest detected peak - i1 = (int)(highPeak + 0.5); - i2 = (int)(peaktmp + 0.5); - if (data[i2] >= 0.4*data[i1]) - { - // The harmonic is at least half as high primary peak, - // thus use the harmonic peak instead - peak = peaktmp; - } - } - - return peak; -} diff --git a/externals/soundtouch/PeakFinder.h b/externals/soundtouch/PeakFinder.h deleted file mode 100644 index d170b1c58..000000000 --- a/externals/soundtouch/PeakFinder.h +++ /dev/null @@ -1,97 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// The routine detects highest value on an array of values and calculates the -/// precise peak location as a mass-center of the 'hump' around the peak value. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 _PeakFinder_H_ -#define _PeakFinder_H_ - -namespace soundtouch -{ - -class PeakFinder -{ -protected: - /// Min, max allowed peak positions within the data vector - int minPos, maxPos; - - /// 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. - ) const; - - /// Finds the data vector index where the monotoniously decreasing signal crosses the - /// given level. - int findCrossingLevel(const float *data, ///< Data vector. - float level, ///< Goal crossing level. - int peakpos, ///< Peak position index within the data vector. - int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. - ) const; - - // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. - int findTop(const float *data, int peakpos) const; - - - /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- - /// or left-hand side of the given peak position. - int findGround(const float *data, /// Data vector. - int peakpos, /// Peak position index within the data vector. - int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. - ) const; - - /// get exact center of peak near given position by calculating local mass of center - double getPeakCenter(const float *data, int peakpos) const; - -public: - /// Constructor. - PeakFinder(); - - /// Detect exact peak position of the data vector by finding the largest peak 'hump' - /// and calculating the mass-center location of the peak hump. - /// - /// \return The location of the largest base harmonic peak hump. - double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has - /// to be at least 'maxPos' items long. - int minPos, ///< Min allowed peak location within the vector data. - int maxPos ///< Max allowed peak location within the vector data. - ); -}; - -} - -#endif // _PeakFinder_H_ diff --git a/externals/soundtouch/RateTransposer.cpp b/externals/soundtouch/RateTransposer.cpp deleted file mode 100644 index 19e810131..000000000 --- a/externals/soundtouch/RateTransposer.cpp +++ /dev/null @@ -1,302 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application) -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 -#include -#include "RateTransposer.h" -#include "InterpolateLinear.h" -#include "InterpolateCubic.h" -#include "InterpolateShannon.h" -#include "AAFilter.h" - -using namespace soundtouch; - -// Define default interpolation algorithm here -TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC; - - -// Constructor -RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) -{ - bUseAAFilter = true; - - // Instantiates the anti-alias filter - pAAFilter = new AAFilter(64); - pTransposer = TransposerBase::newInstance(); -} - - - -RateTransposer::~RateTransposer() -{ - delete pAAFilter; - delete pTransposer; -} - - - -/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable -void RateTransposer::enableAAFilter(bool newMode) -{ - bUseAAFilter = newMode; -} - - -/// Returns nonzero if anti-alias filter is enabled. -bool RateTransposer::isAAFilterEnabled() const -{ - return bUseAAFilter; -} - - -AAFilter *RateTransposer::getAAFilter() -{ - return pAAFilter; -} - - - -// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower -// iRate, larger faster iRates. -void RateTransposer::setRate(double newRate) -{ - double fCutoff; - - pTransposer->setRate(newRate); - - // design a new anti-alias filter - if (newRate > 1.0) - { - fCutoff = 0.5 / newRate; - } - else - { - fCutoff = 0.5 * newRate; - } - pAAFilter->setCutoffFreq(fCutoff); -} - - -// Adds 'nSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples) -{ - processSamples(samples, nSamples); -} - - -// Transposes sample rate by applying anti-alias filter to prevent folding. -// Returns amount of samples returned in the "dest" buffer. -// The maximum amount of samples that can be returned at a time is set by -// the 'set_returnBuffer_size' function. -void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) -{ - uint count; - - if (nSamples == 0) return; - - // Store samples to input buffer - inputBuffer.putSamples(src, nSamples); - - // If anti-alias filter is turned off, simply transpose without applying - // the filter - if (bUseAAFilter == false) - { - count = pTransposer->transpose(outputBuffer, inputBuffer); - return; - } - - assert(pAAFilter); - - // Transpose with anti-alias filter - if (pTransposer->rate < 1.0f) - { - // If the parameter 'Rate' value is smaller than 1, first transpose - // the samples and then apply the anti-alias filter to remove aliasing. - - // Transpose the samples, store the result to end of "midBuffer" - pTransposer->transpose(midBuffer, inputBuffer); - - // Apply the anti-alias filter for transposed samples in midBuffer - pAAFilter->evaluate(outputBuffer, midBuffer); - } - else - { - // If the parameter 'Rate' value is larger than 1, first apply the - // anti-alias filter to remove high frequencies (prevent them from folding - // over the lover frequencies), then transpose. - - // Apply the anti-alias filter for samples in inputBuffer - pAAFilter->evaluate(midBuffer, inputBuffer); - - // Transpose the AA-filtered samples in "midBuffer" - pTransposer->transpose(outputBuffer, midBuffer); - } -} - - -// Sets the number of channels, 1 = mono, 2 = stereo -void RateTransposer::setChannels(int nChannels) -{ - assert(nChannels > 0); - - if (pTransposer->numChannels == nChannels) return; - pTransposer->setChannels(nChannels); - - inputBuffer.setChannels(nChannels); - midBuffer.setChannels(nChannels); - outputBuffer.setChannels(nChannels); -} - - -// Clears all the samples in the object -void RateTransposer::clear() -{ - outputBuffer.clear(); - midBuffer.clear(); - inputBuffer.clear(); -} - - -// Returns nonzero if there aren't any samples available for outputting. -int RateTransposer::isEmpty() const -{ - int res; - - res = FIFOProcessor::isEmpty(); - if (res == 0) return 0; - return inputBuffer.isEmpty(); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// TransposerBase - Base class for interpolation -// - -// static function to set interpolation algorithm -void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a) -{ - TransposerBase::algorithm = a; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// Returns the number of samples returned in the "dest" buffer -int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) -{ - int numSrcSamples = src.numSamples(); - int sizeDemand = (int)((double)numSrcSamples / rate) + 8; - int numOutput; - SAMPLETYPE *psrc = src.ptrBegin(); - SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand); - -#ifndef USE_MULTICH_ALWAYS - if (numChannels == 1) - { - numOutput = transposeMono(pdest, psrc, numSrcSamples); - } - else if (numChannels == 2) - { - numOutput = transposeStereo(pdest, psrc, numSrcSamples); - } - else -#endif // USE_MULTICH_ALWAYS - { - assert(numChannels > 0); - numOutput = transposeMulti(pdest, psrc, numSrcSamples); - } - dest.putSamples(numOutput); - src.receiveSamples(numSrcSamples); - return numOutput; -} - - -TransposerBase::TransposerBase() -{ - numChannels = 0; - rate = 1.0f; -} - - -TransposerBase::~TransposerBase() -{ -} - - -void TransposerBase::setChannels(int channels) -{ - numChannels = channels; - resetRegisters(); -} - - -void TransposerBase::setRate(double newRate) -{ - rate = newRate; -} - - -// static factory function -TransposerBase *TransposerBase::newInstance() -{ -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - // Notice: For integer arithmetics support only linear algorithm (due to simplest calculus) - return ::new InterpolateLinearInteger; -#else - switch (algorithm) - { - case LINEAR: - return new InterpolateLinearFloat; - - case CUBIC: - return new InterpolateCubic; - - case SHANNON: - return new InterpolateShannon; - - default: - assert(false); - return NULL; - } -#endif -} diff --git a/externals/soundtouch/RateTransposer.h b/externals/soundtouch/RateTransposer.h deleted file mode 100644 index 8d0eab82f..000000000 --- a/externals/soundtouch/RateTransposer.h +++ /dev/null @@ -1,179 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation -/// together with anti-alias filtering (first order interpolation with anti- -/// alias filtering should be quite adequate for this application). -/// -/// Use either of the derived classes of 'RateTransposerInteger' or -/// 'RateTransposerFloat' for corresponding integer/floating point tranposing -/// algorithm implementation. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 RateTransposer_H -#define RateTransposer_H - -#include -#include "AAFilter.h" -#include "FIFOSamplePipe.h" -#include "FIFOSampleBuffer.h" - -#include "STTypes.h" - -namespace soundtouch -{ - -/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc) -class TransposerBase -{ -public: - enum ALGORITHM { - LINEAR = 0, - CUBIC, - SHANNON - }; - -protected: - virtual void resetRegisters() = 0; - - virtual int transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - int &srcSamples) = 0; - virtual int transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - int &srcSamples) = 0; - virtual int transposeMulti(SAMPLETYPE *dest, - const SAMPLETYPE *src, - int &srcSamples) = 0; - - static ALGORITHM algorithm; - -public: - double rate; - int numChannels; - - TransposerBase(); - virtual ~TransposerBase(); - - virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src); - virtual void setRate(double newRate); - virtual void setChannels(int channels); - - // static factory function - static TransposerBase *newInstance(); - - // static function to set interpolation algorithm - static void setAlgorithm(ALGORITHM a); -}; - - -/// A common linear samplerate transposer class. -/// -class RateTransposer : public FIFOProcessor -{ -protected: - /// Anti-alias filter object - AAFilter *pAAFilter; - TransposerBase *pTransposer; - - /// Buffer for collecting samples to feed the anti-alias filter between - /// two batches - FIFOSampleBuffer inputBuffer; - - /// Buffer for keeping samples between transposing & anti-alias filter - FIFOSampleBuffer midBuffer; - - /// Output sample buffer - FIFOSampleBuffer outputBuffer; - - bool bUseAAFilter; - - - /// Transposes sample rate by applying anti-alias filter to prevent folding. - /// Returns amount of samples returned in the "dest" buffer. - /// The maximum amount of samples that can be returned at a time is set by - /// the 'set_returnBuffer_size' function. - void processSamples(const SAMPLETYPE *src, - uint numSamples); - -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(); - - /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable - void enableAAFilter(bool newMode); - - /// Returns nonzero if anti-alias filter is enabled. - bool isAAFilterEnabled() const; - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(double newRate); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(int channels); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - void putSamples(const SAMPLETYPE *samples, uint numSamples); - - /// Clears all the samples in the object - void clear(); - - /// Returns nonzero if there aren't any samples available for outputting. - int isEmpty() const; -}; - -} - -#endif diff --git a/externals/soundtouch/STTypes.h b/externals/soundtouch/STTypes.h deleted file mode 100644 index 6803f474f..000000000 --- a/externals/soundtouch/STTypes.h +++ /dev/null @@ -1,185 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Common type definitions for SoundTouch audio processing library. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 STTypes_H -#define STTypes_H - -typedef unsigned int uint; -typedef unsigned long ulong; - -// Patch for MinGW: on Win64 long is 32-bit -#ifdef _WIN64 - typedef unsigned long long ulongptr; -#else - typedef ulong ulongptr; -#endif - - -// Helper macro for aligning pointer up to next 16-byte boundary -#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 ) - - -#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" -#endif - - -namespace soundtouch -{ - /// Activate these undef's to overrule the possible sampletype - /// setting inherited from some other header file: - #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 - /// purposes; output should be same with either routines, yet disabling - /// the dedicated mono/stereo processing routines will result in slower - /// runtime performance so recommendation is to keep this off. - // #define USE_MULTICH_ALWAYS - - #if (defined(__SOFTFP__)) - // 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 - #define SOUNDTOUCH_INTEGER_SAMPLES 1 - #endif - - #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES) - - /// Choose either 32bit floating point or 16bit integer sampletype - /// by choosing one of the following defines, unless this selection - /// has already been done in some other file. - //// - /// Notes: - /// - In Windows environment, choose the sample format with the - /// following defines. - /// - In GNU environment, the floating point samples are used by - /// default, but integer samples can be chosen by giving the - /// following switch to the configure script: - /// ./configure --enable-integer-samples - /// 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 - - #endif - - #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64) - /// Define this to allow X86-specific assembler/intrinsic optimizations. - /// Notice that library contains also usual C++ versions of each of these - /// these routines, so if you're having difficulties getting the optimized - /// routines compiled for whatever reason, you may disable these optimizations - /// to make the library compile. - - //#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: - /// ./configure --disable-x86-optimizations - /// ./configure --enable-x86-optimizations=no - #ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS - #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS - #endif - #else - /// Always disable optimizations when not using a x86 systems. - #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS - - #endif - - // If defined, allows the SIMD-optimized routines to take minor shortcuts - // for improved performance. Undefine to require faithfully similar SIMD - // calculations as in normal C implementation. - #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 - - - #ifdef SOUNDTOUCH_INTEGER_SAMPLES - // 16bit integer sample type - typedef short SAMPLETYPE; - // data type for sample accumulation: Use 32bit integer to prevent overflows - typedef long LONG_SAMPLETYPE; - - #ifdef SOUNDTOUCH_FLOAT_SAMPLES - // check that only one sample type is defined - #error "conflicting sample types defined" - #endif // SOUNDTOUCH_FLOAT_SAMPLES - - #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS - // Allow MMX optimizations - #define SOUNDTOUCH_ALLOW_MMX 1 - #endif - - #else - - // floating point samples - typedef float SAMPLETYPE; - // data type for sample accumulation: Use double to utilize full precision. - typedef double LONG_SAMPLETYPE; - - #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS - // Allow SSE optimizations - #define SOUNDTOUCH_ALLOW_SSE 1 - #endif - - #endif // SOUNDTOUCH_INTEGER_SAMPLES - -}; - -// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: - #define ST_NO_EXCEPTION_HANDLING 1 -#ifdef ST_NO_EXCEPTION_HANDLING - // Exceptions disabled. Throw asserts instead if enabled. - #include - #define ST_THROW_RT_ERROR(x) {assert((const char *)x);} -#else - // use c++ standard exceptions - #include - #include - #define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);} -#endif - -// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" -// parameter setting crosses from value <1 to >=1 or vice versa during processing. -// Default is off as such crossover is untypical case and involves a slight sound -// quality compromise. -//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1 - -#endif diff --git a/externals/soundtouch/SoundTouch.cpp b/externals/soundtouch/SoundTouch.cpp deleted file mode 100644 index 2c715e20a..000000000 --- a/externals/soundtouch/SoundTouch.cpp +++ /dev/null @@ -1,526 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 -#include -#include - -#include "SoundTouch.h" -#include "TDStretch.h" -#include "RateTransposer.h" -#include "cpu_detect.h" - -using namespace soundtouch; - -/// test if two floating point numbers are equal -#define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10) - - -/// Print library version string for autoconf -extern "C" void soundtouch_ac_test() -{ - printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); -} - - -SoundTouch::SoundTouch() -{ - // Initialize rate transposer and tempo changer instances - - pRateTransposer = new RateTransposer(); - pTDStretch = TDStretch::newInstance(); - - setOutPipe(pTDStretch); - - rate = tempo = 0; - - virtualPitch = - virtualRate = - virtualTempo = 1.0; - - calcEffectiveRateAndTempo(); - - samplesExpectedOut = 0; - samplesOutput = 0; - - channels = 0; - bSrateSet = false; -} - - - -SoundTouch::~SoundTouch() -{ - delete pRateTransposer; - delete pTDStretch; -} - - - -/// Get SoundTouch library version string -const char *SoundTouch::getVersionString() -{ - static const char *_version = SOUNDTOUCH_VERSION; - - return _version; -} - - -/// Get SoundTouch library version Id -uint SoundTouch::getVersionId() -{ - return SOUNDTOUCH_VERSION_ID; -} - - -// 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; - }*/ - 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) -{ - virtualRate = newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new rate control value as a difference in percents compared -// to the original rate (-50 .. +100 %) -void SoundTouch::setRateChange(double newRate) -{ - virtualRate = 1.0 + 0.01 * newRate; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value. Normal tempo = 1.0, smaller values -// represent slower tempo, larger faster tempo. -void SoundTouch::setTempo(double newTempo) -{ - virtualTempo = newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new tempo control value as a difference in percents compared -// to the original tempo (-50 .. +100 %) -void SoundTouch::setTempoChange(double newTempo) -{ - virtualTempo = 1.0 + 0.01 * newTempo; - calcEffectiveRateAndTempo(); -} - - - -// Sets new pitch control value. Original pitch = 1.0, smaller values -// represent lower pitches, larger values higher pitch. -void SoundTouch::setPitch(double newPitch) -{ - virtualPitch = newPitch; - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in octaves compared to the original pitch -// (-1.00 .. +1.00) -void SoundTouch::setPitchOctaves(double newPitch) -{ - virtualPitch = exp(0.69314718056 * newPitch); - calcEffectiveRateAndTempo(); -} - - - -// Sets pitch change in semi-tones compared to the original pitch -// (-12 .. +12) -void SoundTouch::setPitchSemiTones(int newPitch) -{ - setPitchOctaves((double)newPitch / 12.0); -} - - - -void SoundTouch::setPitchSemiTones(double newPitch) -{ - setPitchOctaves(newPitch / 12.0); -} - - -// Calculates 'effective' rate and tempo values from the -// nominal control values. -void SoundTouch::calcEffectiveRateAndTempo() -{ - double oldTempo = tempo; - double oldRate = rate; - - tempo = virtualTempo / virtualPitch; - rate = virtualPitch * virtualRate; - - if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); - if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); - -#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER - if (rate <= 1.0f) - { - if (output != pTDStretch) - { - FIFOSamplePipe *tempoOut; - - assert(output == pRateTransposer); - // move samples in the current output buffer to the output of pTDStretch - tempoOut = pTDStretch->getOutput(); - tempoOut->moveSamples(*output); - // move samples in pitch transposer's store buffer to tempo changer's input - // deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore()); - - output = pTDStretch; - } - } - else -#endif - { - if (output != pRateTransposer) - { - FIFOSamplePipe *transOut; - - assert(output == pTDStretch); - // move samples in the current output buffer to the output of pRateTransposer - transOut = pRateTransposer->getOutput(); - transOut->moveSamples(*output); - // move samples in tempo changer's input to pitch transposer's input - pRateTransposer->moveSamples(*pTDStretch->getInput()); - - output = pRateTransposer; - } - } -} - - -// 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); -} - - -// Adds 'numSamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) -{ - if (bSrateSet == false) - { - ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined"); - } - else if (channels == 0) - { - 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); - -#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER - if (rate <= 1.0f) - { - // transpose the rate down, output the transposed sound to tempo changer buffer - assert(output == pTDStretch); - pRateTransposer->putSamples(samples, nSamples); - pTDStretch->moveSamples(*pRateTransposer); - } - else -#endif - { - // evaluate the tempo changer, then transpose the rate up, - assert(output == pRateTransposer); - pTDStretch->putSamples(samples, nSamples); - pRateTransposer->moveSamples(*pTDStretch); - } -} - - -// Flushes the last samples from the processing pipeline to the output. -// Clears also the internal processing buffers. -// -// Note: This function is meant for extracting the last samples of a sound -// stream. This function may introduce additional blank samples in the end -// of the sound stream, and thus it's not recommended to call this function -// in the middle of a sound stream. -void SoundTouch::flush() -{ - int i; - int numStillExpected; - SAMPLETYPE *buff = new SAMPLETYPE[128 * channels]; - - // how many samples are still expected to output - numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput); - - 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); - } - - adjustAmountOfSamples(numStillExpected); - - delete[] buff; - - // Clear input buffers - // pRateTransposer->clearInput(); - pTDStretch->clearInput(); - // yet leave the output intouched as that's where the - // flushed samples are! -} - - -// Changes a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -bool SoundTouch::setSetting(int settingId, int value) -{ - int sampleRate, sequenceMs, seekWindowMs, overlapMs; - - // read current tdstretch routine parameters - pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - // enables / disabless anti-alias filter - pRateTransposer->enableAAFilter((value != 0) ? true : false); - return true; - - case SETTING_AA_FILTER_LENGTH : - // sets anti-alias filter length - pRateTransposer->getAAFilter()->setLength(value); - return true; - - case SETTING_USE_QUICKSEEK : - // enables / disables tempo routine quick seeking algorithm - pTDStretch->enableQuickSeek((value != 0) ? true : false); - return true; - - case SETTING_SEQUENCE_MS: - // change time-stretch sequence duration parameter - pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); - return true; - - case SETTING_SEEKWINDOW_MS: - // change time-stretch seek window length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); - return true; - - case SETTING_OVERLAP_MS: - // change time-stretch overlap length parameter - pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); - return true; - - default : - return false; - } -} - - -// Reads a setting controlling the processing system behaviour. See the -// 'SETTING_...' defines for available setting ID's. -// -// Returns the setting value. -int SoundTouch::getSetting(int settingId) const -{ - int temp; - - switch (settingId) - { - case SETTING_USE_AA_FILTER : - return (uint)pRateTransposer->isAAFilterEnabled(); - - case SETTING_AA_FILTER_LENGTH : - return pRateTransposer->getAAFilter()->getLength(); - - case SETTING_USE_QUICKSEEK : - return (uint) pTDStretch->isQuickSeekEnabled(); - - case SETTING_SEQUENCE_MS: - pTDStretch->getParameters(NULL, &temp, NULL, NULL); - return temp; - - case SETTING_SEEKWINDOW_MS: - pTDStretch->getParameters(NULL, NULL, &temp, NULL); - return temp; - - case SETTING_OVERLAP_MS: - pTDStretch->getParameters(NULL, NULL, NULL, &temp); - return temp; - - case SETTING_NOMINAL_INPUT_SEQUENCE : - return pTDStretch->getInputSampleReq(); - - case SETTING_NOMINAL_OUTPUT_SEQUENCE : - return pTDStretch->getOutputBatchSize(); - - default : - return 0; - } -} - - -// Clears all the samples in the object's output and internal processing -// buffers. -void SoundTouch::clear() -{ - samplesExpectedOut = 0; - pRateTransposer->clear(); - pTDStretch->clear(); -} - - - -/// Returns number of samples currently unprocessed. -uint SoundTouch::numUnprocessedSamples() const -{ - FIFOSamplePipe * psp; - if (pTDStretch) - { - psp = pTDStretch->getInput(); - if (psp) - { - return psp->numSamples(); - } - } - return 0; -} - - - -/// 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. -/// -/// \return Number of samples returned. -uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples) -{ - uint ret = FIFOProcessor::receiveSamples(output, maxSamples); - samplesOutput += (long)ret; - return ret; -} - - -/// Adjusts book-keeping so that given number of samples are removed from beginning of the -/// sample buffer without copying them anywhere. -/// -/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly -/// with 'ptrBegin' function. -uint SoundTouch::receiveSamples(uint maxSamples) -{ - uint ret = FIFOProcessor::receiveSamples(maxSamples); - samplesOutput += (long)ret; - return ret; -} diff --git a/externals/soundtouch/SoundTouch.h b/externals/soundtouch/SoundTouch.h deleted file mode 100644 index b03855eea..000000000 --- a/externals/soundtouch/SoundTouch.h +++ /dev/null @@ -1,301 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -/// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. -/// -/// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set -/// desired tempo/pitch/rate settings with the corresponding functions. -/// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The -/// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read -/// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for -/// processing, then they carry out the processing step and consequently -/// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain -/// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct -/// relationship with the amount of previously input samples. -/// -/// - The tempo/pitch/rate control parameters can be altered during processing. -/// Please notice though that they aren't currently protected by semaphores, -/// so in multi-thread application external semaphore protection may be -/// required. -/// -/// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control -/// 'pitch' (change pitch but maintain tempo) is produced by a combination of -/// combining the two other controls. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 SoundTouch_H -#define SoundTouch_H - -#include "FIFOSamplePipe.h" -#include "STTypes.h" - -namespace soundtouch -{ - -/// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.9.2" - -/// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID (10902) - -// -// Available setting IDs for the 'setSetting' & 'get_setting' functions: - -/// Enable/disable anti-alias filter in pitch transposer (0 = disable) -#define SETTING_USE_AA_FILTER 0 - -/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) -#define SETTING_AA_FILTER_LENGTH 1 - -/// Enable/disable quick seeking algorithm in tempo changer routine -/// (enabling quick seeking lowers CPU utilization but causes a minor sound -/// quality compromising) -#define SETTING_USE_QUICKSEEK 2 - -/// Time-stretch algorithm single processing sequence length in milliseconds. This determines -/// to how long sequences the original sound is chopped in the time-stretch algorithm. -/// See "STTypes.h" or README for more information. -#define SETTING_SEQUENCE_MS 3 - -/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the -/// best possible overlapping location. This determines from how wide window the algorithm -/// may look for an optimal joining location when mixing the sound sequences back together. -/// See "STTypes.h" or README for more information. -#define SETTING_SEEKWINDOW_MS 4 - -/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences -/// are mixed back together, to form a continuous sound stream, this parameter defines over -/// how long period the two consecutive sequences are let to overlap each other. -/// See "STTypes.h" or README for more information. -#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. -/// -/// 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 -/// tempo/pitch/rate/samplerate settings. -#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 -/// tempo/pitch/rate/samplerate settings. -#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 - -class SoundTouch : public FIFOProcessor -{ -private: - /// Rate transposer class instance - class RateTransposer *pRateTransposer; - - /// Time-stretch class instance - class TDStretch *pTDStretch; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - double virtualRate; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - double virtualTempo; - - /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. - double virtualPitch; - - /// Flag: Has sample rate been set? - bool bSrateSet; - - /// Accumulator for how many samples in total will be expected as output vs. samples put in, - /// considering current processing settings. - double samplesExpectedOut; - - /// Accumulator for how many samples in total have been read out from the processing so far - long samplesOutput; - - /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and - /// 'virtualPitch' parameters. - void calcEffectiveRateAndTempo(); - -protected : - /// Number of channels - uint channels; - - /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - double rate; - - /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' - double tempo; - -public: - SoundTouch(); - virtual ~SoundTouch(); - - /// Get SoundTouch library version string - static const char *getVersionString(); - - /// Get SoundTouch library version Id - static uint getVersionId(); - - /// Sets new rate control value. Normal rate = 1.0, smaller values - /// represent slower rate, larger faster rates. - void setRate(double newRate); - - /// Sets new tempo control value. Normal tempo = 1.0, smaller values - /// represent slower tempo, larger faster tempo. - void setTempo(double newTempo); - - /// Sets new rate control value as a difference in percents compared - /// to the original rate (-50 .. +100 %) - void setRateChange(double newRate); - - /// Sets new tempo control value as a difference in percents compared - /// to the original tempo (-50 .. +100 %) - void setTempoChange(double newTempo); - - /// Sets new pitch control value. Original pitch = 1.0, smaller values - /// represent lower pitches, larger values higher pitch. - void setPitch(double newPitch); - - /// Sets pitch change in octaves compared to the original pitch - /// (-1.00 .. +1.00) - void setPitchOctaves(double newPitch); - - /// Sets pitch change in semi-tones compared to the original pitch - /// (-12 .. +12) - void setPitchSemiTones(int newPitch); - void setPitchSemiTones(double newPitch); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(uint numChannels); - - /// Sets sample rate. - void setSampleRate(uint srate); - - /// Flushes the last samples from the processing pipeline to the output. - /// Clears also the internal processing buffers. - // - /// Note: This function is meant for extracting the last samples of a sound - /// stream. This function may introduce additional blank samples in the end - /// of the sound stream, and thus it's not recommended to call this function - /// in the middle of a sound stream. - void flush(); - - /// Adds 'numSamples' pcs of samples from the 'samples' memory position into - /// the input of the object. Notice that sample rate _has_to_ be set before - /// calling this function, otherwise throws a runtime_error exception. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Pointer to sample buffer. - uint numSamples ///< Number of samples in buffer. Notice - ///< that in case of stereo-sound a single sample - ///< contains data for both channels. - ); - - /// 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. - /// - /// \return Number of samples returned. - virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. - uint maxSamples ///< How many samples to receive at max. - ); - - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. - /// - /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly - /// with 'ptrBegin' function. - virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. - ); - - /// Clears all the samples in the object's output and internal processing - /// buffers. - virtual void clear(); - - /// 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 - bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. - int value ///< New setting value. - ); - - /// Reads a setting controlling the processing system behaviour. See the - /// 'SETTING_...' defines for available setting ID's. - /// - /// \return the setting value. - int getSetting(int settingId ///< Setting ID number, see SETTING_... defines. - ) const; - - /// Returns number of samples currently unprocessed. - virtual uint numUnprocessedSamples() const; - - - /// Other handy functions that are implemented in the ancestor classes (see - /// classes 'FIFOProcessor' and 'FIFOSamplePipe') - /// - /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. - /// - numSamples() : Get number of 'ready' samples that can be received with - /// function 'receiveSamples()' - /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. - /// - clear() : Clears all samples from ready/processing buffers. -}; - -} -#endif diff --git a/externals/soundtouch/SoundTouch.vcxproj b/externals/soundtouch/SoundTouch.vcxproj deleted file mode 100644 index 17590bd2e..000000000 --- a/externals/soundtouch/SoundTouch.vcxproj +++ /dev/null @@ -1,75 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - {EC082900-B4D8-42E9-9663-77F02F6936AE} - - - - StaticLibrary - v140 - Unicode - - - true - - - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/externals/soundtouch/TDStretch.cpp b/externals/soundtouch/TDStretch.cpp deleted file mode 100644 index d030558b4..000000000 --- a/externals/soundtouch/TDStretch.cpp +++ /dev/null @@ -1,1078 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// 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' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 -#include -#include - -#include "STTypes.h" -#include "cpu_detect.h" -#include "TDStretch.h" - -using namespace soundtouch; - -#define max(x, y) (((x) > (y)) ? (x) : (y)) - - -/***************************************************************************** - * - * Constant definitions - * - *****************************************************************************/ - -// Table for the hierarchical mixing position seeking algorithm -const short _scanOffsets[5][24]={ - { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, - 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, - {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - { 121, 114, 97, 114, 98, 105, 108, 32, 104, 99, 117, 111, - 116, 100, 110, 117, 111, 115, 0, 0, 0, 0, 0, 0}}; - -/***************************************************************************** - * - * Implementation of the class 'TDStretch' - * - *****************************************************************************/ - - -TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) -{ - bQuickSeek = false; - channels = 2; - - pMidBuffer = NULL; - pMidBufferUnaligned = NULL; - overlapLength = 0; - - bAutoSeqSetting = true; - bAutoSeekSetting = true; - - maxnorm = 0; - maxnormf = 1e8; - - skipFract = 0; - - tempo = 1.0f; - setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); - setTempo(1.0f); - - clear(); -} - - - -TDStretch::~TDStretch() -{ - delete[] pMidBufferUnaligned; -} - - - -// Sets routine control parameters. These control are certain time constants -// defining how the sound is stretched to the desired duration. -// -// 'sampleRate' = sample rate of the sound -// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) -// 'seekwindowMS' = seeking window length for scanning the best overlapping -// position (default = 28 ms) -// 'overlapMS' = overlapping length (default = 12 ms) - -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 (aSequenceMS > 0) - { - this->sequenceMs = aSequenceMS; - bAutoSeqSetting = false; - } - else if (aSequenceMS == 0) - { - // if zero, use automatic setting - bAutoSeqSetting = true; - } - - if (aSeekWindowMS > 0) - { - this->seekWindowMs = aSeekWindowMS; - bAutoSeekSetting = false; - } - else if (aSeekWindowMS == 0) - { - // if zero, use automatic setting - bAutoSeekSetting = true; - } - - calcSeqParameters(); - - calculateOverlapLength(overlapMs); - - // set tempo to recalculate 'sampleReq' - setTempo(tempo); -} - - - -/// Get routine control parameters, see setParameters() function. -/// Any of the parameters to this function can be NULL, in such case corresponding parameter -/// value isn't returned. -void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const -{ - if (pSampleRate) - { - *pSampleRate = sampleRate; - } - - if (pSequenceMs) - { - *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN) : sequenceMs; - } - - if (pSeekWindowMs) - { - *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN) : seekWindowMs; - } - - if (pOverlapMs) - { - *pOverlapMs = overlapMs; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'pInput' -void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const -{ - int i; - SAMPLETYPE m1, m2; - - m1 = (SAMPLETYPE)0; - m2 = (SAMPLETYPE)overlapLength; - - for (i = 0; i < overlapLength ; i ++) - { - pOutput[i] = (pInput[i] * m1 + pMidBuffer[i] * m2 ) / overlapLength; - m1 += 1; - m2 -= 1; - } -} - - - -void TDStretch::clearMidBuffer() -{ - memset(pMidBuffer, 0, channels * sizeof(SAMPLETYPE) * overlapLength); -} - - -void TDStretch::clearInput() -{ - inputBuffer.clear(); - clearMidBuffer(); -} - - -// Clears the sample buffers -void TDStretch::clear() -{ - outputBuffer.clear(); - clearInput(); -} - - - -// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero -// to enable -void TDStretch::enableQuickSeek(bool enable) -{ - bQuickSeek = enable; -} - - -// Returns nonzero if the quick seeking algorithm is enabled. -bool TDStretch::isQuickSeekEnabled() const -{ - return bQuickSeek; -} - - -// Seeks for the optimal overlap-mixing position. -int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) -{ - if (bQuickSeek) - { - return seekBestOverlapPositionQuick(refPos); - } - else - { - return seekBestOverlapPositionFull(refPos); - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position -// of 'ovlPos'. -inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const -{ -#ifndef USE_MULTICH_ALWAYS - if (channels == 1) - { - // mono sound. - overlapMono(pOutput, pInput + ovlPos); - } - else if (channels == 2) - { - // stereo sound - overlapStereo(pOutput, pInput + 2 * ovlPos); - } - else -#endif // USE_MULTICH_ALWAYS - { - assert(channels > 0); - overlapMulti(pOutput, pInput + channels * ovlPos); - } -} - - -// Seeks for the optimal overlap-mixing position. The 'stereo' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) -{ - int bestOffs; - double bestCorr; - int i; - double norm; - - bestCorr = FLT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - bestCorr = calcCrossCorr(refPos, pMidBuffer, norm); - - #pragma omp parallel for - for (i = 1; i < seekLength; i ++) - { - double corr; - // Calculates correlation value for the mixing position corresponding to 'i' -#ifdef _OPENMP - // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't - // iterate the loop in sequential order - corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm); -#else - // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same - // as "calcCrossCorr", but saves time by reusing & updating previously stored - // "norm" value - corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm); -#endif - // heuristic rule to slightly favour values close to mid of the range - double tmp = (double)(2 * i - seekLength) / (double)seekLength; - corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp)); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - // For optimal performance, enter critical section only in case that best value found. - // in such case repeat 'if' condition as it's possible that parallel execution may have - // updated the bestCorr value in the mean time - #pragma omp critical - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = i; - } - } - } - -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - adaptNormalizer(); -#endif - - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Quick seek algorithm for improved runtime-performance: First roughly scans through the -// correlation area, and then scan surroundings of two best preliminary correlation candidates -// with improved precision -// -// Based on testing: -// - This algorithm gives on average 99% as good match as the full algorith -// - 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 -int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) -{ -#define _MIN(a, b) (((a) < (b)) ? (a) : (b)) -#define SCANSTEP 16 -#define SCANWIND 8 - - int bestOffs; - int i; - int bestOffs2; - float bestCorr, corr; - float bestCorr2; - double norm; - - // 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; - - // 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 - // increase possibility of ideal match. - // - // Begin from "SCANSTEP" instead of SCANWIND to make the calculation - // catch the 'middlepoint' of seekLength vector as that's the a-priori - // expected best match position - // - // Roughly: - // - 15% of cases find best result directly on the first round, - // - 75% cases find better match on 2nd round around the best match from 1st round - // - 10% cases find better match on 2nd round around the 2nd-best-match from 1st round - for (i = SCANSTEP; i < seekLength - SCANWIND - 1; i += SCANSTEP) - { - // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm); - // heuristic rule to slightly favour values close to mid of the seek range - float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength; - corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp)); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - // found new best match. keep the previous best as 2nd best match - bestCorr2 = bestCorr; - bestOffs2 = bestOffs; - bestCorr = corr; - bestOffs = i; - } - else if (corr > bestCorr2) - { - // not new best, but still new 2nd best match - bestCorr2 = corr; - bestOffs2 = i; - } - } - - // Scans surroundings of the found best match with small stepping - int end = _MIN(bestOffs + SCANWIND + 1, seekLength); - for (i = bestOffs - SCANWIND; i < end; i++) - { - if (i == bestOffs) continue; // this offset already calculated, thus skip - - // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm); - // heuristic rule to slightly favour values close to mid of the range - float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength; - corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp)); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = i; - best = 1; - } - } - - // Scans surroundings of the 2nd best match with small stepping - end = _MIN(bestOffs2 + SCANWIND + 1, seekLength); - for (i = bestOffs2 - SCANWIND; i < end; i++) - { - if (i == bestOffs2) continue; // this offset already calculated, thus skip - - // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm); - // heuristic rule to slightly favour values close to mid of the range - float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength; - corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp)); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = i; - best = 2; - } - } - - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - adaptNormalizer(); -#endif - - return bestOffs; -} - - - - -/// For integer algorithm: adapt normalization factor divider with music so that -/// it'll not be pessimistically restrictive that can degrade quality on quieter sections -/// yet won't cause integer overflows either -void TDStretch::adaptNormalizer() -{ - // Do not adapt normalizer over too silent sequences to avoid averaging filter depleting to - // too low values during pauses in music - if ((maxnorm > 1000) || (maxnormf > 40000000)) - { - //norm averaging filter - maxnormf = 0.9f * maxnormf + 0.1f * (float)maxnorm; - - if ((maxnorm > 800000000) && (overlapDividerBitsNorm < 16)) - { - // large values, so increase divider - overlapDividerBitsNorm++; - if (maxnorm > 1600000000) overlapDividerBitsNorm++; // extra large value => extra increase - } - else if ((maxnormf < 1000000) && (overlapDividerBitsNorm > 0)) - { - // extra small values, decrease divider - overlapDividerBitsNorm--; - } - } - - maxnorm = 0; -} - - -/// clear cross correlation routine state if necessary -void TDStretch::clearCrossCorrState() -{ - // default implementation is empty. -} - - -/// Calculates processing sequence length according to tempo setting -void TDStretch::calcSeqParameters() -{ - // Adjust tempo param according to tempo, so that variating processing sequence length is used - // at varius tempo settings, between the given low...top limits - #define AUTOSEQ_TEMPO_LOW 0.5 // auto setting low tempo range (-50%) - #define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%) - - // sequence-ms setting values at above low & top tempo - #define AUTOSEQ_AT_MIN 125.0 - #define AUTOSEQ_AT_MAX 50.0 - #define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) - #define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW)) - - // seek-window-ms setting values at above low & top tempoq - #define AUTOSEEK_AT_MIN 25.0 - #define AUTOSEEK_AT_MAX 15.0 - #define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) - #define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW)) - - #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x))) - - double seq, seek; - - if (bAutoSeqSetting) - { - seq = AUTOSEQ_C + AUTOSEQ_K * tempo; - seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN); - sequenceMs = (int)(seq + 0.5); - } - - if (bAutoSeekSetting) - { - seek = AUTOSEEK_C + AUTOSEEK_K * tempo; - seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN); - seekWindowMs = (int)(seek + 0.5); - } - - // Update seek window lengths - seekWindowLength = (sampleRate * sequenceMs) / 1000; - if (seekWindowLength < 2 * overlapLength) - { - seekWindowLength = 2 * overlapLength; - } - seekLength = (sampleRate * seekWindowMs) / 1000; -} - - - -// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower -// tempo, larger faster tempo. -void TDStretch::setTempo(double newTempo) -{ - int intskip; - - tempo = newTempo; - - // Calculate new sequence duration - calcSeqParameters(); - - // Calculate ideal skip length (according to tempo value) - nominalSkip = tempo * (seekWindowLength - overlapLength); - intskip = (int)(nominalSkip + 0.5); - - // Calculate how many samples are needed in the 'inputBuffer' to - // process another batch of samples - //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2; - sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength; -} - - - -// 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); - - channels = numChannels; - inputBuffer.setChannels(channels); - outputBuffer.setChannels(channels); - - // re-init overlap/buffer - overlapLength=0; - setParameters(sampleRate); -} - - -// nominal tempo, no need for processing, just pass the samples through -// to outputBuffer -/* -void TDStretch::processNominalTempo() -{ - assert(tempo == 1.0f); - - if (bMidBufferDirty) - { - // If there are samples in pMidBuffer waiting for overlapping, - // do a single sliding overlapping with them in order to prevent a - // clicking distortion in the output sound - if (inputBuffer.numSamples() < overlapLength) - { - // wait until we've got overlapLength input samples - return; - } - // Mix the samples in the beginning of 'inputBuffer' with the - // samples in 'midBuffer' using sliding overlapping - overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); - outputBuffer.putSamples(overlapLength); - inputBuffer.receiveSamples(overlapLength); - clearMidBuffer(); - // now we've caught the nominal sample flow and may switch to - // bypass mode - } - - // Simply bypass samples from input to output - outputBuffer.moveSamples(inputBuffer); -} -*/ - - -// Processes as many processing frames of the samples 'inputBuffer', store -// the result into 'outputBuffer' -void TDStretch::processSamples() -{ - int ovlSkip, offset; - int temp; - - /* Removed this small optimization - can introduce a click to sound when tempo setting - crosses the nominal value - if (tempo == 1.0f) - { - // tempo not changed from the original, so bypass the processing - processNominalTempo(); - return; - } - */ - - // Process samples as long as there are enough samples in 'inputBuffer' - // 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); - - // ... 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)) - { - continue; // just in case, shouldn't really happen - } - - outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), (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), - channels * sizeof(SAMPLETYPE) * overlapLength); - - // Remove the processed samples from the input buffer. Update - // the difference between integer & nominal skip step to 'skipFract' - // in order to prevent the error from accumulating over time. - skipFract += nominalSkip; // real skip size - ovlSkip = (int)skipFract; // rounded to integer skip - skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip - inputBuffer.receiveSamples((uint)ovlSkip); - } -} - - -// Adds 'numsamples' pcs of samples from the 'samples' memory position into -// the input of the object. -void TDStretch::putSamples(const SAMPLETYPE *samples, uint nSamples) -{ - // Add the samples into the input buffer - inputBuffer.putSamples(samples, nSamples); - // Process the samples in input buffer - processSamples(); -} - - - -/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. -void TDStretch::acceptNewOverlapLength(int newOverlapLength) -{ - int prevOvl; - - assert(newOverlapLength >= 0); - prevOvl = overlapLength; - overlapLength = newOverlapLength; - - if (overlapLength > prevOvl) - { - delete[] pMidBufferUnaligned; - - pMidBufferUnaligned = new SAMPLETYPE[overlapLength * channels + 16 / sizeof(SAMPLETYPE)]; - // ensure that 'pMidBuffer' is aligned to 16 byte boundary for efficiency - pMidBuffer = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(pMidBufferUnaligned); - - clearMidBuffer(); - } -} - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * TDStretch::operator new(size_t s) -{ - // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"); - return newInstance(); -} - - -TDStretch * TDStretch::newInstance() -{ - uint uExtensions; - - uExtensions = detectCPUextensions(); - - // Check if MMX/SSE instruction set extensions supported by CPU - -#ifdef SOUNDTOUCH_ALLOW_MMX - // MMX routines available only with integer sample types - if (uExtensions & SUPPORT_MMX) - { - return ::new TDStretchMMX; - } - else -#endif // SOUNDTOUCH_ALLOW_MMX - - -#ifdef SOUNDTOUCH_ALLOW_SSE - if (uExtensions & SUPPORT_SSE) - { - // SSE support - return ::new TDStretchSSE; - } - else -#endif // SOUNDTOUCH_ALLOW_SSE - - { - // ISA optimizations not supported, use plain C version - return ::new TDStretch; - } -} - - -////////////////////////////////////////////////////////////////////////////// -// -// Integer arithmetics specific algorithm implementations. -// -////////////////////////////////////////////////////////////////////////////// - -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - -// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' -// version of the routine. -void TDStretch::overlapStereo(short *poutput, const short *input) const -{ - int i; - short temp; - int cnt2; - - for (i = 0; i < overlapLength ; i ++) - { - temp = (short)(overlapLength - i); - cnt2 = 2 * i; - poutput[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; - poutput[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Multi' -// version of the routine. -void TDStretch::overlapMulti(SAMPLETYPE *poutput, const SAMPLETYPE *input) const -{ - SAMPLETYPE m1=(SAMPLETYPE)0; - SAMPLETYPE m2; - int i=0; - - for (m2 = (SAMPLETYPE)overlapLength; m2; m2 --) - { - for (int c = 0; c < channels; c ++) - { - poutput[i] = (input[i] * m1 + pMidBuffer[i] * m2) / overlapLength; - i++; - } - - m1++; - } -} - -// Calculates the x having the closest 2^x value for the given value -static int _getClosest2Power(double value) -{ - return (int)(log(value) / log(2.0) + 0.5); -} - - -/// Calculates overlap period length in samples. -/// Integer version rounds overlap length to closest power of 2 -/// for a divide scaling operation. -void TDStretch::calculateOverlapLength(int aoverlapMs) -{ - int newOvl; - - assert(aoverlapMs >= 0); - - // calculate overlap length so that it's power of 2 - thus it's easy to do - // integer division by right-shifting. Term "-1" at end is to account for - // the extra most significatnt bit left unused in result by signed multiplication - overlapDividerBitsPure = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1; - if (overlapDividerBitsPure > 9) overlapDividerBitsPure = 9; - if (overlapDividerBitsPure < 3) overlapDividerBitsPure = 3; - newOvl = (int)pow(2.0, (int)overlapDividerBitsPure + 1); // +1 => account for -1 above - - acceptNewOverlapLength(newOvl); - - overlapDividerBitsNorm = overlapDividerBitsPure; - - // calculate sloping divider so that crosscorrelation operation won't - // overflow 32-bit register. Max. sum of the crosscorrelation sum without - // divider would be 2^30*(N^3-N)/3, where N = overlap length - slopingDivider = (newOvl * newOvl - 1) / 3; -} - - -double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, double &norm) -{ - long corr; - unsigned long lnorm; - int i; - - corr = lnorm = 0; - // Same routine for stereo and mono. For stereo, unroll loop for better - // efficiency and gives slightly better resolution against rounding. - // For mono it same routine, just unrolls loop by factor of 4 - for (i = 0; i < channels * overlapLength; i += 4) - { - corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow - corr += (mixingPos[i + 2] * compare[i + 2] + - mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBitsNorm; - lnorm += (mixingPos[i] * mixingPos[i] + - mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow - lnorm += (mixingPos[i + 2] * mixingPos[i + 2] + - mixingPos[i + 3] * mixingPos[i + 3]) >> overlapDividerBitsNorm; - } - - if (lnorm > maxnorm) - { - maxnorm = lnorm; - } - // Normalize result by dividing by sqrt(norm) - this step is easiest - // done using floating point operation - norm = (double)lnorm; - return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); -} - - -/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value -double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) -{ - long corr; - unsigned long lnorm; - int i; - - // cancel first normalizer tap from previous round - lnorm = 0; - for (i = 1; i <= channels; i ++) - { - lnorm -= (mixingPos[-i] * mixingPos[-i]) >> overlapDividerBitsNorm; - } - - corr = 0; - // Same routine for stereo and mono. For stereo, unroll loop for better - // efficiency and gives slightly better resolution against rounding. - // For mono it same routine, just unrolls loop by factor of 4 - for (i = 0; i < channels * overlapLength; i += 4) - { - corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow - corr += (mixingPos[i + 2] * compare[i + 2] + - mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBitsNorm; - } - - // update normalizer with last samples of this round - for (int j = 0; j < channels; j ++) - { - i --; - lnorm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBitsNorm; - } - - norm += (double)lnorm; - if (norm > maxnorm) - { - maxnorm = (unsigned long)norm; - } - - // Normalize result by dividing by sqrt(norm) - this step is easiest - // done using floating point operation - return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); -} - -#endif // SOUNDTOUCH_INTEGER_SAMPLES - -////////////////////////////////////////////////////////////////////////////// -// -// Floating point arithmetics specific algorithm implementations. -// - -#ifdef SOUNDTOUCH_FLOAT_SAMPLES - -// Overlaps samples in 'midBuffer' with the samples in 'pInput' -void TDStretch::overlapStereo(float *pOutput, const float *pInput) const -{ - int i; - float fScale; - float f1; - float f2; - - fScale = 1.0f / (float)overlapLength; - - f1 = 0; - f2 = 1.0f; - - for (i = 0; i < 2 * (int)overlapLength ; i += 2) - { - pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2; - pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2; - - f1 += fScale; - f2 -= fScale; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input'. -void TDStretch::overlapMulti(float *pOutput, const float *pInput) const -{ - int i; - float fScale; - float f1; - float f2; - - fScale = 1.0f / (float)overlapLength; - - f1 = 0; - f2 = 1.0f; - - i=0; - for (int i2 = 0; i2 < overlapLength; i2 ++) - { - // note: Could optimize this slightly by taking into account that always channels > 2 - for (int c = 0; c < channels; c ++) - { - pOutput[i] = pInput[i] * f1 + pMidBuffer[i] * f2; - i++; - } - f1 += fScale; - f2 -= fScale; - } -} - - -/// Calculates overlapInMsec period length in samples. -void TDStretch::calculateOverlapLength(int overlapInMsec) -{ - int newOvl; - - assert(overlapInMsec >= 0); - newOvl = (sampleRate * overlapInMsec) / 1000; - if (newOvl < 16) newOvl = 16; - - // must be divisible by 8 - newOvl -= newOvl % 8; - - acceptNewOverlapLength(newOvl); -} - - -/// Calculate cross-correlation -double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &anorm) -{ - double corr; - double norm; - int i; - - corr = norm = 0; - // Same routine for stereo and mono. For Stereo, unroll by factor of 2. - // For mono it's same routine yet unrollsd by factor of 4. - for (i = 0; i < channels * overlapLength; i += 4) - { - corr += mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]; - - norm += mixingPos[i] * mixingPos[i] + - mixingPos[i + 1] * mixingPos[i + 1]; - - // unroll the loop for better CPU efficiency: - corr += mixingPos[i + 2] * compare[i + 2] + - mixingPos[i + 3] * compare[i + 3]; - - norm += mixingPos[i + 2] * mixingPos[i + 2] + - mixingPos[i + 3] * mixingPos[i + 3]; - } - - anorm = norm; - return corr / sqrt((norm < 1e-9 ? 1.0 : norm)); -} - - -/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value -double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) -{ - double corr; - int i; - - corr = 0; - - // cancel first normalizer tap from previous round - for (i = 1; i <= channels; i ++) - { - norm -= mixingPos[-i] * mixingPos[-i]; - } - - // Same routine for stereo and mono. For Stereo, unroll by factor of 2. - // For mono it's same routine yet unrollsd by factor of 4. - for (i = 0; i < channels * overlapLength; i += 4) - { - corr += mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1] + - mixingPos[i + 2] * compare[i + 2] + - mixingPos[i + 3] * compare[i + 3]; - } - - // update normalizer with last samples of this round - for (int j = 0; j < channels; j ++) - { - i --; - norm += mixingPos[i] * mixingPos[i]; - } - - return corr / sqrt((norm < 1e-9 ? 1.0 : norm)); -} - - -#endif // SOUNDTOUCH_FLOAT_SAMPLES diff --git a/externals/soundtouch/TDStretch.h b/externals/soundtouch/TDStretch.h deleted file mode 100644 index e6d75aac1..000000000 --- a/externals/soundtouch/TDStretch.h +++ /dev/null @@ -1,281 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method -/// with several performance-increasing tweaks. -/// -/// Note : MMX/SSE optimized functions reside in separate, platform-specific files -/// 'mmx_optimized.cpp' and 'sse_optimized.cpp' -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 TDStretch_H -#define TDStretch_H - -#include -#include "STTypes.h" -#include "RateTransposer.h" -#include "FIFOSamplePipe.h" - -namespace soundtouch -{ - -/// Default values for sound processing parameters: -/// Notice that the default parameters are tuned for contemporary popular music -/// processing. For speech processing applications these parameters suit better: -/// #define DEFAULT_SEQUENCE_MS 40 -/// #define DEFAULT_SEEKWINDOW_MS 15 -/// #define DEFAULT_OVERLAP_MS 8 -/// - -/// Default length of a single processing sequence, in milliseconds. This determines to how -/// long sequences the original sound is chopped in the time-stretch algorithm. -/// -/// The larger this value is, the lesser sequences are used in processing. In principle -/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo -/// and vice versa. -/// -/// Increasing this value reduces computational burden & vice versa. -//#define DEFAULT_SEQUENCE_MS 40 -#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN - -/// Giving this value for the sequence length sets automatic parameter value -/// according to tempo setting (recommended) -#define USE_AUTO_SEQUENCE_LEN 0 - -/// Seeking window default length in milliseconds for algorithm that finds the best possible -/// overlapping location. This determines from how wide window the algorithm may look for an -/// optimal joining location when mixing the sound sequences back together. -/// -/// The bigger this window setting is, the higher the possibility to find a better mixing -/// position will become, but at the same time large values may cause a "drifting" artifact -/// because consequent sequences will be taken at more uneven intervals. -/// -/// If there's a disturbing artifact that sounds as if a constant frequency was drifting -/// around, try reducing this setting. -/// -/// Increasing this value increases computational burden & vice versa. -//#define DEFAULT_SEEKWINDOW_MS 15 -#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN - -/// Giving this value for the seek window length sets automatic parameter value -/// according to tempo setting (recommended) -#define USE_AUTO_SEEKWINDOW_LEN 0 - -/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, -/// to form a continuous sound stream, this parameter defines over how long period the two -/// consecutive sequences are let to overlap each other. -/// -/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting -/// by a large amount, you might wish to try a smaller value on this. -/// -/// Increasing this value increases computational burden & vice versa. -#define DEFAULT_OVERLAP_MS 8 - - -/// Class that does the time-stretch (tempo change) effect for the processed -/// sound. -class TDStretch : public FIFOProcessor -{ -protected: - int channels; - int sampleReq; - - int overlapLength; - int seekLength; - int seekWindowLength; - int overlapDividerBitsNorm; - int overlapDividerBitsPure; - int slopingDivider; - int sampleRate; - int sequenceMs; - int seekWindowMs; - int overlapMs; - - unsigned long maxnorm; - float maxnormf; - - double tempo; - double nominalSkip; - double skipFract; - - bool bQuickSeek; - bool bAutoSeqSetting; - bool bAutoSeekSetting; - - SAMPLETYPE *pMidBuffer; - SAMPLETYPE *pMidBufferUnaligned; - - FIFOSampleBuffer outputBuffer; - FIFOSampleBuffer inputBuffer; - - void acceptNewOverlapLength(int newOverlapLength); - - virtual void clearCrossCorrState(); - void calculateOverlapLength(int overlapMs); - - virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); - virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); - - virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos); - virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); - virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos); - - virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; - virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; - virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const; - - void clearMidBuffer(); - void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; - - 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 - /// the 'set_returnBuffer_size' function. - void processSamples(); - -public: - TDStretch(); - virtual ~TDStretch(); - - /// Operator 'new' is overloaded so that it automatically creates a suitable instance - /// depending on if we've a MMX/SSE/etc-capable CPU available or not. - 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 feature set depending on if the CPU - /// supports MMX/SSE/etc extensions. - static TDStretch *newInstance(); - - /// Returns the output buffer object - FIFOSamplePipe *getOutput() { return &outputBuffer; }; - - /// Returns the input buffer object - FIFOSamplePipe *getInput() { return &inputBuffer; }; - - /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower - /// tempo, larger faster tempo. - void setTempo(double newTempo); - - /// Returns nonzero if there aren't any samples available for outputting. - virtual void clear(); - - /// Clears the input buffer - void clearInput(); - - /// Sets the number of channels, 1 = mono, 2 = stereo - void setChannels(int numChannels); - - /// Enables/disables the quick position seeking algorithm. Zero to disable, - /// nonzero to enable - void enableQuickSeek(bool enable); - - /// Returns nonzero if the quick seeking algorithm is enabled. - bool isQuickSeekEnabled() const; - - /// Sets routine control parameters. These control are certain time constants - /// defining how the sound is stretched to the desired duration. - // - /// 'sampleRate' = sample rate of the sound - /// 'sequenceMS' = one processing sequence length in milliseconds - /// 'seekwindowMS' = seeking window length for scanning the best overlapping - /// position - /// 'overlapMS' = overlapping length - void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz) - int sequenceMS = -1, ///< Single processing sequence length (ms) - int seekwindowMS = -1, ///< Offset seeking window length (ms) - int overlapMS = -1 ///< Sequence overlapping length (ms) - ); - - /// Get routine control parameters, see setParameters() function. - /// Any of the parameters to this function can be NULL, in such case corresponding parameter - /// value isn't returned. - void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const; - - /// Adds 'numsamples' pcs of samples from the 'samples' memory position into - /// the input of the object. - virtual void putSamples( - const SAMPLETYPE *samples, ///< Input sample data - uint numSamples ///< Number of samples in 'samples' so that one sample - ///< contains both channels if stereo - ); - - /// return nominal input sample requirement for triggering a processing batch - int getInputSampleReq() const - { - return (int)(nominalSkip + 0.5); - } - - /// return nominal output sample amount when running a processing batch - int getOutputBatchSize() const - { - return seekWindowLength - overlapLength; - } -}; - - - -// Implementation-specific class declarations: - -#ifdef SOUNDTOUCH_ALLOW_MMX - /// Class that implements MMX optimized routines for 16bit integer samples type. - class TDStretchMMX : public TDStretch - { - protected: - double calcCrossCorr(const short *mixingPos, const short *compare, double &norm); - double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm); - virtual void overlapStereo(short *output, const short *input) const; - virtual void clearCrossCorrState(); - }; -#endif /// SOUNDTOUCH_ALLOW_MMX - - -#ifdef SOUNDTOUCH_ALLOW_SSE - /// Class that implements SSE optimized routines for floating point samples type. - class TDStretchSSE : public TDStretch - { - protected: - double calcCrossCorr(const float *mixingPos, const float *compare, double &norm); - double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm); - }; - -#endif /// SOUNDTOUCH_ALLOW_SSE - -} -#endif /// TDStretch_H diff --git a/externals/soundtouch/cpu_detect.h b/externals/soundtouch/cpu_detect.h deleted file mode 100644 index 7859ffb55..000000000 --- a/externals/soundtouch/cpu_detect.h +++ /dev/null @@ -1,62 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// A header file for detecting the Intel MMX instructions set extension. -/// -/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the -/// routine implementations for x86 Windows, x86 gnu version and non-x86 -/// platforms, respectively. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 _CPU_DETECT_H_ -#define _CPU_DETECT_H_ - -#include "STTypes.h" - -#define SUPPORT_MMX 0x0001 -#define SUPPORT_3DNOW 0x0002 -#define SUPPORT_ALTIVEC 0x0004 -#define SUPPORT_SSE 0x0008 -#define SUPPORT_SSE2 0x0010 - -/// Checks which instruction set extensions are supported by the CPU. -/// -/// \return A bitmask of supported extensions, see SUPPORT_... defines. -uint detectCPUextensions(void); - -/// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint wDisableMask); - -#endif // _CPU_DETECT_H_ diff --git a/externals/soundtouch/cpu_detect_x86.cpp b/externals/soundtouch/cpu_detect_x86.cpp deleted file mode 100644 index 00f22ab27..000000000 --- a/externals/soundtouch/cpu_detect_x86.cpp +++ /dev/null @@ -1,138 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// Generic version of the x86 CPU extension detection routine. -/// -/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' -/// for the Microsoft compiler version. -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 "cpu_detect.h" -#include "STTypes.h" - - -#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) - - #if defined(__GNUC__) && defined(__i386__) - // gcc - #include "cpuid.h" - #elif defined(_M_IX86) - // windows non-gcc - #include - #endif - - #define bit_MMX (1 << 23) - #define bit_SSE (1 << 25) - #define bit_SSE2 (1 << 26) -#endif - - -////////////////////////////////////////////////////////////////////////////// -// -// processor instructions extension detection routines -// -////////////////////////////////////////////////////////////////////////////// - -// Flag variable indicating whick ISA extensions are disabled (for debugging) -static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions - -// Disables given set of instruction extensions. See SUPPORT_... defines. -void disableExtensions(uint dwDisableMask) -{ - _dwDisabledISA = dwDisableMask; -} - - - -/// Checks which instruction set extensions are supported by the CPU. -uint detectCPUextensions(void) -{ -/// If building for a 64bit system (no Itanium) and the user wants optimizations. -/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19. -/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). -#if ((defined(__GNUC__) && defined(__x86_64__)) \ - || defined(_M_X64)) \ - && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) - return 0x19 & ~_dwDisabledISA; - -/// If building for a 32bit system and the user wants optimizations. -/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). -#elif ((defined(__GNUC__) && defined(__i386__)) \ - || defined(_M_IX86)) \ - && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) - - if (_dwDisabledISA == 0xffffffff) return 0; - - uint res = 0; - -#if defined(__GNUC__) - // GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support. - uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable. - - // Check if no cpuid support. - if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions. - - if (edx & bit_MMX) res = res | SUPPORT_MMX; - if (edx & bit_SSE) res = res | SUPPORT_SSE; - if (edx & bit_SSE2) res = res | SUPPORT_SSE2; - -#else - // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required - // for __cpuid intrinsic support. - int reg[4] = {-1}; - - // Check if no cpuid support. - __cpuid(reg,0); - if ((unsigned int)reg[0] == 0) return 0; // always disable extensions. - - __cpuid(reg,1); - if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX; - if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE; - if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2; - -#endif - - return res & ~_dwDisabledISA; - -#else - -/// One of these is true: -/// 1) We don't want optimizations. -/// 2) Using an unsupported compiler. -/// 3) Running on a non-x86 platform. - return 0; - -#endif -} diff --git a/externals/soundtouch/mmx_optimized.cpp b/externals/soundtouch/mmx_optimized.cpp deleted file mode 100644 index 5c34b9adc..000000000 --- a/externals/soundtouch/mmx_optimized.cpp +++ /dev/null @@ -1,395 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// MMX optimized routines. All MMX optimized functions have been gathered into -/// this single source code file, regardless to their class or original source -/// code file, in order to ease porting the library to other compiler and -/// processor platforms. -/// -/// The MMX-optimizations are programmed using MMX compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support compiler intrinsic syntax. The update -/// is available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 "STTypes.h" - -#ifdef SOUNDTOUCH_ALLOW_MMX -// MMX routines available only with integer sample type - -using namespace soundtouch; - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'TDStretchMMX' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include -#include -#include - - -// Calculates cross correlation of two buffers -double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm) -{ - const __m64 *pVec1, *pVec2; - __m64 shifter; - __m64 accu, normaccu; - long corr, norm; - int i; - - pVec1 = (__m64*)pV1; - pVec2 = (__m64*)pV2; - - shifter = _m_from_int(overlapDividerBitsNorm); - normaccu = accu = _mm_setzero_si64(); - - // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples - // during each round for improved CPU-level parallellization. - for (i = 0; i < channels * overlapLength / 16; i ++) - { - __m64 temp, temp2; - - // dictionary of instructions: - // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] - // _mm_add_pi32 : 2*32bit add - // _m_psrad : 32bit right-shift - - temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), - _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter)); - temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), shifter), - _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter)); - accu = _mm_add_pi32(accu, temp); - normaccu = _mm_add_pi32(normaccu, temp2); - - temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), - _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter)); - temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), shifter), - _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter)); - accu = _mm_add_pi32(accu, temp); - normaccu = _mm_add_pi32(normaccu, temp2); - - pVec1 += 4; - pVec2 += 4; - } - - // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 - // and finally store the result into the variable "corr" - - accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); - corr = _m_to_int(accu); - - normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32)); - norm = _m_to_int(normaccu); - - // Clear MMS state - _m_empty(); - - if (norm > (long)maxnorm) - { - maxnorm = norm; - } - - // Normalize result by dividing by sqrt(norm) - this step is easiest - // done using floating point operation - dnorm = (double)norm; - - return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm); - // Note: Warning about the missing EMMS instruction is harmless - // as it'll be called elsewhere. -} - - -/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value -double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm) -{ - const __m64 *pVec1, *pVec2; - __m64 shifter; - __m64 accu; - long corr, lnorm; - int i; - - // cancel first normalizer tap from previous round - lnorm = 0; - for (i = 1; i <= channels; i ++) - { - lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm; - } - - pVec1 = (__m64*)pV1; - pVec2 = (__m64*)pV2; - - shifter = _m_from_int(overlapDividerBitsNorm); - accu = _mm_setzero_si64(); - - // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples - // during each round for improved CPU-level parallellization. - for (i = 0; i < channels * overlapLength / 16; i ++) - { - __m64 temp; - - // dictionary of instructions: - // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] - // _mm_add_pi32 : 2*32bit add - // _m_psrad : 32bit right-shift - - temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), - _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter)); - accu = _mm_add_pi32(accu, temp); - - temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), - _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter)); - accu = _mm_add_pi32(accu, temp); - - pVec1 += 4; - pVec2 += 4; - } - - // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 - // and finally store the result into the variable "corr" - - accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); - corr = _m_to_int(accu); - - // Clear MMS state - _m_empty(); - - // update normalizer with last samples of this round - pV1 = (short *)pVec1; - for (int j = 1; j <= channels; j ++) - { - lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm; - } - dnorm += (double)lnorm; - - if (lnorm > (long)maxnorm) - { - maxnorm = lnorm; - } - - // Normalize result by dividing by sqrt(norm) - this step is easiest - // done using floating point operation - return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm); -} - - -void TDStretchMMX::clearCrossCorrState() -{ - // Clear MMS state - _m_empty(); - //_asm EMMS; -} - - - -// MMX-optimized version of the function overlapStereo -void TDStretchMMX::overlapStereo(short *output, const short *input) const -{ - const __m64 *pVinput, *pVMidBuf; - __m64 *pVdest; - __m64 mix1, mix2, adder, shifter; - int i; - - pVinput = (const __m64*)input; - pVMidBuf = (const __m64*)pMidBuffer; - pVdest = (__m64*)output; - - // mix1 = mixer values for 1st stereo sample - // mix1 = mixer values for 2nd stereo sample - // adder = adder for updating mixer values after each round - - mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); - adder = _mm_set_pi16(1, -1, 1, -1); - mix2 = _mm_add_pi16(mix1, adder); - adder = _mm_add_pi16(adder, adder); - - // Overlaplength-division by shifter. "+1" is to account for "-1" deduced in - // overlapDividerBits calculation earlier. - shifter = _m_from_int(overlapDividerBitsPure + 1); - - for (i = 0; i < overlapLength / 4; i ++) - { - __m64 temp1, temp2; - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r - temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - // --- second round begins here --- - - // load & shuffle data so that input & mixbuffer data samples are paired - temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r - temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r - - // temp = (temp .* mix) >> shifter - temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); - temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); - pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit - - // update mix += adder - mix1 = _mm_add_pi16(mix1, adder); - mix2 = _mm_add_pi16(mix2, adder); - - pVinput += 2; - pVMidBuf += 2; - pVdest += 2; - } - - _m_empty(); // clear MMS state -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of MMX optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - - -FIRFilterMMX::FIRFilterMMX() : FIRFilter() -{ - filterCoeffsAlign = NULL; - filterCoeffsUnalign = NULL; -} - - -FIRFilterMMX::~FIRFilterMMX() -{ - delete[] filterCoeffsUnalign; -} - - -// (overloaded) Calculates filter coefficients for MMX routine -void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new short[2 * newLength + 8]; - filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); - - // rearrange the filter coefficients for mmx routines - for (i = 0;i < length; i += 4) - { - filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; - filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; - filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; - - filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; - filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; - filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; - } -} - - - -// mmx-optimized version of the filter routine for stereo sound -uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const -{ - // Create stack copies of the needed member variables for asm routines : - uint i, j; - __m64 *pVdest = (__m64*)dest; - - if (length < 2) return 0; - - for (i = 0; i < (numSamples - length) / 2; i ++) - { - __m64 accu1; - __m64 accu2; - const __m64 *pVsrc = (const __m64*)src; - const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; - - accu1 = accu2 = _mm_setzero_si64(); - for (j = 0; j < lengthDiv8 * 2; j ++) - { - __m64 temp1, temp2; - - temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 - temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 - - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 - accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 - - temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 - - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 - accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 - - // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 - // += l3*f3+l1*f1 r3*f3+r1*f1 - - // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 - // l4*f3+l2*f1 r4*f3+r2*f1 - - pVfilter += 2; - pVsrc += 2; - } - // accu >>= resultDivFactor - accu1 = _mm_srai_pi32(accu1, resultDivFactor); - accu2 = _mm_srai_pi32(accu2, resultDivFactor); - - // pack 2*2*32bits => 4*16 bits - pVdest[0] = _mm_packs_pi32(accu1, accu2); - src += 4; - pVdest ++; - } - - _m_empty(); // clear emms state - - return (numSamples & 0xfffffffe) - length; -} - -#endif // SOUNDTOUCH_ALLOW_MMX diff --git a/externals/soundtouch/sse_optimized.cpp b/externals/soundtouch/sse_optimized.cpp deleted file mode 100644 index b6bb4cc22..000000000 --- a/externals/soundtouch/sse_optimized.cpp +++ /dev/null @@ -1,372 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// -/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE -/// optimized functions have been gathered into this single source -/// code file, regardless to their class or original source code file, in order -/// to ease porting the library to other compiler and processor platforms. -/// -/// The SSE-optimizations are programmed using SSE compiler intrinsics that -/// are supported both by Microsoft Visual C++ and GCC compilers, so this file -/// should compile with both toolsets. -/// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support SSE instruction set. The update is -/// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx -/// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and -/// perform a search with keywords "processor pack". -/// -/// Author : Copyright (c) Olli Parviainen -/// Author e-mail : oparviai 'at' iki.fi -/// SoundTouch WWW: http://www.surina.net/soundtouch -/// -//////////////////////////////////////////////////////////////////////////////// -// -// 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 -// 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 "cpu_detect.h" -#include "STTypes.h" - -using namespace soundtouch; - -#ifdef SOUNDTOUCH_ALLOW_SSE - -// SSE routines available only with float sample type - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'TDStretchSSE' -// -////////////////////////////////////////////////////////////////////////////// - -#include "TDStretch.h" -#include -#include - -// Calculates cross correlation of two buffers -double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm) -{ - int i; - const float *pVec1; - const __m128 *pVec2; - __m128 vSum, vNorm; - - // Note. It means a major slow-down if the routine needs to tolerate - // unaligned __m128 memory accesses. It's way faster if we can skip - // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. - // This can mean up to ~ 10-fold difference (incl. part of which is - // due to skipping every second round for stereo sound though). - // - // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided - // for choosing if this little cheating is allowed. - -#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION - // Little cheating allowed, return valid correlation only for - // aligned locations, meaning every second round for stereo sound. - - #define _MM_LOAD _mm_load_ps - - if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations - -#else - // No cheating allowed, use unaligned load & take the resulting - // performance hit. - #define _MM_LOAD _mm_loadu_ps -#endif - - // ensure overlapLength is divisible by 8 - assert((overlapLength % 8) == 0); - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. - pVec1 = (const float*)pV1; - pVec2 = (const __m128*)pV2; - vSum = vNorm = _mm_setzero_ps(); - - // Unroll the loop by factor of 4 * 4 operations. Use same routine for - // stereo & mono, for mono it just means twice the amount of unrolling. - for (i = 0; i < channels * overlapLength / 16; i ++) - { - __m128 vTemp; - // vSum += pV1[0..3] * pV2[0..3] - vTemp = _MM_LOAD(pVec1); - vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0])); - vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); - - // vSum += pV1[4..7] * pV2[4..7] - vTemp = _MM_LOAD(pVec1 + 4); - vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1])); - vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); - - // vSum += pV1[8..11] * pV2[8..11] - vTemp = _MM_LOAD(pVec1 + 8); - vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2])); - vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); - - // vSum += pV1[12..15] * pV2[12..15] - vTemp = _MM_LOAD(pVec1 + 12); - vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3])); - vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); - - pVec1 += 16; - pVec2 += 4; - } - - // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] - float *pvNorm = (float*)&vNorm; - float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); - anorm = norm; - - float *pvSum = (float*)&vSum; - return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm); - - /* This is approximately corresponding routine in C-language yet without normalization: - double corr, norm; - uint i; - - // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors - corr = norm = 0.0; - for (i = 0; i < channels * overlapLength / 16; i ++) - { - corr += pV1[0] * pV2[0] + - pV1[1] * pV2[1] + - pV1[2] * pV2[2] + - pV1[3] * pV2[3] + - pV1[4] * pV2[4] + - pV1[5] * pV2[5] + - pV1[6] * pV2[6] + - pV1[7] * pV2[7] + - pV1[8] * pV2[8] + - pV1[9] * pV2[9] + - pV1[10] * pV2[10] + - pV1[11] * pV2[11] + - pV1[12] * pV2[12] + - pV1[13] * pV2[13] + - pV1[14] * pV2[14] + - pV1[15] * pV2[15]; - - for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j]; - - pV1 += 16; - pV2 += 16; - } - return corr / sqrt(norm); - */ -} - - - -double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm) -{ - // call usual calcCrossCorr function because SSE does not show big benefit of - // accumulating "norm" value, and also the "norm" rolling algorithm would get - // complicated due to SSE-specific alignment-vs-nonexact correlation rules. - return calcCrossCorr(pV1, pV2, norm); -} - - -////////////////////////////////////////////////////////////////////////////// -// -// implementation of SSE optimized functions of class 'FIRFilter' -// -////////////////////////////////////////////////////////////////////////////// - -#include "FIRFilter.h" - -FIRFilterSSE::FIRFilterSSE() : FIRFilter() -{ - filterCoeffsAlign = NULL; - filterCoeffsUnalign = NULL; -} - - -FIRFilterSSE::~FIRFilterSSE() -{ - delete[] filterCoeffsUnalign; - filterCoeffsAlign = NULL; - filterCoeffsUnalign = NULL; -} - - -// (overloaded) Calculates filter coefficients for SSE routine -void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) -{ - uint i; - float fDivider; - - FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); - - // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for SSE - // Ensure that filter coeffs array is aligned to 16-byte boundary - delete[] filterCoeffsUnalign; - filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); - - fDivider = (float)resultDivider; - - // rearrange the filter coefficients for mmx routines - for (i = 0; i < newLength; i ++) - { - filterCoeffsAlign[2 * i + 0] = - filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; - } -} - - - -// SSE-optimized version of the filter routine for stereo sound -uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const -{ - int count = (int)((numSamples - length) & (uint)-2); - int j; - - assert(count % 2 == 0); - - if (count < 2) return 0; - - assert(source != NULL); - assert(dest != NULL); - assert((length % 8) == 0); - assert(filterCoeffsAlign != NULL); - assert(((ulongptr)filterCoeffsAlign) % 16 == 0); - - // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' - #pragma omp parallel for - for (j = 0; j < count; j += 2) - { - const float *pSrc; - float *pDest; - const __m128 *pFil; - __m128 sum1, sum2; - uint i; - - pSrc = (const float*)source + j * 2; // source audio data - pDest = dest + j * 2; // destination audio data - pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients - // are aligned to 16-byte boundary - sum1 = sum2 = _mm_setzero_ps(); - - for (i = 0; i < length / 8; i ++) - { - // Unroll loop for efficiency & calculate filter for 2*2 stereo samples - // at each pass - - // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset - // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); - - sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); - sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); - - pSrc += 16; - pFil += 4; - } - - // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - // post-shuffle & add the filtered values and store to dest. - _mm_storeu_ps(pDest, _mm_add_ps( - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 - _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 - )); - } - - // Ideas for further improvement: - // 1. If it could be guaranteed that 'source' were always aligned to 16-byte - // boundary, a faster aligned '_mm_load_ps' instruction could be used. - // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte - // boundary, a faster '_mm_store_ps' instruction could be used. - - return (uint)count; - - /* original routine in C-language. please notice the C-version has differently - organized coefficients though. - double suml1, suml2; - double sumr1, sumr2; - uint i, j; - - for (j = 0; j < count; j += 2) - { - const float *ptr; - const float *pFil; - - suml1 = sumr1 = 0.0; - suml2 = sumr2 = 0.0; - ptr = src; - pFil = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) - { - // unroll loop for efficiency. - - suml1 += ptr[0] * pFil[0] + - ptr[2] * pFil[2] + - ptr[4] * pFil[4] + - ptr[6] * pFil[6]; - - sumr1 += ptr[1] * pFil[1] + - ptr[3] * pFil[3] + - ptr[5] * pFil[5] + - ptr[7] * pFil[7]; - - suml2 += ptr[8] * pFil[0] + - ptr[10] * pFil[2] + - ptr[12] * pFil[4] + - ptr[14] * pFil[6]; - - sumr2 += ptr[9] * pFil[1] + - ptr[11] * pFil[3] + - ptr[13] * pFil[5] + - ptr[15] * pFil[7]; - - ptr += 16; - pFil += 8; - } - dest[0] = (float)suml1; - dest[1] = (float)sumr1; - dest[2] = (float)suml2; - dest[3] = (float)sumr2; - - src += 4; - dest += 4; - } - */ -} - -#endif // SOUNDTOUCH_ALLOW_SSE diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index c5b60120c..869da5e83 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -2,14 +2,8 @@ set(SRCS audio_core.cpp codec.cpp hle/dsp.cpp - hle/effects.cpp hle/filter.cpp - hle/final.cpp hle/pipe.cpp - hle/source.cpp - interpolate.cpp - null_sink.cpp - time_stretch.cpp ) set(HEADERS @@ -17,31 +11,11 @@ set(HEADERS codec.h hle/common.h hle/dsp.h - hle/effects.h hle/filter.h - hle/final.h hle/pipe.h - hle/source.h - interpolate.h - null_sink.h sink.h - time_stretch.h ) -if(SDL2_FOUND) - set(SRCS ${SRCS} sdl2_sink.cpp) - set(HEADERS ${HEADERS} sdl2_sink.h) - include_directories(${SDL2_INCLUDE_DIR}) -endif() - -include_directories(../../externals/soundtouch) -include_directories(../../externals/rubberband/rubberband/rubberband) - create_directory_groups(${SRCS} ${HEADERS}) -add_library(audio_core STATIC ${SRCS} ${HEADERS}) -target_link_libraries(audio_core SoundTouch rubberband) - -if(SDL2_FOUND) - target_link_libraries(audio_core ${SDL2_LIBRARY}) -endif() \ No newline at end of file +add_library(audio_core STATIC ${SRCS} ${HEADERS}) \ No newline at end of file diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp index c1de63cba..894f46990 100644 --- a/src/audio_core/audio_core.cpp +++ b/src/audio_core/audio_core.cpp @@ -4,7 +4,6 @@ #include "audio_core/audio_core.h" #include "audio_core/hle/dsp.h" -#include "audio_core/sdl2_sink.h" #include "core/core_timing.h" #include "core/hle/kernel/vm_manager.h" diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h index 6db9de717..64c330914 100644 --- a/src/audio_core/audio_core.h +++ b/src/audio_core/audio_core.h @@ -4,17 +4,15 @@ #pragma once -#include - namespace Kernel { class VMManager; } namespace AudioCore { -constexpr size_t num_sources = 24; -constexpr size_t samples_per_frame = 160; ///< Samples per audio frame at native sample rate -constexpr unsigned native_sample_rate = 32728; ///< 32kHz +constexpr int num_sources = 24; +constexpr int samples_per_frame = 160; ///< Samples per audio frame at native sample rate +constexpr int native_sample_rate = 32728; ///< 32kHz /// Initialise Audio Core void Init(); diff --git a/src/audio_core/codec.cpp b/src/audio_core/codec.cpp index 410447e9c..ab65514b7 100644 --- a/src/audio_core/codec.cpp +++ b/src/audio_core/codec.cpp @@ -77,7 +77,9 @@ StereoBuffer16 DecodeADPCM(const u8* const data, const size_t sample_count, cons } static s16 SignExtendS8(u8 x) { - return s16(u16(x) << 8); + // The data is actually signed PCM8. + // We sign extend this to signed PCM16. + return static_cast(static_cast(x)); } StereoBuffer16 DecodePCM8(const unsigned num_channels, const u8* const data, const size_t sample_count) { diff --git a/src/audio_core/hle/common.cpp b/src/audio_core/hle/common.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/audio_core/hle/dsp.cpp b/src/audio_core/hle/dsp.cpp index d142c47da..c89356edc 100644 --- a/src/audio_core/hle/dsp.cpp +++ b/src/audio_core/hle/dsp.cpp @@ -2,23 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include -#include - -#include "audio_core/audio_core.h" -#include "audio_core/hle/effects.h" #include "audio_core/hle/dsp.h" -#include "audio_core/hle/final.h" #include "audio_core/hle/pipe.h" -#include "audio_core/hle/source.h" -#include "audio_core/sink.h" -#include "audio_core/time_stretch.h" - -#include "common/microprofile.h" -#include "common/profiler.h" -#include "common/thread.h" - -#include "core/hle/service/dsp_dsp.h" namespace DSP { namespace HLE { @@ -26,104 +11,14 @@ namespace HLE { SharedMemory g_region0; SharedMemory g_region1; -static void ThreadFunc(); -static Common::Barrier ThreadFunc_barrier(2); -static std::atomic ThreadFunc_quit = true; - void Init() { - ResetPipes(); - SourceInit(); - EffectsInit(); - FinalInit(); - TimeStretch::Init(); - - ThreadFunc_quit = false; - std::thread thread(ThreadFunc); - thread.detach(); - - // Lioncash won't like this. Don't do it. - std::memset(&g_region0, 0, sizeof(SharedMemory)); - std::memset(&g_region1, 0, sizeof(SharedMemory)); + DSP::HLE::ResetPipes(); } void Shutdown() { - TimeStretch::Shutdown(); - - if (!ThreadFunc_quit) { - ThreadFunc_quit = true; - ThreadFunc_barrier.Sync(); - } -} - -static bool next_region_is_ready = true; - -unsigned num_frames = 500; -double time_for_a_frame = 0.005; - -static Common::Profiling::TimingCategory profile_tick("DSP::Tick"); -static Common::Profiling::TimingCategory profile_work("DSP::Work"); -MICROPROFILE_DEFINE(DSP_Tick, "DSP", "Tick", MP_RGB(204, 204, 0)); -MICROPROFILE_DEFINE(DSP_Work, "DSP", "Work", MP_RGB(153, 153, 0)); - -static void DoWork() { - Common::Profiling::ScopeTimer timer_work(profile_work); - MICROPROFILE_SCOPE(DSP_Work); - - auto& region = CurrentRegion(); - - for (int i = 0; i < AudioCore::num_sources; i++) { - auto& config = region.source_configurations.config[i]; - auto& coeffs = region.adpcm_coefficients.coeff[i]; - auto& status = region.source_statuses.status[i]; - - SourceUpdate(i, config, coeffs, status); - } - - EffectsUpdate(region.dsp_configuration, region.intermediate_mix_samples); - - FinalUpdate(region.dsp_configuration, region.dsp_status, region.final_samples); - - StereoFrame16 samples = FinalFrame(); - -#if 0 - std::vector output; - output.reserve(AudioCore::samples_per_frame * 2); - for (int i = 0; i < AudioCore::samples_per_frame; i++) { - output.push_back(samples[0][i]); - output.push_back(samples[1][i]); - } - AudioCore::sink->EnqueueSamples(output); -#else - TimeStretch::Tick(AudioCore::sink->SamplesInQueue()); - TimeStretch::AddSamples(samples); - TimeStretch::OutputSamples([&](const std::vector& output) { - if (AudioCore::sink->SamplesInQueue() < 16000) { - AudioCore::sink->EnqueueSamples(output); - } - }); -#endif -} - -static void ThreadFunc() { - while (true) { - ThreadFunc_barrier.Sync(); - if (ThreadFunc_quit) { - break; - } - - DoWork(); - } } bool Tick() { - Common::Profiling::ScopeTimer timer_tick(profile_tick); - MICROPROFILE_SCOPE(DSP_Tick); - - if (GetDspState() != DspState::On || !DSP_DSP::SemaphoreSignalled()) - return false; - - ThreadFunc_barrier.Sync(); - return true; } diff --git a/src/audio_core/hle/dsp.h b/src/audio_core/hle/dsp.h index fd71cc0d9..c15ef0b7a 100644 --- a/src/audio_core/hle/dsp.h +++ b/src/audio_core/hle/dsp.h @@ -313,10 +313,10 @@ ASSERT_DSP_STRUCT(SourceConfiguration::Configuration::Buffer, 20); struct SourceStatus { struct Status { u8 is_enabled; ///< Is this channel enabled? (Doesn't have to be playing anything.) - u8 current_buffer_id_dirty; ///< Non-zero when current_buffer_id changes + u8 previous_buffer_id_dirty; ///< Non-zero when previous_buffer_id changes u16_le sync; ///< Is set by the DSP to the value of SourceConfiguration::sync u32_dsp buffer_position; ///< Number of samples into the current buffer - u16_le current_buffer_id; ///< Updated when a buffer finishes playing + u16_le previous_buffer_id; ///< Updated when a buffer finishes playing INSERT_PADDING_DSPWORDS(1); }; @@ -330,13 +330,6 @@ struct DspConfiguration { union { u32_le dirty_raw; - BitField<0, 1, u32_le> unknown10_dirty; - BitField<1, 1, u32_le> unknown11_dirty; - BitField<2, 1, u32_le> unknown12_dirty; - BitField<3, 1, u32_le> unknown13_dirty; - BitField<4, 1, u32_le> unknown14_dirty; - BitField<5, 1, u32_le> unknown15_dirty; - BitField<8, 1, u32_le> mixer1_enabled_dirty; BitField<9, 1, u32_le> mixer2_enabled_dirty; BitField<10, 1, u32_le> delay_effect_0_dirty; @@ -344,7 +337,6 @@ struct DspConfiguration { BitField<12, 1, u32_le> reverb_effect_0_dirty; BitField<13, 1, u32_le> reverb_effect_1_dirty; - BitField<15, 1, u32_le> unknown17_dirty; BitField<16, 1, u32_le> volume_0_dirty; BitField<24, 1, u32_le> volume_1_dirty; @@ -352,16 +344,12 @@ struct DspConfiguration { BitField<26, 1, u32_le> output_format_dirty; BitField<27, 1, u32_le> limiter_enabled_dirty; BitField<28, 1, u32_le> headphones_connected_dirty; - - BitField<30, 1, u32_le> unknown16_dirty; - BitField<31, 1, u32_le> unknown18_dirty; }; /// The DSP has three intermediate audio mixers. This controls the volume level (0.0-1.0) for each at the final mixer float_le volume[3]; - u16 unknown17; - INSERT_PADDING_DSPWORDS(2); + INSERT_PADDING_DSPWORDS(3); enum class OutputFormat : u16_le { Mono = 0, @@ -373,10 +361,7 @@ struct DspConfiguration { u16_le limiter_enabled; ///< Not sure of the exact gain equation for the limiter. u16_le headphones_connected; ///< Application updates the DSP on headphone status. - INSERT_PADDING_DSPWORDS(1); ///< TODO: Surround sound related - u16 unknown16; - u16 unknown15; - u16 unknown18; + INSERT_PADDING_DSPWORDS(4); ///< TODO: Surround sound related INSERT_PADDING_DSPWORDS(2); ///< TODO: Intermediate mixer 1/2 related u16_le mixer1_enabled; u16_le mixer2_enabled; @@ -494,29 +479,25 @@ struct SharedMemory { AdpcmCoefficients adpcm_coefficients; struct { - u16 unknown[256]; + INSERT_PADDING_DSPWORDS(0x100); } unknown10; struct { - u16 unknown[192]; + INSERT_PADDING_DSPWORDS(0xC0); } unknown11; struct { - u16 unknown[384]; + INSERT_PADDING_DSPWORDS(0x180); } unknown12; struct { - // biq - u32_dsp unknown[5]; + INSERT_PADDING_DSPWORDS(0xA); } unknown13; struct { - // biq - u32_dsp unknown[5]; + INSERT_PADDING_DSPWORDS(0x13A3); } unknown14; - INSERT_PADDING_DSPWORDS(0x1399); - u16_le frame_counter; }; ASSERT_DSP_STRUCT(SharedMemory, 0x8000); diff --git a/src/audio_core/hle/effects.cpp b/src/audio_core/hle/effects.cpp deleted file mode 100644 index 1b12a3c5c..000000000 --- a/src/audio_core/hle/effects.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "audio_core/audio_core.h" -#include "audio_core/hle/common.h" -#include "audio_core/hle/effects.h" -#include "audio_core/hle/source.h" - -namespace DSP { -namespace HLE { - -struct State { - QuadFrame32 current_frame; -}; - -static std::array state; - -void EffectsInit() { - state = {}; -} - -void EffectsUpdate(const DspConfiguration& config, IntermediateMixSamples& samples) { - state[0].current_frame.fill({}); - state[1].current_frame.fill({}); - state[2].current_frame.fill({}); - - for (size_t source_id = 0; source_id < AudioCore::num_sources; source_id++) { - SourceFrameMixInto(state[0].current_frame, source_id, 0); - SourceFrameMixInto(state[1].current_frame, source_id, 1); - SourceFrameMixInto(state[2].current_frame, source_id, 2); - } - - // TODO: Delay - // TODO: Reverb - -} - -const QuadFrame32& IntermediateMixFrame(int mix_id) { - return state[mix_id].current_frame; -} - -} -} diff --git a/src/audio_core/hle/effects.h b/src/audio_core/hle/effects.h deleted file mode 100644 index 0d776d89a..000000000 --- a/src/audio_core/hle/effects.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "audio_core/hle/common.h" -#include "audio_core/hle/dsp.h" - -namespace DSP { -namespace HLE { - -void EffectsInit(); - -void EffectsUpdate(const DspConfiguration& config, IntermediateMixSamples& samples); - -const QuadFrame32& IntermediateMixFrame(int mix_id); - -} -} diff --git a/src/audio_core/hle/final.cpp b/src/audio_core/hle/final.cpp deleted file mode 100644 index b404a7d91..000000000 --- a/src/audio_core/hle/final.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "audio_core/hle/common.h" -#include "audio_core/hle/effects.h" -#include "audio_core/hle/final.h" - -#include "common/logging/log.h" -#include "common/math_util.h" - -namespace DSP { -namespace HLE { - -struct State { - StereoFrame16 current_frame; - std::array volumes = {1.0, 0.0, 0.0}; -}; - -static State state; - -void FinalInit() { - state = {}; -} - -void FinalUpdate(const DspConfiguration& config, DspStatus& status, FinalMixSamples& samples) { - // TODO: Final processing - - bool clipping = false; - - std::array mix; - for (int k = 0; k < 3; k++) { - mix[k] = IntermediateMixFrame(k); - } - - for (int i = 0; i < AudioCore::samples_per_frame; i++) { - for (int j = 0; j < 2; j++) { - s32 value = 0; - for (int k = 0; k < 3; k++) { - value += 0.2 * state.volumes[0] * mix[k][i][j + 0]; - value += 0.2 * state.volumes[0] * mix[k][i][j + 2]; - } - - if (value > 0x8000 || value < -0x7FFF) { - clipping = true; - } - - state.current_frame[i][j] = static_cast(MathUtil::Clamp(value, -0x7FFF, 0x8000)); - } - } - - if (clipping) { - LOG_ERROR(Audio_DSP, "AUDIO IS CLIPPING"); - } -} - -const StereoFrame16& FinalFrame() { - return state.current_frame; -} - -} -} diff --git a/src/audio_core/hle/final.h b/src/audio_core/hle/final.h deleted file mode 100644 index e45e2e940..000000000 --- a/src/audio_core/hle/final.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "audio_core/hle/dsp.h" - -namespace DSP { -namespace HLE { - -void FinalInit(); - -void FinalUpdate(const DspConfiguration& config, DspStatus& status, FinalMixSamples& samples); - -const StereoFrame16& FinalFrame(); - -} -} diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp index 361671901..9381883b4 100644 --- a/src/audio_core/hle/pipe.cpp +++ b/src/audio_core/hle/pipe.cpp @@ -17,7 +17,7 @@ namespace HLE { static DspState dsp_state = DspState::Off; -static std::array, DspPipe_MAX> pipe_data; +static std::array, static_cast(DspPipe::DspPipe_MAX)> pipe_data; void ResetPipes() { for (auto& data : pipe_data) { diff --git a/src/audio_core/hle/pipe.h b/src/audio_core/hle/pipe.h index e554fad4a..382d35e87 100644 --- a/src/audio_core/hle/pipe.h +++ b/src/audio_core/hle/pipe.h @@ -23,8 +23,6 @@ enum class DspPipe { DspPipe_MAX }; -constexpr size_t DspPipe_MAX = static_cast(DspPipe::DspPipe_MAX); - /** * Read a DSP pipe. * @param pipe_number The Pipe ID diff --git a/src/audio_core/hle/source.cpp b/src/audio_core/hle/source.cpp deleted file mode 100644 index d22d56b41..000000000 --- a/src/audio_core/hle/source.cpp +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include - -#include "audio_core/codec.h" -#include "audio_core/hle/common.h" -#include "audio_core/hle/source.h" -#include "audio_core/interpolate.h" - -#include "common/assert.h" -#include "common/logging/log.h" - -#include "core/memory.h" - -namespace DSP { -namespace HLE { - -using MonoOrStereo = SourceConfiguration::Configuration::MonoOrStereo; -using Format = SourceConfiguration::Configuration::Format; -using DspBuffer = SourceConfiguration::Configuration::Buffer; - -struct Buffer { - PAddr physical_address; - u32 length; - u8 adpcm_ps; - u16 adpcm_yn[2]; - bool adpcm_dirty; - bool is_looping; - u16 buffer_id; - - MonoOrStereo mono_or_stereo; - Format format; - - bool from_queue; - - bool operator < (const Buffer& other) const { - // We want things with lower id to appear first, unless we have wraparound. - // priority_queue puts a before b when b < a. - if (this->buffer_id < 10 && other.buffer_id > 65520) return true; - if (other.buffer_id < 10 && this->buffer_id > 65520) return false; - return this->buffer_id > other.buffer_id; - } -}; - -struct State { - size_t source_id; - - bool enabled = false; - float rate_multiplier = 1.0; - u16 sync = 0; - std::array, 3> gains = {}; - MonoOrStereo mono_or_stereo = MonoOrStereo::Mono; - Format format = Format::PCM16; - - std::array adpcm_coeffs = {}; - Codec::ADPCMState adpcm_state = {0, 0}; - - AudioInterp::State interp_state = {}; - - bool do_not_trigger_update = true; - bool buffer_update = false; - u32 current_buffer_id = 0; - u32 previous_buffer_id = 0; - - std::priority_queue queue = {}; - u32 current_sample_number = 0; - u32 next_sample_number = 0; - Codec::StereoBuffer16 current_buffer = {}; - QuadFrame32 current_frame = {}; -}; - -static void ParseConfig(State& s, SourceConfiguration::Configuration& config, const s16_le adpcm_coeffs[16]) { - if (!config.dirty_raw) { - return; - } - - if (config.reset_flag) { - config.reset_flag.Assign(0); - size_t id = s.source_id; - s = {}; - s.source_id = id; - LOG_DEBUG(Audio_DSP, "source_id=%zu reset", s.source_id); - } - - if (config.enable_dirty) { - config.enable_dirty.Assign(0); - s.enabled = config.enable != 0; - LOG_TRACE(Audio_DSP, "source_id=%zu enable=%d", s.source_id, s.enabled); - } - - if (config.sync_dirty) { - config.sync_dirty.Assign(0); - s.sync = config.sync; - LOG_DEBUG(Audio_DSP, "source_id=%zu sync=%u", s.source_id, s.sync); - } - - if (config.rate_multiplier_dirty) { - config.rate_multiplier_dirty.Assign(0); - s.rate_multiplier = config.rate_multiplier; - LOG_TRACE(Audio_DSP, "source_id=%zu rate=%f", s.source_id, s.rate_multiplier); - } - - if (config.adpcm_coefficients_dirty) { - config.adpcm_coefficients_dirty.Assign(0); - std::copy(adpcm_coeffs, adpcm_coeffs + s.adpcm_coeffs.size(), s.adpcm_coeffs.begin()); - LOG_TRACE(Audio_DSP, "source_id=%zu adpcm update", s.source_id); - } - - if (config.gain_0_dirty) { - config.gain_0_dirty.Assign(0); - for (int i = 0; i < 4; i++) { - s.gains[0][i] = config.gain[0][i]; - LOG_TRACE(Audio_DSP, "source_id=%zu gains[0][%i] = %f", s.source_id, i, s.gains[0][i]); - } - } - - if (config.gain_1_dirty) { - config.gain_1_dirty.Assign(0); - for (int i = 0; i < 4; i++) { - s.gains[1][i] = config.gain[1][i]; - LOG_TRACE(Audio_DSP, "source_id=%zu gains[1][%i] = %f", s.source_id, i, s.gains[1][i]); - } - } - - if (config.gain_2_dirty) { - config.gain_2_dirty.Assign(0); - for (int i = 0; i < 4; i++) { - s.gains[2][i] = config.gain[2][i]; - LOG_TRACE(Audio_DSP, "source_id=%zu gains[2][%i] = %f", s.source_id, i, s.gains[2][i]); - } - } - -// if (config.unknown_flag) { - //config.unknown_flag = 0; -// LOG_WARNING(Audio_DSP, "(STUB) unknown_flag is set!!!"); -// } - - if (config.format_dirty || config.embedded_buffer_dirty) { - config.format_dirty.Assign(0); - s.format = config.format; - LOG_DEBUG(Audio_DSP, "source_id=%zu format=%u", s.source_id, s.format); - } - - if (config.mono_or_stereo_dirty || config.embedded_buffer_dirty) { - config.mono_or_stereo_dirty.Assign(0); - s.mono_or_stereo = config.mono_or_stereo; - LOG_DEBUG(Audio_DSP, "source_id=%zu mono_or_stereo=%u", s.source_id, s.mono_or_stereo); - } - - if (config.buffer_queue_dirty) { - config.buffer_queue_dirty.Assign(0); - for (int i = 0; i < 4; i++) { - if (config.buffers_dirty & (1 << i)) { - const auto& b = config.buffers[i]; - s.queue.emplace(Buffer{ - b.physical_address, - b.length, - (u8)b.adpcm_ps, - { b.adpcm_yn[0], b.adpcm_yn[1] }, - b.adpcm_dirty != 0, - b.is_looping != 0, - b.buffer_id, - s.mono_or_stereo, - s.format, - true - }); - LOG_TRACE(Audio_DSP, "enqueueing queued %i addr=0x%08x len=%u id=%u", i, b.physical_address, b.length, b.buffer_id); - } - } - config.buffers_dirty = 0; - } - - if (config.embedded_buffer_dirty) { - config.embedded_buffer_dirty.Assign(0); - s.queue.emplace(Buffer { - config.physical_address, - config.length, - (u8)config.adpcm_ps, - { config.adpcm_yn[0], config.adpcm_yn[1] }, - config.adpcm_dirty.ToBool(), - config.is_looping.ToBool(), - config.buffer_id, - s.mono_or_stereo, - s.format, - false - }); - LOG_TRACE(Audio_DSP, "enqueueing embedded addr=0x%08x len=%u id=%u", config.physical_address, config.length, config.buffer_id); - } - - if (config.interpolation_dirty) { - config.interpolation_dirty.Assign(0); - //config.interpolation_mode - LOG_DEBUG(Audio_DSP, "source_id=%zu interpolation_mode=%u ", s.source_id, config.interpolation_mode); - } - - if (config.dirty_raw) { - LOG_WARNING(Audio_DSP, "source_id=%zu remaining_dirty=%x", s.source_id, config.dirty_raw); - } - - config.dirty_raw = 0; -} - -static bool DequeueBuffer(State& s) { - if (!s.current_buffer.empty()) - return true; - if (s.queue.empty()) - return false; - - const Buffer buf = s.queue.top(); - s.queue.pop(); - - const u8* const memory = Memory::GetPhysicalPointer(buf.physical_address); - ASSERT(memory); - - if (buf.adpcm_dirty) { - s.adpcm_state.yn1 = buf.adpcm_yn[0]; - s.adpcm_state.yn2 = buf.adpcm_yn[1]; - } - - if (buf.is_looping) { - LOG_ERROR(Audio_DSP, "Looped buffers are unimplemented at the moment"); - } - - const unsigned num_channels = buf.mono_or_stereo == MonoOrStereo::Stereo ? 2 : 1; - switch (buf.format) { - case Format::PCM8: - s.current_buffer = Codec::DecodePCM8(num_channels, memory, buf.length); - break; - case Format::PCM16: - s.current_buffer = Codec::DecodePCM16(num_channels, memory, buf.length); - break; - case Format::ADPCM: - ASSERT(num_channels == 1); - s.current_buffer = Codec::DecodeADPCM(memory, buf.length, s.adpcm_coeffs, s.adpcm_state); - break; - default: - UNIMPLEMENTED(); - break; - } - - s.current_sample_number = s.next_sample_number = 0; - s.current_buffer_id = buf.buffer_id; - s.buffer_update = buf.from_queue; - - LOG_TRACE(Audio_DSP, "source_id=%u buffer_id=%u from_queue=%d", s.source_id, buf.buffer_id, buf.from_queue); - return true; -} - -static void ResampleBuffer(State& s) { - s.current_frame.fill({}); - - s.current_sample_number = s.next_sample_number; - while (true) { - if (!DequeueBuffer(s)) - break; - - auto result = AudioInterp::None(s.interp_state, s.current_frame, s.current_buffer, s.rate_multiplier); - s.next_sample_number += std::get<0>(result); - if (!std::get<1>(result)) - break; - } -} - -static void AdvanceFrame(State& s) { - ResampleBuffer(s); - - if (s.current_sample_number == s.next_sample_number) { - s.enabled = false; - } - - // TODO: Filters -} - -static void UpdateStatus(State& s, SourceStatus::Status& status) { - // Applications depend on the correct emulation of - // previous_buffer_id_dirty and previous_buffer_id to synchronise - // audio with video. - status.is_enabled = s.enabled; - status.current_buffer_id_dirty = s.buffer_update ? 1 : 0; - s.buffer_update = false; - status.current_buffer_id = s.current_buffer_id; - status.buffer_position = s.current_sample_number; - status.sync = s.sync; -} - -std::array state = {}; - -void SourceInit() { - state = {}; - for (size_t i = 0; i < state.size(); i++) { - state[i] = {}; - state[i].source_id = i; - } -} - -void SourceUpdate(int source_id, SourceConfiguration::Configuration& config, const s16_le adpcm_coeffs[16], SourceStatus::Status& status) { - ASSERT(source_id >= 0 && source_id < AudioCore::num_sources); - - ParseConfig(state[source_id], config, adpcm_coeffs); - AdvanceFrame(state[source_id]); - UpdateStatus(state[source_id], status); -} - -const QuadFrame32& SourceFrame(int source_id) { - ASSERT(source_id >= 0 && source_id < AudioCore::num_sources); - ASSERT(state[source_id].enabled); - - return state[source_id].current_frame; -} - -void SourceFrameMixInto(QuadFrame32& dest, int source_id, int intermediate_mix_id) { - ASSERT(source_id >= 0 && source_id < AudioCore::num_sources); - ASSERT(intermediate_mix_id >= 0 && intermediate_mix_id < 3); - - const State& s = state[source_id]; - - if (!s.enabled) - return; - - for (int i = 0; i < dest.size(); i++) { - for (int channel = 0; channel < 4; channel++) { - dest[i][channel] += s.gains[intermediate_mix_id][channel] * s.current_frame[i][channel]; - } - } -} - -} -} diff --git a/src/audio_core/hle/source.h b/src/audio_core/hle/source.h deleted file mode 100644 index 663b29dd4..000000000 --- a/src/audio_core/hle/source.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "audio_core/audio_core.h" -#include "audio_core/hle/common.h" -#include "audio_core/hle/dsp.h" - -namespace DSP { -namespace HLE { - -/// Initialise this DSP module -void SourceInit(); - -/** - * Perform processing for this DSP module. - * This module performs: - * - Buffer management - * - Decoding of buffers - * - Buffer resampling and interpolation - * - Per-source filtering (SimpleFilter, BiquadFilter) - * - Per-source gain - */ -void SourceUpdate(int source_id, SourceConfiguration::Configuration& config, const s16_le adpcm_coeffs[16], SourceStatus::Status& status); - -/// Output of this DSP module. -const QuadFrame32& SourceFrame(int source_id); - -/// Mix current frame from source_id into buffer based on gain coefficients for intermediate_mix_id. -void SourceFrameMixInto(QuadFrame32& dest, int source_id, int intermediate_mix_id); - -} -} diff --git a/src/audio_core/interpolate.cpp b/src/audio_core/interpolate.cpp deleted file mode 100644 index 0ebde61d2..000000000 --- a/src/audio_core/interpolate.cpp +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#define _USE_MATH_DEFINES -#include - -#include "audio_core/interpolate.h" - -#include "common/assert.h" -#include "common/math_util.h" - -namespace AudioInterp { - -/// Kaiser window with alpha=2.4, N=11 -static const std::array kaiser_window {{ - 0.327949, - 0.521302, - 0.707379, - 0.861996, - 0.964250 -}}; - -struct BiquadLpf { - /// Calculate coefficients required for a biquad filter to behave as a low-pass filter. - void Init(double freq) { - const double w0 = 2 * M_PI * freq; - const double Q = 0.707; - const double a = sin(w0) / (2.0*Q); - double a0; - - b0 = 0.5 * (1.0 - cos(w0)); - b1 = (1.0 - cos(w0)); - b2 = 0.5 * (1.0 - cos(w0)); - a0 = 1.0 + a; - a1 = -2.0 * cos(w0); - a2 = 1.0 - a; - - // Normalize; - b0 /= a0; - b1 /= a0; - b2 /= a0; - a1 /= a0; - a2 /= a0; - } - inline s32 Process(s32 x) { - double xn0 = x; - double yn0 = b0 * xn0 + b1 * xn1 + b2 * xn2 - a1 * yn1 - a2 * yn2; - - // Advance state - xn2 = xn1; - xn1 = xn0; - yn2 = yn1; - yn1 = yn0; - - return (s32)yn0; - } -private: - double a1, a2; - double b0, b1, b2; - double xn1 = 0.0, xn2 = 0.0, yn1 = 0.0, yn2 = 0.0; -}; - -double sinc(double x) { - DEBUG_ASSERT(x != 0); - return sin(x) / x; -} - -std::tuple KaiserSinc(State& state, DSP::HLE::QuadFrame32& output, std::array, 2>& input, const float rate_change) { - ASSERT(input[0].size() == input[1].size()); - ASSERT(input[0].size() > required_history); - - size_t position = 0; - double& position_fractional = state.position_fractional; - - for (int j = 0; j < 2; j++) { - input[j].insert(input[j].begin(), state.history[j].begin(), state.history[j].end()); - } - - std::array lpf; - const double lpf_cutoff = std::min(0.5 * rate_change, 0.5 / rate_change); - lpf[0].Init(lpf_cutoff); - lpf[1].Init(lpf_cutoff); - - auto step = [&](size_t i) -> s32 { - auto& in = input[i]; - s32 sample = 0; - sample += kaiser_window[0] * sinc(-5.0 - position_fractional) * in[position + 0]; - sample += kaiser_window[1] * sinc(-4.0 - position_fractional) * in[position + 1]; - sample += kaiser_window[2] * sinc(-3.0 - position_fractional) * in[position + 2]; - sample += kaiser_window[3] * sinc(-2.0 - position_fractional) * in[position + 3]; - sample += kaiser_window[4] * sinc(-1.0 - position_fractional) * in[position + 4]; - sample += in[position + 5]; - sample += kaiser_window[4] * sinc(+1.0 - position_fractional) * in[position + 6]; - sample += kaiser_window[3] * sinc(+2.0 - position_fractional) * in[position + 7]; - sample += kaiser_window[2] * sinc(+3.0 - position_fractional) * in[position + 8]; - sample += kaiser_window[1] * sinc(+4.0 - position_fractional) * in[position + 9]; - sample += kaiser_window[0] * sinc(+5.0 - position_fractional) * in[position + 10]; - //sample = lpf[i].Process(sample); - return sample; - }; - - const size_t position_stop = input[0].size() - required_history; - while (state.output_position < output[0].size() && position < position_stop) { - s32 sample0 = step(0); - s32 sample1 = step(1); - - output[0][state.output_position] = sample0; - output[1][state.output_position] = sample0; - output[2][state.output_position] = sample1; - output[3][state.output_position] = sample1; - - position_fractional += rate_change; - position += (size_t)position_fractional; - position_fractional -= (size_t)position_fractional; - - state.output_position++; - } - - bool continue_feeding_me = true; - if (state.output_position >= output[0].size()) { - state.output_position = 0; - continue_feeding_me = false; - } - - for (int j = 0; j < 2; j++) { - std::copy(input[j].begin() + position, - input[j].begin() + position + required_history, - state.history[j].begin()); - if (position + required_history >= input[j].size()) { - input[j].clear(); - } else { - input[j].erase(input[j].begin(), - input[j].begin() + position + required_history); - } - } - - ASSERT(input[0].size() == input[1].size()); - - return std::make_tuple(position, continue_feeding_me); -} - -std::tuple Linear(State& state, DSP::HLE::QuadFrame32& output, std::array, 2>& input, const float rate_change) { - ASSERT(input[0].size() == input[1].size()); - while (input[0].size() < 2) { - input[0].emplace_back(0); - input[1].emplace_back(0); - } - - size_t position = 0; - double& position_fractional = state.position_fractional; - - auto step = [&](size_t i) -> s32 { - auto& in = input[i]; - s32 sample = 0; - sample = position_fractional * in[position + 0] + (1.0 - position_fractional) * in[position + 1]; - return sample; - }; - - const size_t position_stop = input.size() - 1; - while (state.output_position < output.size() && position < position_stop) { - s32 sample0 = step(0); - s32 sample1 = step(1); - - output[state.output_position][0] = sample0; - output[state.output_position][1] = sample0; - output[state.output_position][2] = sample1; - output[state.output_position][3] = sample1; - - position_fractional += rate_change; - position += (size_t)position_fractional; - position_fractional -= (size_t)position_fractional; - - state.output_position++; - } - - bool continue_feeding_me = true; - if (state.output_position >= output[0].size()) { - state.output_position = 0; - continue_feeding_me = false; - } - - for (int j = 0; j < 2; j++) { - if (position >= input[j].size()) { - input[j].clear(); - } else { - input[j].erase(input[j].begin(), - input[j].begin() + position); - } - } - - ASSERT(input[0].size() == input[1].size()); - - return std::make_tuple(position, continue_feeding_me); -} - -std::tuple None(State& state, DSP::HLE::QuadFrame32& output, std::vector>& input, const float rate_change) { - size_t position = 0; - double& position_fractional = state.position_fractional; - - auto step = [&](size_t i) -> s32 { - return input[position][i]; - }; - - const size_t position_stop = input.size(); - while (state.output_position < output.size() && position < position_stop) { - s32 sample0 = step(0); - s32 sample1 = step(1); - - output[state.output_position][0] = sample0; - output[state.output_position][1] = sample0; - output[state.output_position][2] = sample1; - output[state.output_position][3] = sample1; - - position_fractional += rate_change; - position += (size_t)position_fractional; - position_fractional -= (size_t)position_fractional; - - state.output_position++; - } - - bool continue_feeding_me = true; - if (state.output_position >= output.size()) { - state.output_position = 0; - continue_feeding_me = false; - } - - if (position >= input.size()) { - input.clear(); - } else { - input.erase(input.begin(), input.begin() + position); - } - - return std::make_tuple(position, continue_feeding_me); -} - -} diff --git a/src/audio_core/interpolate.h b/src/audio_core/interpolate.h deleted file mode 100644 index d1be5f832..000000000 --- a/src/audio_core/interpolate.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "audio_core/hle/common.h" - -#include "common/common_types.h" - -namespace AudioInterp { - -constexpr size_t required_history = 11; - -struct State { - double position_fractional = 0; - size_t output_position = 0; - std::array, 2> history = {}; -}; - -std::tuple KaiserSinc(State& state, DSP::HLE::QuadFrame32& output, std::array, 2>& input, const float rate_change); - -std::tuple Linear(State& state, DSP::HLE::QuadFrame32& output, std::array, 2>& input, const float rate_change); - -std::tuple None(State& state, DSP::HLE::QuadFrame32& output, std::vector>& input, const float rate_change); - -} diff --git a/src/audio_core/null_sink.cpp b/src/audio_core/null_sink.cpp deleted file mode 100644 index cd5f9e998..000000000 --- a/src/audio_core/null_sink.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. diff --git a/src/audio_core/null_sink.h b/src/audio_core/null_sink.h deleted file mode 100644 index fa7549ece..000000000 --- a/src/audio_core/null_sink.h +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -namespace AudioCore { - -} diff --git a/src/audio_core/sdl2_sink.cpp b/src/audio_core/sdl2_sink.cpp deleted file mode 100644 index b74b5a622..000000000 --- a/src/audio_core/sdl2_sink.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include - -#include "audio_core/audio_core.h" -#include "audio_core/sdl2_sink.h" - -#include "common/assert.h" -#include "common/logging/log.h" - -namespace AudioCore { - -std::unique_ptr sink(new SDL2Sink()); - -SDL2Sink::SDL2Sink() { - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - LOG_CRITICAL(Audio_SDL2, "SDL_Init(SDL_INIT_AUDIO) failed"); - exit(-2); - } - - SDL_AudioSpec desired_audiospec; - SDL_zero(desired_audiospec); - desired_audiospec.format = AUDIO_S16; - desired_audiospec.channels = 2; - desired_audiospec.freq = AudioCore::native_sample_rate; - desired_audiospec.samples = 4096; - desired_audiospec.userdata = this; - desired_audiospec.callback = &SDL2Sink::Callback; // We're going to use SDL_QueueAudio - - SDL_AudioSpec obtained_audiospec; - SDL_zero(obtained_audiospec); - - audio_device_id = SDL_OpenAudioDevice(nullptr, /*iscapture=*/false, &desired_audiospec, &obtained_audiospec, 0); - if (audio_device_id < 0) { - LOG_CRITICAL(Audio_SDL2, "SDL_OpenAudioDevice failed"); - exit(-2); - } - - sample_rate = obtained_audiospec.freq; - - SDL_PauseAudioDevice(audio_device_id, 0); -} - -SDL2Sink::~SDL2Sink() { -} - -/// The native rate of this sink. The sink expects to be fed samples that respect this. (Units: samples/sec) -unsigned SDL2Sink::GetNativeSampleRate() const { - return sample_rate; -} - -/** -* Feed stereo samples to sink. -* @param samples Samples in interleaved stereo PCM16 format. Size of vector must be multiple of two. -*/ -void SDL2Sink::EnqueueSamples(const std::vector& samples) { - ASSERT(samples.size() % 2 == 0); - SDL_LockAudioDevice(audio_device_id); - queue.emplace_back(samples); - SDL_UnlockAudioDevice(audio_device_id); -} - -/// Samples enqueued that have not been played yet. -size_t SDL2Sink::SamplesInQueue() const { - const size_t queue_size = RealQueueSize() + dequeue_consumed; - - if (dequeue_consumed == 0) - return queue_size; - - const std::chrono::duration duration = std::chrono::steady_clock::now() - dequeue_time; - const size_t estimated_samples_consumed = sample_rate * duration.count(); - - if (estimated_samples_consumed > queue_size) - return 0; - - return queue_size - estimated_samples_consumed; -} - -size_t SDL2Sink::RealQueueSize() const { - size_t total_size = 0; - SDL_LockAudioDevice(audio_device_id); - for (const auto& buf : queue) { - total_size += buf.size() / 2; - } - SDL_UnlockAudioDevice(audio_device_id); - return total_size; -} - -void SDL2Sink::Callback(void* sink_, u8* buffer, int buffer_size) { - SDL2Sink* sink = reinterpret_cast(sink_); - buffer_size /= sizeof(s16); // Convert to number of half-samples. - - sink->dequeue_time = std::chrono::steady_clock::now(); - sink->dequeue_consumed = buffer_size / 2; - - while (buffer_size > 0 && !sink->queue.empty()) { - if (sink->queue.front().size() <= buffer_size) { - memcpy(buffer, sink->queue.front().data(), sink->queue.front().size() * sizeof(s16)); - buffer += sink->queue.front().size() * sizeof(s16); - buffer_size -= sink->queue.front().size(); - sink->queue.pop_front(); - } else { - memcpy(buffer, sink->queue.front().data(), buffer_size * sizeof(s16)); - buffer += buffer_size * sizeof(s16); - sink->queue.front().erase(sink->queue.front().begin(), sink->queue.front().begin() + buffer_size); - buffer_size = 0; - } - } - - if (buffer_size > 0) { - sink->dequeue_consumed -= buffer_size / 2; - memset(buffer, 0, buffer_size * sizeof(s16)); - } -} - -} diff --git a/src/audio_core/sdl2_sink.h b/src/audio_core/sdl2_sink.h deleted file mode 100644 index 039ae282e..000000000 --- a/src/audio_core/sdl2_sink.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include - -#include "audio_core/sink.h" - -namespace AudioCore { - -class SDL2Sink final : public Sink { -public: - SDL2Sink(); - ~SDL2Sink() override; - - /// The native rate of this sink. The sink expects to be fed samples that respect this. (Units: samples/sec) - unsigned GetNativeSampleRate() const override; - - /** - * Feed stereo samples to sink. - * @param samples Samples in interleaved stereo PCM16 format. Size of vector must be multiple of two. - */ - void EnqueueSamples(const std::vector& samples) override; - - /// Samples enqueued that have not been played yet. - size_t SamplesInQueue() const override; - -private: - using SDL_AudioDeviceID = u32; - unsigned sample_rate; - SDL_AudioDeviceID audio_device_id; - - std::list> queue; - size_t RealQueueSize() const; - static void Callback(void* sink, u8* buffer, int buffer_size); - - std::chrono::steady_clock::time_point dequeue_time; - size_t dequeue_consumed = 0; -}; - -} diff --git a/src/audio_core/sink.h b/src/audio_core/sink.h index c63219f06..cad21a85e 100644 --- a/src/audio_core/sink.h +++ b/src/audio_core/sink.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include "common/common_types.h" @@ -32,6 +31,4 @@ public: virtual std::size_t SamplesInQueue() const = 0; }; -extern std::unique_ptr sink; - } // namespace diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp deleted file mode 100644 index 867402043..000000000 --- a/src/audio_core/time_stretch.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "audio_core/audio_core.h" -#include "audio_core/sink.h" -#include "audio_core/time_stretch.h" - -#include "common/common_types.h" -#include "common/math_util.h" -#include "common/logging/log.h" - -namespace TimeStretch { - -static soundtouch::SoundTouch soundtouch; - -using steady_clock = std::chrono::steady_clock; - -steady_clock::time_point frame_timer = steady_clock::now(); -double smooth_ratio = 1.0; -void Tick(unsigned samples_in_queue) { - const steady_clock::time_point now = steady_clock::now(); - const std::chrono::duration duration = now - frame_timer; - frame_timer = now; - - constexpr double native_frame_time = (double)AudioCore::samples_per_frame / (double)AudioCore::native_sample_rate; - const double actual_frame_time = duration.count(); - - double ratio = actual_frame_time / native_frame_time; - ratio = MathUtil::Clamp(ratio, 0.01, 100.0); - - // TODO: Uhh was just reading this and this seems super wonky double-check your logic wtf are you thinking. - if (samples_in_queue < 4096) { - ratio = ratio > 1.0 ? ratio * ratio : 1.0; - ratio = MathUtil::Clamp(ratio, 0.01, 100.0); - } else if (AudioCore::sink->SamplesInQueue() > 16000) { - ratio = ratio > 1.0 ? sqrt(ratio) : 0.01; - ratio = MathUtil::Clamp(ratio, 0.01, 100.0); - } - - smooth_ratio = 0.993 * smooth_ratio + 0.007 * ratio; - smooth_ratio = MathUtil::Clamp(smooth_ratio, 0.01, 100.0); - - //printf("%f, %f\n", ratio, smooth_ratio); - - soundtouch.setTempo(1.0 / smooth_ratio); -} - -void Init() { - soundtouch.setTempo(1.0); - soundtouch.setChannels(2); -} - -void Shutdown() { - soundtouch.setTempo(1.0); -} - -void AddSamples(const std::array, AudioCore::samples_per_frame>& samples) { - // FIXME: lol don't do this c-style cast - soundtouch.putSamples((s16*)samples.data(), AudioCore::samples_per_frame); -} - -void OutputSamples(std::function&)> fn) { - size_t available = soundtouch.numSamples(); - - std::vector output(available * 2); - - soundtouch.receiveSamples(output.data(), available); - - fn(output); -} - -} diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h deleted file mode 100644 index 6993f3a15..000000000 --- a/src/audio_core/time_stretch.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include - -#include "common/common_types.h" - -namespace TimeStretch { - -void Init(); -void Shutdown(); - -void Tick(unsigned samples_in_queue); -void AddSamples(const std::array, AudioCore::samples_per_frame>& samples); -void OutputSamples(std::function&)> fn); - -} diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 470eb8f26..6660d9879 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -117,8 +117,6 @@ if (Qt5_FOUND AND MSVC) ) windows_copy_files(citra-qt ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$:d>.*) - windows_copy_files(citra-qt ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll) - unset(Qt5_DLL_DIR) unset(Qt5_PLATFORMS_DIR) unset(DLL_DEST) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 1cc1b432a..3d39f94d5 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -65,7 +65,6 @@ namespace Log { SUB(Render, OpenGL) \ CLS(Audio) \ SUB(Audio, DSP) \ - SUB(Audio, SDL2) \ CLS(Loader) // GetClassName is a macro defined by Windows.h, grrr... diff --git a/src/common/logging/log.h b/src/common/logging/log.h index b5919d590..521362317 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -80,7 +80,6 @@ enum class Class : ClassType { Render_OpenGL, ///< OpenGL backend Audio, ///< Emulator audio output Audio_DSP, ///< The HLE implementation of the DSP - Audio_SDL2, ///< SDL2 frontend for audio output Loader, ///< ROM loader Count ///< Total number of logging classes diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 941c92b36..08e437125 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -20,55 +20,29 @@ namespace DSP_DSP { static u32 read_pipe_count; static Kernel::SharedPtr semaphore_event; -enum class InterruptType { - Zero = 0, // Unknown purpose. Channel is always zero. - One = 1, // Unknown purpose. Channel is always zero. - Pipe = 2, // Related to a pipe - MAX -}; -constexpr size_t InterruptType_MAX = static_cast(InterruptType::MAX); - -/// Map of (interrupt number, channel number) to Kernel::Events. See: RegisterInterruptEvents -static std::array>, InterruptType_MAX> interrupt_events; -constexpr size_t max_number_of_interrupt_events = 6; - -size_t GetNumberOfRegisteredEvents() { - size_t number = 0; - for (const auto& events : interrupt_events) { - number += events.size(); +struct PairHash { + template + std::size_t operator()(const std::pair &x) const { + // TODO(yuriks): Replace with better hash combining function. + return std::hash()(x.first) ^ std::hash()(x.second); } - return number; -} +}; + +/// Map of (audio interrupt number, channel number) to Kernel::Events. See: RegisterInterruptEvents +static std::unordered_map, Kernel::SharedPtr, PairHash> interrupt_events; // DSP Interrupts: -// Interrupt (2, 2) occurs every frame tick. Userland programs normally have a thread that's waiting +// Interrupt #2 occurs every frame tick. Userland programs normally have a thread that's waiting // for an interrupt event. Immediately after this interrupt event, userland normally updates the // state in the next region and increments the relevant frame counter by two. void SignalAllInterrupts() { // HACK: The other interrupts have currently unknown purpose, we trigger them each tick in any case. - for (auto& events : interrupt_events) - for (auto& event : events) - event.second->Signal(); + for (auto& interrupt_event : interrupt_events) + interrupt_event.second->Signal(); } void SignalInterrupt(u32 interrupt, u32 channel) { - ASSERT(interrupt < interrupt_events.size()); - if (interrupt == 0 || interrupt == 1) - ASSERT(channel == 0); - - auto& events = interrupt_events[interrupt]; - if (events.find(channel) != events.end()) { - events[channel]->Signal(); - } -} - -bool SemaphoreSignalled() { - if (semaphore_event->signaled) { - semaphore_event->Clear(); - return true; - } else { - return false; - } + interrupt_events[std::make_pair(interrupt, channel)]->Signal(); } /** @@ -84,7 +58,6 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) { u32 addr = cmd_buff[1]; - cmd_buff[0] = 0xC0080; cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); @@ -140,11 +113,9 @@ static void LoadComponent(Service::Interface* self) { static void GetSemaphoreEventHandle(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[0] = 0x160042; cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[3] = Kernel::g_handle_table.Create(semaphore_event).MoveFrom(); // Event handle - LOG_WARNING(Service_DSP, "(STUBBED) called"); } @@ -186,47 +157,23 @@ static void FlushDataCache(Service::Interface* self) { static void RegisterInterruptEvents(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 type_num = cmd_buff[1]; + u32 interrupt = cmd_buff[1]; u32 channel = cmd_buff[2]; u32 event_handle = cmd_buff[4]; - if (cmd_buff[3] != 0) { - cmd_buff[0] = 0x40; - cmd_buff[1] = 0xD9001830; - return; - } - - InterruptType type = static_cast(type_num); - if (type == InterruptType::Zero || type == InterruptType::One) { - channel = 0; - } else if (type == InterruptType::Pipe) { - if (channel >= DSP::HLE::DspPipe_MAX) { - LOG_ERROR(Service_DSP, "Invalid (type, channel) combination (%u, %u)", type, channel); - } - } else { - // I suspect that interrupt values greater than two are invalid. - LOG_ERROR(Service_DSP, "Unimplemented (type, channel) combination (%u, %u)", type, channel); - UNIMPLEMENTED(); - } - - cmd_buff[0] = 0x150040; if (event_handle) { auto evt = Kernel::g_handle_table.Get(cmd_buff[4]); if (evt) { - if (GetNumberOfRegisteredEvents() < max_number_of_interrupt_events) { - interrupt_events[type_num][channel] = evt; - LOG_INFO(Service_DSP, "Registered type=%u, channel=%u, event_handle=0x%08X", type, channel, event_handle); - } else { - cmd_buff[1] = 0xC860A7FF; - LOG_ERROR(Service_DSP, "Ran out of space to register interrupts"); - } + interrupt_events[std::make_pair(interrupt, channel)] = evt; + cmd_buff[1] = RESULT_SUCCESS.raw; + LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); } else { - LOG_CRITICAL(Service_DSP, "Invalid event handle! type=%u, channel=%u, event_handle=0x%08X", type, channel, event_handle); + LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); ASSERT(false); // This should really be handled at a IPC translation layer. } } else { - interrupt_events[type_num].erase(channel); - LOG_INFO(Service_DSP, "Unregistered type=%u, channel=%u, event_handle=0x%08X", type, channel, event_handle); + interrupt_events.erase(std::make_pair(interrupt, channel)); + LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); } } @@ -240,13 +187,8 @@ static void RegisterInterruptEvents(Service::Interface* self) { static void SetSemaphore(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[0] = 0x70040; cmd_buff[1] = RESULT_SUCCESS.raw; // No error - // Observed Behaviour: Waits for DSP_PSEM to be clear then sets DSP_PSEM. - - SignalAllInterrupts(); // This is a HACK - LOG_WARNING(Service_DSP, "(STUBBED) called"); } @@ -268,13 +210,7 @@ static void WriteProcessPipe(Service::Interface* self) { u32 size = cmd_buff[2]; u32 buffer = cmd_buff[4]; - if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) { - LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe, size, buffer); - cmd_buff[0] = 0x40; - cmd_buff[1] = 0xD9001830; - return; - } - + ASSERT_MSG(IPC::StaticBufferDesc(size, 1) == cmd_buff[3], "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe, size, buffer); ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); std::vector message(size); @@ -285,7 +221,6 @@ static void WriteProcessPipe(Service::Interface* self) { DSP::HLE::PipeWrite(pipe, message); - cmd_buff[0] = 0xD0040; cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); @@ -315,14 +250,16 @@ static void ReadPipeIfPossible(Service::Interface* self) { ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); - cmd_buff[0] = 0x100082; cmd_buff[1] = RESULT_SUCCESS.raw; // No error + if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { + std::vector response = DSP::HLE::PipeRead(pipe, size); - std::vector response = DSP::HLE::PipeRead(pipe, size); + Memory::WriteBlock(addr, response.data(), response.size()); - Memory::WriteBlock(addr, response.data(), response.size()); - - cmd_buff[2] = static_cast(response.size()); + cmd_buff[2] = static_cast(response.size()); + } else { + cmd_buff[2] = 0; // Return no data + } LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); } @@ -396,7 +333,6 @@ static void SetSemaphoreMask(Service::Interface* self) { u32 mask = cmd_buff[1]; - cmd_buff[0] = 0x170040; cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_WARNING(Service_DSP, "(STUBBED) called mask=0x%08X", mask); @@ -414,11 +350,10 @@ static void SetSemaphoreMask(Service::Interface* self) { static void GetHeadphoneStatus(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[0] = 0x1F0080; cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = 0; // Not using headphones? - LOG_TRACE(Service_DSP, "called"); + LOG_WARNING(Service_DSP, "(STUBBED) called"); } /** @@ -441,7 +376,6 @@ static void RecvData(Service::Interface* self) { // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept. - cmd_buff[0] = 0x10080; cmd_buff[1] = RESULT_SUCCESS.raw; switch (DSP::HLE::GetDspState()) { case DSP::HLE::DspState::On: @@ -477,7 +411,6 @@ static void RecvDataIsReady(Service::Interface* self) { ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); - cmd_buff[0] = 0x20080; cmd_buff[1] = RESULT_SUCCESS.raw; cmd_buff[2] = 1; // Ready to read @@ -532,8 +465,7 @@ Interface::Interface() { Interface::~Interface() { semaphore_event = nullptr; - for (auto& events : interrupt_events) - events.clear(); + interrupt_events.clear(); } } // namespace diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h index 990770d43..32b89e9bb 100644 --- a/src/core/hle/service/dsp_dsp.h +++ b/src/core/hle/service/dsp_dsp.h @@ -34,7 +34,4 @@ void SignalAllInterrupts(); */ void SignalInterrupt(u32 interrupt_id, u32 channel_id); -/// Returns true it the application signalled the semaphore, then clears the semaphore. -bool SemaphoreSignalled(); - } // namespace diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 02cf57fc1..11c4d0daf 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -440,7 +440,8 @@ static void DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity, level = Log::Level::Debug; break; } - //LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type), id, message); + LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", + GetSource(source), GetType(type), id, message); } /// Initialize the renderer