| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: RateTransposer.h 63 2009-02-21 16:00:14Z 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 <stddef.h> | ||
| #include "AAFilter.h" | ||
| #include "FIFOSamplePipe.h" | ||
| #include "FIFOSampleBuffer.h" | ||
|
|
||
| #include "STTypes.h" | ||
|
|
||
| namespace soundtouch | ||
| { | ||
|
|
||
| /// A common linear samplerate transposer class. | ||
| /// | ||
| /// Note: Use function "RateTransposer::newInstance()" to create a new class | ||
| /// instance instead of the "new" operator; that function automatically | ||
| /// chooses a correct implementation depending on if integer or floating | ||
| /// arithmetics are to be used. | ||
| class RateTransposer : public FIFOProcessor | ||
| { | ||
| protected: | ||
| /// Anti-alias filter object | ||
| AAFilter *pAAFilter; | ||
|
|
||
| float fRate; | ||
|
|
||
| int numChannels; | ||
|
|
||
| /// Buffer for collecting samples to feed the anti-alias filter between | ||
| /// two batches | ||
| FIFOSampleBuffer storeBuffer; | ||
|
|
||
| /// Buffer for keeping samples between transposing & anti-alias filter | ||
| FIFOSampleBuffer tempBuffer; | ||
|
|
||
| /// Output sample buffer | ||
| FIFOSampleBuffer outputBuffer; | ||
|
|
||
| BOOL bUseAAFilter; | ||
|
|
||
| virtual void resetRegisters() = 0; | ||
|
|
||
| virtual uint transposeStereo(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples) = 0; | ||
| virtual uint transposeMono(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples) = 0; | ||
| inline uint transpose(SAMPLETYPE *dest, | ||
| const SAMPLETYPE *src, | ||
| uint numSamples); | ||
|
|
||
| void downsample(const SAMPLETYPE *src, | ||
| uint numSamples); | ||
| void upsample(const SAMPLETYPE *src, | ||
| uint numSamples); | ||
|
|
||
| /// 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(float 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-12-28 16:53:56 +0200 (Fri, 28 Dec 2012) $ | ||
| // File revision : $Revision: 3 $ | ||
| // | ||
| // $Id: STTypes.h 162 2012-12-28 14:53:56Z 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 | ||
|
|
||
| #ifndef _WINDEF_ | ||
| // if these aren't defined already by Windows headers, define now | ||
| #if defined(__APPLE__) | ||
| typedef signed char BOOL; | ||
| #else | ||
| typedef int BOOL; | ||
| #endif | ||
| #define FALSE 0 | ||
| #define TRUE 1 | ||
|
|
||
| #endif // _WINDEF_ | ||
|
|
||
|
|
||
| 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 (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 | ||
| #ifndef _M_X64 | ||
| #define SOUNDTOUCH_ALLOW_MMX 1 | ||
| #endif | ||
| #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 <assert.h> | ||
| #define ST_THROW_RT_ERROR(x) {assert((const char *)x);} | ||
| #else | ||
| // use c++ standard exceptions | ||
| #include <stdexcept> | ||
| #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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,277 @@ | ||
| ////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-12-28 21:32:59 +0200 (Fri, 28 Dec 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: SoundTouch.h 163 2012-12-28 19:32:59Z 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.7.1" | ||
|
|
||
| /// SoundTouch library version id | ||
| #define SOUNDTOUCH_VERSION_ID (10701) | ||
|
|
||
| // | ||
| // 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. | ||
| float virtualRate; | ||
|
|
||
| /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. | ||
| float virtualTempo; | ||
|
|
||
| /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. | ||
| float virtualPitch; | ||
|
|
||
| /// Flag: Has sample rate been set? | ||
| BOOL bSrateSet; | ||
|
|
||
| /// 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' | ||
| float rate; | ||
|
|
||
| /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' | ||
| float 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(float newRate); | ||
|
|
||
| /// Sets new tempo control value. Normal tempo = 1.0, smaller values | ||
| /// represent slower tempo, larger faster tempo. | ||
| void setTempo(float newTempo); | ||
|
|
||
| /// Sets new rate control value as a difference in percents compared | ||
| /// to the original rate (-50 .. +100 %) | ||
| void setRateChange(float newRate); | ||
|
|
||
| /// Sets new tempo control value as a difference in percents compared | ||
| /// to the original tempo (-50 .. +100 %) | ||
| void setTempoChange(float newTempo); | ||
|
|
||
| /// Sets new pitch control value. Original pitch = 1.0, smaller values | ||
| /// represent lower pitches, larger values higher pitch. | ||
| void setPitch(float newPitch); | ||
|
|
||
| /// Sets pitch change in octaves compared to the original pitch | ||
| /// (-1.00 .. +1.00) | ||
| void setPitchOctaves(float newPitch); | ||
|
|
||
| /// Sets pitch change in semi-tones compared to the original pitch | ||
| /// (-12 .. +12) | ||
| void setPitchSemiTones(int newPitch); | ||
| void setPitchSemiTones(float 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. | ||
| ); | ||
|
|
||
| /// 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| <ItemGroup> | ||
| <Filter Include="Source Files"> | ||
| <UniqueIdentifier>{b7786182-6345-4203-8b48-39eec5ec85dc}</UniqueIdentifier> | ||
| <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions> | ||
| </Filter> | ||
| <Filter Include="Source Files\bpm"> | ||
| <UniqueIdentifier>{75380bb9-1e58-4186-a9cd-ec7cd284e6a5}</UniqueIdentifier> | ||
| </Filter> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <ClCompile Include="AAFilter.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="cpu_detect_x86.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="FIFOSampleBuffer.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="FIRFilter.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="mmx_optimized.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="RateTransposer.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="SoundTouch.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="sse_optimized.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="TDStretch.cpp"> | ||
| <Filter>Source Files</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="BPMDetect.cpp"> | ||
| <Filter>Source Files\bpm</Filter> | ||
| </ClCompile> | ||
| <ClCompile Include="PeakFinder.cpp"> | ||
| <Filter>Source Files\bpm</Filter> | ||
| </ClCompile> | ||
| </ItemGroup> | ||
| <ItemGroup> | ||
| <ClInclude Include="FIFOSampleBuffer.h" /> | ||
| <ClInclude Include="FIFOSamplePipe.h" /> | ||
| <ClInclude Include="FIRFilter.h" /> | ||
| <ClInclude Include="PeakFinder.h" /> | ||
| <ClInclude Include="RateTransposer.h" /> | ||
| <ClInclude Include="SoundTouch.h" /> | ||
| <ClInclude Include="STTypes.h" /> | ||
| <ClInclude Include="TDStretch.h" /> | ||
| <ClInclude Include="AAFilter.h" /> | ||
| <ClInclude Include="BPMDetect.h" /> | ||
| <ClInclude Include="cpu_detect.h" /> | ||
| </ItemGroup> | ||
| </Project> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,268 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-04-01 22:49:30 +0300 (Sun, 01 Apr 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: TDStretch.h 137 2012-04-01 19:49:30Z 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 <stddef.h> | ||
| #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; | ||
| float tempo; | ||
|
|
||
| SAMPLETYPE *pMidBuffer; | ||
| SAMPLETYPE *pMidBufferUnaligned; | ||
| int overlapLength; | ||
| int seekLength; | ||
| int seekWindowLength; | ||
| int overlapDividerBits; | ||
| int slopingDivider; | ||
| float nominalSkip; | ||
| float skipFract; | ||
| FIFOSampleBuffer outputBuffer; | ||
| FIFOSampleBuffer inputBuffer; | ||
| BOOL bQuickSeek; | ||
|
|
||
| int sampleRate; | ||
| int sequenceMs; | ||
| int seekWindowMs; | ||
| int overlapMs; | ||
| BOOL bAutoSeqSetting; | ||
| BOOL bAutoSeekSetting; | ||
|
|
||
| void acceptNewOverlapLength(int newOverlapLength); | ||
|
|
||
| virtual void clearCrossCorrState(); | ||
| void calculateOverlapLength(int overlapMs); | ||
|
|
||
| virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; | ||
|
|
||
| virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos); | ||
| virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); | ||
| int seekBestOverlapPosition(const SAMPLETYPE *refPos); | ||
|
|
||
| virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; | ||
| virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; | ||
|
|
||
| void clearMidBuffer(); | ||
| void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; | ||
|
|
||
| void calcSeqParameters(); | ||
|
|
||
| /// Changes the tempo of the given sound samples. | ||
| /// Returns amount of samples returned in the "output" buffer. | ||
| /// The maximum amount of samples that can be returned at a time is set by | ||
| /// 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(float 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) const; | ||
| 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) const; | ||
| }; | ||
|
|
||
| #endif /// SOUNDTOUCH_ALLOW_SSE | ||
|
|
||
| } | ||
| #endif /// TDStretch_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-11-08 20:44:37 +0200 (Thu, 08 Nov 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: cpu_detect_x86.cpp 159 2012-11-08 18:44:37Z 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 <intrin.h> | ||
| #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 | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,317 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: mmx_optimized.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 "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 <mmintrin.h> | ||
| #include <limits.h> | ||
| #include <math.h> | ||
|
|
||
|
|
||
| // Calculates cross correlation of two buffers | ||
| double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const | ||
| { | ||
| const __m64 *pVec1, *pVec2; | ||
| __m64 shifter; | ||
| __m64 accu, normaccu; | ||
| long corr, norm; | ||
| int i; | ||
|
|
||
| pVec1 = (__m64*)pV1; | ||
| pVec2 = (__m64*)pV2; | ||
|
|
||
| shifter = _m_from_int(overlapDividerBits); | ||
| 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_madd_pi16(pVec1[0], pVec2[0]), | ||
| _mm_madd_pi16(pVec1[1], pVec2[1])); | ||
| temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), | ||
| _mm_madd_pi16(pVec1[1], pVec1[1])); | ||
| accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); | ||
| normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter)); | ||
|
|
||
| temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), | ||
| _mm_madd_pi16(pVec1[3], pVec2[3])); | ||
| temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), | ||
| _mm_madd_pi16(pVec1[3], pVec1[3])); | ||
| accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); | ||
| normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter)); | ||
|
|
||
| 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(); | ||
|
|
||
| // Normalize result by dividing by sqrt(norm) - this step is easiest | ||
| // done using floating point operation | ||
| if (norm == 0) norm = 1; // to avoid div by zero | ||
|
|
||
| return (double)corr / sqrt((double)norm); | ||
| // Note: Warning about the missing EMMS instruction is harmless | ||
| // as it'll be called elsewhere. | ||
| } | ||
|
|
||
|
|
||
|
|
||
| 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(overlapDividerBits + 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() | ||
| { | ||
| 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,361 @@ | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// | ||
| /// 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: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $ | ||
| // File revision : $Revision: 4 $ | ||
| // | ||
| // $Id: sse_optimized.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 "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 <xmmintrin.h> | ||
| #include <math.h> | ||
|
|
||
| // Calculates cross correlation of two buffers | ||
| double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const | ||
| { | ||
| 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; | ||
| double norm = sqrt(pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); | ||
| if (norm < 1e-9) norm = 1.0; // to avoid div by zero | ||
|
|
||
| float *pvSum = (float*)&vSum; | ||
| return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / 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); | ||
| */ | ||
| } | ||
|
|
||
|
|
||
| ////////////////////////////////////////////////////////////////////////////// | ||
| // | ||
| // 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' | ||
| for (j = 0; j < count; j += 2) | ||
| { | ||
| const float *pSrc; | ||
| const __m128 *pFil; | ||
| __m128 sum1, sum2; | ||
| uint i; | ||
|
|
||
| pSrc = (const float*)source; // source 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(dest, _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 | ||
| )); | ||
| source += 4; | ||
| dest += 4; | ||
| } | ||
|
|
||
| // 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // Copyright (C) 2003 Dolphin Project. | ||
|
|
||
| // This program is free software: you can redistribute it and/or modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, version 2.0. | ||
|
|
||
| // This program 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 General Public License 2.0 for more details. | ||
|
|
||
| // A copy of the GPL 2.0 should have been included with the program. | ||
| // If not, see http://www.gnu.org/licenses/ | ||
|
|
||
| // Official SVN repository and contact information can be found at | ||
| // http://code.google.com/p/dolphin-emu/ | ||
|
|
||
| #ifndef _DPL2DECODER_H_ | ||
| #define _DPL2DECODER_H_ | ||
|
|
||
| void dpl2decode(float *samples, int numsamples, float *out); | ||
| void dpl2reset(); | ||
|
|
||
| #endif // _DPL2DECODER_H_ |