1
0
mirror of https://github.com/RPCS3/soundtouch.git synced 2024-09-18 23:42:27 +02:00

dos2unix:ify line endings, source code formatter

This commit is contained in:
Olli 2024-03-29 19:32:39 +02:00
parent 290b0b13e2
commit 63002027de
49 changed files with 10809 additions and 10806 deletions

View File

@ -1,16 +1,16 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
## ##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
## ##
## SoundTouch is free software; you can redistribute it and/or modify it under the ## SoundTouch 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 ## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later ## Foundation; either version 2 of the License, or (at your option) any later
## version. ## version.
## ##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY ## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details. ## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
## ##
## You should have received a copy of the GNU General Public License along with ## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA ## Place - Suite 330, Boston, MA 02111-1307, USA

View File

@ -147,6 +147,9 @@
cmake . cmake .
make -j make -j
make install</pre> make install</pre>
<p>To list available build options:</p>
<pre>
cmake -LH</pre>
<p>To compile the additional portable Shared Library / DLL version with the native C-language API:</p> <p>To compile the additional portable Shared Library / DLL version with the native C-language API:</p>
<pre> <pre>
cmake . -DSOUNDTOUCH_DLL=ON cmake . -DSOUNDTOUCH_DLL=ON

View File

@ -10,7 +10,7 @@ then
elif [ -a configure ] elif [ -a configure ]
then then
configure && $0 --clean configure && $0 --clean
else else
bootstrap && configure && $0 --clean bootstrap && configure && $0 --clean
fi fi

View File

@ -1,205 +1,205 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Beats-per-minute (BPM) detection routine. /// Beats-per-minute (BPM) detection routine.
/// ///
/// The beat detection algorithm works as follows: /// The beat detection algorithm works as follows:
/// - Use function 'inputSamples' to input a chunks of samples to the class for /// - 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 /// 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. /// 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, /// - 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. /// 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 /// Simple averaging is used for anti-alias filtering because the resulting signal
/// quality isn't of that high importance. /// quality isn't of that high importance.
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by /// - 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 /// 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 /// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there. /// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term /// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal. /// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is /// - 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 /// 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. /// function, calculates it's precise location and converts this reading to bpm's.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _BPMDetect_H_ #ifndef _BPMDetect_H_
#define _BPMDetect_H_ #define _BPMDetect_H_
#include <vector> #include <vector>
#include "STTypes.h" #include "STTypes.h"
#include "FIFOSampleBuffer.h" #include "FIFOSampleBuffer.h"
namespace soundtouch namespace soundtouch
{ {
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
#define MIN_BPM 45 #define MIN_BPM 45
/// Maximum allowed BPM rate range. Used for calculating algorithm parametrs /// Maximum allowed BPM rate range. Used for calculating algorithm parametrs
#define MAX_BPM_RANGE 200 #define MAX_BPM_RANGE 200
/// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit. /// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit.
#define MAX_BPM_VALID 190 #define MAX_BPM_VALID 190
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef struct typedef struct
{ {
float pos; float pos;
float strength; float strength;
} BEAT; } BEAT;
class IIR2_filter class IIR2_filter
{ {
double coeffs[5]; double coeffs[5];
double prev[5]; double prev[5];
public: public:
IIR2_filter(const double *lpf_coeffs); IIR2_filter(const double *lpf_coeffs);
float update(float x); float update(float x);
}; };
/// Class for calculating BPM rate for audio data. /// Class for calculating BPM rate for audio data.
class BPMDetect class BPMDetect
{ {
protected: protected:
/// Auto-correlation accumulator bins. /// Auto-correlation accumulator bins.
float *xcorr; float *xcorr;
/// Sample average counter. /// Sample average counter.
int decimateCount; int decimateCount;
/// Sample average accumulator for FIFO-like decimation. /// Sample average accumulator for FIFO-like decimation.
soundtouch::LONG_SAMPLETYPE decimateSum; soundtouch::LONG_SAMPLETYPE decimateSum;
/// Decimate sound by this coefficient to reach approx. 500 Hz. /// Decimate sound by this coefficient to reach approx. 500 Hz.
int decimateBy; int decimateBy;
/// Auto-correlation window length /// Auto-correlation window length
int windowLen; int windowLen;
/// Number of channels (1 = mono, 2 = stereo) /// Number of channels (1 = mono, 2 = stereo)
int channels; int channels;
/// sample rate /// sample rate
int sampleRate; int sampleRate;
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for /// Beginning of auto-correlation window: Autocorrelation isn't being updated for
/// the first these many correlation bins. /// the first these many correlation bins.
int windowStart; int windowStart;
/// window functions for data preconditioning /// window functions for data preconditioning
float *hamw; float *hamw;
float *hamw2; float *hamw2;
// beat detection variables // beat detection variables
int pos; int pos;
int peakPos; int peakPos;
int beatcorr_ringbuffpos; int beatcorr_ringbuffpos;
int init_scaler; int init_scaler;
float peakVal; float peakVal;
float *beatcorr_ringbuff; float *beatcorr_ringbuff;
/// FIFO-buffer for decimated processing samples. /// FIFO-buffer for decimated processing samples.
soundtouch::FIFOSampleBuffer *buffer; soundtouch::FIFOSampleBuffer *buffer;
/// Collection of detected beat positions /// Collection of detected beat positions
//BeatCollection beats; //BeatCollection beats;
std::vector<BEAT> beats; std::vector<BEAT> beats;
// 2nd order low-pass-filter // 2nd order low-pass-filter
IIR2_filter beat_lpf; IIR2_filter beat_lpf;
/// Updates auto-correlation function for given number of decimated samples that /// 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 /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though). /// though).
void updateXCorr(int process_samples /// How many samples are processed. void updateXCorr(int process_samples /// How many samples are processed.
); );
/// Decimates samples to approx. 500 Hz. /// Decimates samples to approx. 500 Hz.
/// ///
/// \return Number of output samples. /// \return Number of output samples.
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
int numsamples ///< Number of source samples. int numsamples ///< Number of source samples.
); );
/// Calculates amplitude envelope for the buffer of samples. /// Calculates amplitude envelope for the buffer of samples.
/// Result is output to 'samples'. /// Result is output to 'samples'.
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
int numsamples ///< Number of samples in buffer int numsamples ///< Number of samples in buffer
); );
/// remove constant bias from xcorr data /// remove constant bias from xcorr data
void removeBias(); void removeBias();
// Detect individual beat positions // Detect individual beat positions
void updateBeatPos(int process_samples); void updateBeatPos(int process_samples);
public: public:
/// Constructor. /// Constructor.
BPMDetect(int numChannels, ///< Number of channels in sample data. BPMDetect(int numChannels, ///< Number of channels in sample data.
int sampleRate ///< Sample rate in Hz. int sampleRate ///< Sample rate in Hz.
); );
/// Destructor. /// Destructor.
virtual ~BPMDetect(); virtual ~BPMDetect();
/// Inputs a block of samples for analyzing: Envelopes the samples and then /// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input /// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm' /// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function. /// function.
/// ///
/// Notice that data in 'samples' array can be disrupted in processing. /// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer int numSamples ///< Number of samples in buffer
); );
/// Analyzes the results and returns the BPM rate. Use this function to read result /// 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 /// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function. /// 'inputSamples' function.
/// ///
/// \return Beats-per-minute rate, or zero if detection failed. /// \return Beats-per-minute rate, or zero if detection failed.
float getBpm(); float getBpm();
/// Get beat position arrays. Note: The array includes also really low beat detection values /// Get beat position arrays. Note: The array includes also really low beat detection values
/// in absence of clear strong beats. Consumer may wish to filter low values away. /// in absence of clear strong beats. Consumer may wish to filter low values away.
/// - "pos" receive array of beat positions /// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths /// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array. /// - max_num indicates max.size of "pos" and "values" array.
/// ///
/// You can query a suitable array sized by calling this with nullptr in "pos" & "values". /// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
/// ///
/// \return number of beats in the arrays. /// \return number of beats in the arrays.
int getBeats(float *pos, float *strength, int max_num); int getBeats(float *pos, float *strength, int max_num);
}; };
} }
#endif // _BPMDetect_H_ #endif // _BPMDetect_H_

View File

@ -1,180 +1,180 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A buffer class for temporarily storaging sound samples, operates as a /// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe. /// first-in-first-out pipe.
/// ///
/// Samples are added to the end of the sample buffer with the 'putSamples' /// 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 /// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the /// the 'receiveSamples' function. The class automatically removes the
/// output samples from the buffer as well as grows the storage size /// output samples from the buffer as well as grows the storage size
/// whenever necessary. /// whenever necessary.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSampleBuffer_H #ifndef FIFOSampleBuffer_H
#define FIFOSampleBuffer_H #define FIFOSampleBuffer_H
#include "FIFOSamplePipe.h" #include "FIFOSamplePipe.h"
namespace soundtouch namespace soundtouch
{ {
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes /// 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. /// 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 /// Notice that in case of stereo audio, one sample is considered to consist of
/// both channel data. /// both channel data.
class FIFOSampleBuffer : public FIFOSamplePipe class FIFOSampleBuffer : public FIFOSamplePipe
{ {
private: private:
/// Sample buffer. /// Sample buffer.
SAMPLETYPE *buffer; SAMPLETYPE *buffer;
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
// 16-byte aligned location of this buffer // 16-byte aligned location of this buffer
SAMPLETYPE *bufferUnaligned; SAMPLETYPE *bufferUnaligned;
/// Sample buffer size in bytes /// Sample buffer size in bytes
uint sizeInBytes; uint sizeInBytes;
/// How many samples are currently in buffer. /// How many samples are currently in buffer.
uint samplesInBuffer; uint samplesInBuffer;
/// Channels, 1=mono, 2=stereo. /// Channels, 1=mono, 2=stereo.
uint channels; uint channels;
/// Current position pointer to the buffer. This pointer is increased when samples are /// 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) /// removed from the pipe so that it's necessary to actually rewind buffer (move data)
/// only new data when is put to the pipe. /// only new data when is put to the pipe.
uint bufferPos; uint bufferPos;
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
/// beginning of the buffer. /// beginning of the buffer.
void rewind(); void rewind();
/// Ensures that the buffer has capacity for at least this many samples. /// Ensures that the buffer has capacity for at least this many samples.
void ensureCapacity(uint capacityRequirement); void ensureCapacity(uint capacityRequirement);
/// Returns current capacity. /// Returns current capacity.
uint getCapacity() const; uint getCapacity() const;
public: public:
/// Constructor /// Constructor
FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
///< Default is stereo. ///< Default is stereo.
); );
/// destructor /// destructor
~FIFOSampleBuffer() override; ~FIFOSampleBuffer() override;
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping! /// Please be careful for not to corrupt the book-keeping!
/// ///
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() override; virtual SAMPLETYPE *ptrBegin() override;
/// Returns a pointer to the end of the used part of the sample buffer (i.e. /// 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 /// 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 /// inserting new samples into the sample buffer directly. Please be careful
/// not corrupt the book-keeping! /// not corrupt the book-keeping!
/// ///
/// When using this function as means for inserting new samples, also remember /// When using this function as means for inserting new samples, also remember
/// to increase the sample count afterwards, by calling the /// to increase the sample count afterwards, by calling the
/// 'putSamples(numSamples)' function. /// 'putSamples(numSamples)' function.
SAMPLETYPE *ptrEnd( SAMPLETYPE *ptrEnd(
uint slackCapacity ///< How much free capacity (in samples) there _at least_ uint slackCapacity ///< How much free capacity (in samples) there _at least_
///< should be so that the caller can successfully insert the ///< should be so that the caller can successfully insert the
///< desired samples to the buffer. If necessary, the function ///< desired samples to the buffer. If necessary, the function
///< grows the buffer size to comply with this requirement. ///< grows the buffer size to comply with this requirement.
); );
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer. /// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert. uint numSamples ///< Number of samples to insert.
) override; ) override;
/// Adjusts the book-keeping to increase number of samples in the buffer without /// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples. /// copying any actual samples.
/// ///
/// This function is used to update the number of samples in the sample buffer /// This function is used to update the number of samples in the sample buffer
/// when accessing the buffer directly with 'ptrEnd' function. Please be /// when accessing the buffer directly with 'ptrEnd' function. Please be
/// careful though! /// careful though!
virtual void putSamples(uint numSamples ///< Number of samples been inserted. virtual void putSamples(uint numSamples ///< Number of samples been inserted.
); );
/// Output samples from beginning of the sample buffer. Copies requested samples to /// 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 /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) override; ) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) override; ) override;
/// Returns number of samples currently available. /// Returns number of samples currently available.
virtual uint numSamples() const override; virtual uint numSamples() const override;
/// Sets number of channels, 1 = mono, 2 = stereo. /// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(int numChannels); void setChannels(int numChannels);
/// Get number of channels /// Get number of channels
int getChannels() int getChannels()
{ {
return channels; return channels;
} }
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const override; virtual int isEmpty() const override;
/// Clears all the samples. /// Clears all the samples.
virtual void clear() override; virtual void clear() override;
/// allow trimming (downwards) amount of samples in pipeline. /// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples /// Returns adjusted amount of samples
uint adjustAmountOfSamples(uint numSamples) override; uint adjustAmountOfSamples(uint numSamples) override;
/// Add silence to end of buffer /// Add silence to end of buffer
void addSilent(uint nSamples); void addSilent(uint nSamples);
}; };
} }
#endif #endif

View File

@ -1,230 +1,230 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound /// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
/// samples by operating like a first-in-first-out pipe: New samples are fed /// 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 /// into one end of the pipe with the 'putSamples' function, and the processed
/// samples are received from the other end with the 'receiveSamples' function. /// samples are received from the other end with the 'receiveSamples' function.
/// ///
/// 'FIFOProcessor' : A base class for classes the do signal processing with /// 'FIFOProcessor' : A base class for classes the do signal processing with
/// the samples while operating like a first-in-first-out pipe. When samples /// the samples while operating like a first-in-first-out pipe. When samples
/// are input with the 'putSamples' function, the class processes them /// are input with the 'putSamples' function, the class processes them
/// and moves the processed samples to the given 'output' pipe object, which /// and moves the processed samples to the given 'output' pipe object, which
/// may be either another processing stage, or a fifo sample buffer object. /// may be either another processing stage, or a fifo sample buffer object.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSamplePipe_H #ifndef FIFOSamplePipe_H
#define FIFOSamplePipe_H #define FIFOSamplePipe_H
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
/// Abstract base class for FIFO (first-in-first-out) sample processing classes. /// Abstract base class for FIFO (first-in-first-out) sample processing classes.
class FIFOSamplePipe class FIFOSamplePipe
{ {
protected: protected:
bool verifyNumberOfChannels(int nChannels) const bool verifyNumberOfChannels(int nChannels) const
{ {
if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS)) if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS))
{ {
return true; return true;
} }
ST_THROW_RT_ERROR("Error: Illegal number of channels"); ST_THROW_RT_ERROR("Error: Illegal number of channels");
return false; return false;
} }
public: public:
// virtual default destructor // virtual default destructor
virtual ~FIFOSamplePipe() {} virtual ~FIFOSamplePipe() {}
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping! /// Please be careful for not to corrupt the book-keeping!
/// ///
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() = 0; virtual SAMPLETYPE *ptrBegin() = 0;
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to /// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer. /// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert. uint numSamples ///< Number of samples to insert.
) = 0; ) = 0;
// Moves samples from the 'other' pipe instance to this instance. // Moves samples from the 'other' pipe instance to this instance.
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
) )
{ {
const uint oNumSamples = other.numSamples(); const uint oNumSamples = other.numSamples();
putSamples(other.ptrBegin(), oNumSamples); putSamples(other.ptrBegin(), oNumSamples);
other.receiveSamples(oNumSamples); other.receiveSamples(oNumSamples);
} }
/// Output samples from beginning of the sample buffer. Copies requested samples to /// 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 /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) = 0; ) = 0;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) = 0; ) = 0;
/// Returns number of samples currently available. /// Returns number of samples currently available.
virtual uint numSamples() const = 0; virtual uint numSamples() const = 0;
// Returns nonzero if there aren't any samples available for outputting. // Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const = 0; virtual int isEmpty() const = 0;
/// Clears all the samples. /// Clears all the samples.
virtual void clear() = 0; virtual void clear() = 0;
/// allow trimming (downwards) amount of samples in pipeline. /// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples /// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples) = 0; virtual uint adjustAmountOfSamples(uint numSamples) = 0;
}; };
/// Base-class for sound processing routines working in FIFO principle. With this base /// 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, /// 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 /// so that samples that are fed into beginning of the pipe automatically go through
/// all the processing stages. /// all the processing stages.
/// ///
/// When samples are input to this class, they're first processed and then put to /// 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 /// 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. /// either other processing stage or a FIFO sample buffer.
class FIFOProcessor :public FIFOSamplePipe class FIFOProcessor :public FIFOSamplePipe
{ {
protected: protected:
/// Internal pipe where processed samples are put. /// Internal pipe where processed samples are put.
FIFOSamplePipe *output; FIFOSamplePipe *output;
/// Sets output pipe. /// Sets output pipe.
void setOutPipe(FIFOSamplePipe *pOutput) void setOutPipe(FIFOSamplePipe *pOutput)
{ {
assert(output == nullptr); assert(output == nullptr);
assert(pOutput != nullptr); assert(pOutput != nullptr);
output = pOutput; output = pOutput;
} }
/// Constructor. Doesn't define output pipe; it has to be set be /// Constructor. Doesn't define output pipe; it has to be set be
/// 'setOutPipe' function. /// 'setOutPipe' function.
FIFOProcessor() FIFOProcessor()
{ {
output = nullptr; output = nullptr;
} }
/// Constructor. Configures output pipe. /// Constructor. Configures output pipe.
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
) )
{ {
output = pOutput; output = pOutput;
} }
/// Destructor. /// Destructor.
virtual ~FIFOProcessor() override virtual ~FIFOProcessor() override
{ {
} }
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping! /// Please be careful for not to corrupt the book-keeping!
/// ///
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() override virtual SAMPLETYPE *ptrBegin() override
{ {
return output->ptrBegin(); return output->ptrBegin();
} }
public: public:
/// Output samples from beginning of the sample buffer. Copies requested samples to /// 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 /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) override ) override
{ {
return output->receiveSamples(outBuffer, maxSamples); return output->receiveSamples(outBuffer, maxSamples);
} }
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) override ) override
{ {
return output->receiveSamples(maxSamples); return output->receiveSamples(maxSamples);
} }
/// Returns number of samples currently available. /// Returns number of samples currently available.
virtual uint numSamples() const override virtual uint numSamples() const override
{ {
return output->numSamples(); return output->numSamples();
} }
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const override virtual int isEmpty() const override
{ {
return output->isEmpty(); return output->isEmpty();
} }
/// allow trimming (downwards) amount of samples in pipeline. /// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples /// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples) override virtual uint adjustAmountOfSamples(uint numSamples) override
{ {
return output->adjustAmountOfSamples(numSamples); return output->adjustAmountOfSamples(numSamples);
} }
}; };
} }
#endif #endif

View File

@ -1,22 +1,22 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
## ##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
## ##
## SoundTouch is free software; you can redistribute it and/or modify it under the ## SoundTouch 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 ## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later ## Foundation; either version 2 of the License, or (at your option) any later
## version. ## version.
## ##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY ## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details. ## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
## ##
## You should have received a copy of the GNU General Public License along with ## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA ## Place - Suite 330, Boston, MA 02111-1307, USA
## I used config/am_include.mk for common definitions ## I used config/am_include.mk for common definitions
include $(top_srcdir)/config/am_include.mk include $(top_srcdir)/config/am_include.mk
pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h

View File

@ -1,190 +1,190 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Common type definitions for SoundTouch audio processing library. /// Common type definitions for SoundTouch audio processing library.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef STTypes_H #ifndef STTypes_H
#define STTypes_H #define STTypes_H
typedef unsigned int uint; typedef unsigned int uint;
typedef unsigned long ulong; typedef unsigned long ulong;
// Patch for MinGW: on Win64 long is 32-bit // Patch for MinGW: on Win64 long is 32-bit
#ifdef _WIN64 #ifdef _WIN64
typedef unsigned long long ulongptr; typedef unsigned long long ulongptr;
#else #else
typedef ulong ulongptr; typedef ulong ulongptr;
#endif #endif
// Helper macro for aligning pointer up to next 16-byte boundary // Helper macro for aligning pointer up to next 16-byte boundary
#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 ) #define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 )
#if (defined(__GNUC__) && !defined(ANDROID)) #if (defined(__GNUC__) && !defined(ANDROID))
// In GCC, include soundtouch_config.h made by config scritps. // In GCC, include soundtouch_config.h made by config scritps.
// Skip this in Android compilation that uses GCC but without configure scripts. // Skip this in Android compilation that uses GCC but without configure scripts.
#include "soundtouch_config.h" #include "soundtouch_config.h"
#endif #endif
namespace soundtouch namespace soundtouch
{ {
/// Max allowed number of channels /// Max allowed number of channels
#define SOUNDTOUCH_MAX_CHANNELS 16 #define SOUNDTOUCH_MAX_CHANNELS 16
/// Activate these undef's to overrule the possible sampletype /// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file: /// setting inherited from some other header file:
//#undef SOUNDTOUCH_INTEGER_SAMPLES //#undef SOUNDTOUCH_INTEGER_SAMPLES
//#undef SOUNDTOUCH_FLOAT_SAMPLES //#undef SOUNDTOUCH_FLOAT_SAMPLES
/// If following flag is defined, always uses multichannel processing /// If following flag is defined, always uses multichannel processing
/// routines also for mono and stero sound. This is for routine testing /// routines also for mono and stero sound. This is for routine testing
/// purposes; output should be same with either routines, yet disabling /// purposes; output should be same with either routines, yet disabling
/// the dedicated mono/stereo processing routines will result in slower /// the dedicated mono/stereo processing routines will result in slower
/// runtime performance so recommendation is to keep this off. /// runtime performance so recommendation is to keep this off.
// #define USE_MULTICH_ALWAYS // #define USE_MULTICH_ALWAYS
#if (defined(__SOFTFP__) && defined(ANDROID)) #if (defined(__SOFTFP__) && defined(ANDROID))
// For Android compilation: Force use of Integer samples in case that // For Android compilation: Force use of Integer samples in case that
// compilation uses soft-floating point emulation - soft-fp is way too slow // compilation uses soft-floating point emulation - soft-fp is way too slow
#undef SOUNDTOUCH_FLOAT_SAMPLES #undef SOUNDTOUCH_FLOAT_SAMPLES
#define SOUNDTOUCH_INTEGER_SAMPLES 1 #define SOUNDTOUCH_INTEGER_SAMPLES 1
#endif #endif
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES) #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
/// Choose either 32bit floating point or 16bit integer sampletype /// Choose either 32bit floating point or 16bit integer sampletype
/// by choosing one of the following defines, unless this selection /// by choosing one of the following defines, unless this selection
/// has already been done in some other file. /// has already been done in some other file.
//// ////
/// Notes: /// Notes:
/// - In Windows environment, choose the sample format with the /// - In Windows environment, choose the sample format with the
/// following defines. /// following defines.
/// - In GNU environment, the floating point samples are used by /// - In GNU environment, the floating point samples are used by
/// default, but integer samples can be chosen by giving the /// default, but integer samples can be chosen by giving the
/// following switch to the configure script: /// following switch to the configure script:
/// ./configure --enable-integer-samples /// ./configure --enable-integer-samples
/// However, if you still prefer to select the sample format here /// However, if you still prefer to select the sample format here
/// also in GNU environment, then please #undef the INTEGER_SAMPLE /// also in GNU environment, then please #undef the INTEGER_SAMPLE
/// and FLOAT_SAMPLE defines first as in comments above. /// and FLOAT_SAMPLE defines first as in comments above.
//#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples //#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples #define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
#endif #endif
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64) #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
/// Define this to allow X86-specific assembler/intrinsic optimizations. /// Define this to allow X86-specific assembler/intrinsic optimizations.
/// Notice that library contains also usual C++ versions of each of these /// Notice that library contains also usual C++ versions of each of these
/// these routines, so if you're having difficulties getting the optimized /// these routines, so if you're having difficulties getting the optimized
/// routines compiled for whatever reason, you may disable these optimizations /// routines compiled for whatever reason, you may disable these optimizations
/// to make the library compile. /// to make the library compile.
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
/// In GNU environment, allow the user to override this setting by /// In GNU environment, allow the user to override this setting by
/// giving the following switch to the configure script: /// giving the following switch to the configure script:
/// ./configure --disable-x86-optimizations /// ./configure --disable-x86-optimizations
/// ./configure --enable-x86-optimizations=no /// ./configure --enable-x86-optimizations=no
#ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS #ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
#endif #endif
#else #else
/// Always disable optimizations when not using a x86 systems. /// Always disable optimizations when not using a x86 systems.
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
#endif #endif
// If defined, allows the SIMD-optimized routines to skip unevenly aligned // If defined, allows the SIMD-optimized routines to skip unevenly aligned
// memory offsets that can cause performance penalty in some SIMD implementations. // memory offsets that can cause performance penalty in some SIMD implementations.
// Causes slight compromise in sound quality. // Causes slight compromise in sound quality.
// #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 // #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
// 16bit integer sample type // 16bit integer sample type
typedef short SAMPLETYPE; typedef short SAMPLETYPE;
// data type for sample accumulation: Use 32bit integer to prevent overflows // data type for sample accumulation: Use 32bit integer to prevent overflows
typedef long LONG_SAMPLETYPE; typedef long LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES #ifdef SOUNDTOUCH_FLOAT_SAMPLES
// check that only one sample type is defined // check that only one sample type is defined
#error "conflicting sample types defined" #error "conflicting sample types defined"
#endif // SOUNDTOUCH_FLOAT_SAMPLES #endif // SOUNDTOUCH_FLOAT_SAMPLES
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow MMX optimizations (not available in X64 mode) // Allow MMX optimizations (not available in X64 mode)
#if (!_M_X64) #if (!_M_X64)
#define SOUNDTOUCH_ALLOW_MMX 1 #define SOUNDTOUCH_ALLOW_MMX 1
#endif #endif
#endif #endif
#else #else
// floating point samples // floating point samples
typedef float SAMPLETYPE; typedef float SAMPLETYPE;
// data type for sample accumulation: Use float also here to enable // data type for sample accumulation: Use float also here to enable
// efficient autovectorization // efficient autovectorization
typedef float LONG_SAMPLETYPE; typedef float LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow SSE optimizations // Allow SSE optimizations
#define SOUNDTOUCH_ALLOW_SSE 1 #define SOUNDTOUCH_ALLOW_SSE 1
#endif #endif
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
#if ((SOUNDTOUCH_ALLOW_SSE) || (__SSE__) || (SOUNDTOUCH_USE_NEON)) #if ((SOUNDTOUCH_ALLOW_SSE) || (__SSE__) || (SOUNDTOUCH_USE_NEON))
#if SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION #if SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION
#define ST_SIMD_AVOID_UNALIGNED #define ST_SIMD_AVOID_UNALIGNED
#endif #endif
#endif #endif
} }
// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: // define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:
// #define ST_NO_EXCEPTION_HANDLING 1 // #define ST_NO_EXCEPTION_HANDLING 1
#ifdef ST_NO_EXCEPTION_HANDLING #ifdef ST_NO_EXCEPTION_HANDLING
// Exceptions disabled. Throw asserts instead if enabled. // Exceptions disabled. Throw asserts instead if enabled.
#include <assert.h> #include <assert.h>
#define ST_THROW_RT_ERROR(x) {assert((const char *)x);} #define ST_THROW_RT_ERROR(x) {assert((const char *)x);}
#else #else
// use c++ standard exceptions // use c++ standard exceptions
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);} #define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
#endif #endif
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" // 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. // 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 // Default is off as such crossover is untypical case and involves a slight sound
// quality compromise. // quality compromise.
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1 //#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1
#endif #endif

View File

@ -1,348 +1,348 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// ///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines. /// SoundTouch - main class for tempo/pitch/rate adjusting routines.
/// ///
/// Notes: /// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream /// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set /// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions. /// desired tempo/pitch/rate settings with the corresponding functions.
/// ///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The /// - 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 /// 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 /// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'. /// from the other end of the pipeline with function 'receiveSamples'.
/// ///
/// - The SoundTouch processing classes require certain sized 'batches' of /// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer /// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for /// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently /// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting. /// make the processed samples available for outputting.
/// ///
/// - For the above reason, the processing routines introduce a certain /// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to /// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither /// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct /// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples. /// relationship with the amount of previously input samples.
/// ///
/// - The tempo/pitch/rate control parameters can be altered during processing. /// - The tempo/pitch/rate control parameters can be altered during processing.
/// Please notice though that they aren't currently protected by semaphores, /// Please notice though that they aren't currently protected by semaphores,
/// so in multi-thread application external semaphore protection may be /// so in multi-thread application external semaphore protection may be
/// required. /// required.
/// ///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying /// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both /// 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 /// 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 /// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls. /// combining the two other controls.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef SoundTouch_H #ifndef SoundTouch_H
#define SoundTouch_H #define SoundTouch_H
#include "FIFOSamplePipe.h" #include "FIFOSamplePipe.h"
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
/// Soundtouch library version string /// Soundtouch library version string
#define SOUNDTOUCH_VERSION "2.3.3" #define SOUNDTOUCH_VERSION "2.3.3"
/// SoundTouch library version id /// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (20303) #define SOUNDTOUCH_VERSION_ID (20303)
// //
// Available setting IDs for the 'setSetting' & 'get_setting' functions: // Available setting IDs for the 'setSetting' & 'get_setting' functions:
/// Enable/disable anti-alias filter in pitch transposer (0 = disable) /// Enable/disable anti-alias filter in pitch transposer (0 = disable)
#define SETTING_USE_AA_FILTER 0 #define SETTING_USE_AA_FILTER 0
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) /// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
#define SETTING_AA_FILTER_LENGTH 1 #define SETTING_AA_FILTER_LENGTH 1
/// Enable/disable quick seeking algorithm in tempo changer routine /// Enable/disable quick seeking algorithm in tempo changer routine
/// (enabling quick seeking lowers CPU utilization but causes a minor sound /// (enabling quick seeking lowers CPU utilization but causes a minor sound
/// quality compromising) /// quality compromising)
#define SETTING_USE_QUICKSEEK 2 #define SETTING_USE_QUICKSEEK 2
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines /// 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. /// to how long sequences the original sound is chopped in the time-stretch algorithm.
/// See "STTypes.h" or README for more information. /// See "STTypes.h" or README for more information.
#define SETTING_SEQUENCE_MS 3 #define SETTING_SEQUENCE_MS 3
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the /// 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 /// 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. /// may look for an optimal joining location when mixing the sound sequences back together.
/// See "STTypes.h" or README for more information. /// See "STTypes.h" or README for more information.
#define SETTING_SEEKWINDOW_MS 4 #define SETTING_SEEKWINDOW_MS 4
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences /// 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 /// 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. /// how long period the two consecutive sequences are let to overlap each other.
/// See "STTypes.h" or README for more information. /// See "STTypes.h" or README for more information.
#define SETTING_OVERLAP_MS 5 #define SETTING_OVERLAP_MS 5
/// Call "getSetting" with this ID to query processing sequence size in samples. /// Call "getSetting" with this ID to query processing sequence size in samples.
/// This value gives approximate value of how many input samples you'll need to /// This value gives approximate value of how many input samples you'll need to
/// feed into SoundTouch after initial buffering to get out a new batch of /// feed into SoundTouch after initial buffering to get out a new batch of
/// output samples. /// output samples.
/// ///
/// This value does not include initial buffering at beginning of a new processing /// This value does not include initial buffering at beginning of a new processing
/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size. /// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size.
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on /// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings. /// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_INPUT_SEQUENCE 6 #define SETTING_NOMINAL_INPUT_SEQUENCE 6
/// Call "getSetting" with this ID to query nominal average processing output /// Call "getSetting" with this ID to query nominal average processing output
/// size in samples. This value tells approcimate value how many output samples /// 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. /// SoundTouch outputs once it does DSP processing run for a batch of input samples.
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on /// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings. /// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 #define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
/// Call "getSetting" with this ID to query initial processing latency, i.e. /// Call "getSetting" with this ID to query initial processing latency, i.e.
/// approx. how many samples you'll need to enter to SoundTouch pipeline before /// approx. how many samples you'll need to enter to SoundTouch pipeline before
/// you can expect to get first batch of ready output samples out. /// you can expect to get first batch of ready output samples out.
/// ///
/// After the first output batch, you can then expect to get approx. /// After the first output batch, you can then expect to get approx.
/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every /// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every
/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch. /// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.
/// ///
/// Example: /// Example:
/// processing with parameter -tempo=5 /// processing with parameter -tempo=5
/// => initial latency = 5509 samples /// => initial latency = 5509 samples
/// input sequence = 4167 samples /// input sequence = 4167 samples
/// output sequence = 3969 samples /// output sequence = 3969 samples
/// ///
/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of /// Accordingly, you can expect to feed in approx. 5509 samples at beginning of
/// the stream, and then you'll get out the first 3969 samples. After that, for /// the stream, and then you'll get out the first 3969 samples. After that, for
/// every approx. 4167 samples that you'll put in, you'll receive again approx. /// every approx. 4167 samples that you'll put in, you'll receive again approx.
/// 3969 samples out. /// 3969 samples out.
/// ///
/// This also means that average latency during stream processing is /// This also means that average latency during stream processing is
/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2 /// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2
/// = 3524 samples /// = 3524 samples
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on /// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings. /// tempo/pitch/rate/samplerate settings.
#define SETTING_INITIAL_LATENCY 8 #define SETTING_INITIAL_LATENCY 8
class SoundTouch : public FIFOProcessor class SoundTouch : public FIFOProcessor
{ {
private: private:
/// Rate transposer class instance /// Rate transposer class instance
class RateTransposer *pRateTransposer; class RateTransposer *pRateTransposer;
/// Time-stretch class instance /// Time-stretch class instance
class TDStretch *pTDStretch; class TDStretch *pTDStretch;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
double virtualRate; double virtualRate;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
double virtualTempo; double virtualTempo;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
double virtualPitch; double virtualPitch;
/// Flag: Has sample rate been set? /// Flag: Has sample rate been set?
bool bSrateSet; bool bSrateSet;
/// Accumulator for how many samples in total will be expected as output vs. samples put in, /// Accumulator for how many samples in total will be expected as output vs. samples put in,
/// considering current processing settings. /// considering current processing settings.
double samplesExpectedOut; double samplesExpectedOut;
/// Accumulator for how many samples in total have been read out from the processing so far /// Accumulator for how many samples in total have been read out from the processing so far
long samplesOutput; long samplesOutput;
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
/// 'virtualPitch' parameters. /// 'virtualPitch' parameters.
void calcEffectiveRateAndTempo(); void calcEffectiveRateAndTempo();
protected : protected :
/// Number of channels /// Number of channels
uint channels; uint channels;
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
double rate; double rate;
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
double tempo; double tempo;
public: public:
SoundTouch(); SoundTouch();
virtual ~SoundTouch() override; virtual ~SoundTouch() override;
/// Get SoundTouch library version string /// Get SoundTouch library version string
static const char *getVersionString(); static const char *getVersionString();
/// Get SoundTouch library version Id /// Get SoundTouch library version Id
static uint getVersionId(); static uint getVersionId();
/// Sets new rate control value. Normal rate = 1.0, smaller values /// Sets new rate control value. Normal rate = 1.0, smaller values
/// represent slower rate, larger faster rates. /// represent slower rate, larger faster rates.
void setRate(double newRate); void setRate(double newRate);
/// Sets new tempo control value. Normal tempo = 1.0, smaller values /// Sets new tempo control value. Normal tempo = 1.0, smaller values
/// represent slower tempo, larger faster tempo. /// represent slower tempo, larger faster tempo.
void setTempo(double newTempo); void setTempo(double newTempo);
/// Sets new rate control value as a difference in percents compared /// Sets new rate control value as a difference in percents compared
/// to the original rate (-50 .. +100 %) /// to the original rate (-50 .. +100 %)
void setRateChange(double newRate); void setRateChange(double newRate);
/// Sets new tempo control value as a difference in percents compared /// Sets new tempo control value as a difference in percents compared
/// to the original tempo (-50 .. +100 %) /// to the original tempo (-50 .. +100 %)
void setTempoChange(double newTempo); void setTempoChange(double newTempo);
/// Sets new pitch control value. Original pitch = 1.0, smaller values /// Sets new pitch control value. Original pitch = 1.0, smaller values
/// represent lower pitches, larger values higher pitch. /// represent lower pitches, larger values higher pitch.
void setPitch(double newPitch); void setPitch(double newPitch);
/// Sets pitch change in octaves compared to the original pitch /// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00) /// (-1.00 .. +1.00)
void setPitchOctaves(double newPitch); void setPitchOctaves(double newPitch);
/// Sets pitch change in semi-tones compared to the original pitch /// Sets pitch change in semi-tones compared to the original pitch
/// (-12 .. +12) /// (-12 .. +12)
void setPitchSemiTones(int newPitch); void setPitchSemiTones(int newPitch);
void setPitchSemiTones(double newPitch); void setPitchSemiTones(double newPitch);
/// Sets the number of channels, 1 = mono, 2 = stereo /// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(uint numChannels); void setChannels(uint numChannels);
/// Sets sample rate. /// Sets sample rate.
void setSampleRate(uint srate); void setSampleRate(uint srate);
/// Get ratio between input and output audio durations, useful for calculating /// Get ratio between input and output audio durations, useful for calculating
/// processed output duration: if you'll process a stream of N samples, then /// processed output duration: if you'll process a stream of N samples, then
/// you can expect to get out N * getInputOutputSampleRatio() samples. /// you can expect to get out N * getInputOutputSampleRatio() samples.
/// ///
/// This ratio will give accurate target duration ratio for a full audio track, /// This ratio will give accurate target duration ratio for a full audio track,
/// given that the the whole track is processed with same processing parameters. /// given that the the whole track is processed with same processing parameters.
/// ///
/// If this ratio is applied to calculate intermediate offsets inside a processing /// If this ratio is applied to calculate intermediate offsets inside a processing
/// stream, then this ratio is approximate and can deviate +- some tens of milliseconds /// stream, then this ratio is approximate and can deviate +- some tens of milliseconds
/// from ideal offset, yet by end of the audio stream the duration ratio will become /// from ideal offset, yet by end of the audio stream the duration ratio will become
/// exact. /// exact.
/// ///
/// Example: if processing with parameters "-tempo=15 -pitch=-3", the function /// Example: if processing with parameters "-tempo=15 -pitch=-3", the function
/// will return value 0.8695652... Now, if processing an audio stream whose duration /// will return value 0.8695652... Now, if processing an audio stream whose duration
/// is exactly one million audio samples, then you can expect the processed /// is exactly one million audio samples, then you can expect the processed
/// output duration be 0.869565 * 1000000 = 869565 samples. /// output duration be 0.869565 * 1000000 = 869565 samples.
double getInputOutputSampleRatio(); double getInputOutputSampleRatio();
/// Flushes the last samples from the processing pipeline to the output. /// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers. /// Clears also the internal processing buffers.
// //
/// Note: This function is meant for extracting the last samples of a sound /// Note: This function is meant for extracting the last samples of a sound
/// stream. This function may introduce additional blank samples in the end /// stream. This function may introduce additional blank samples in the end
/// of the sound stream, and thus it's not recommended to call this function /// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream. /// in the middle of a sound stream.
void flush(); void flush();
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into /// 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 /// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception. /// calling this function, otherwise throws a runtime_error exception.
virtual void putSamples( virtual void putSamples(
const SAMPLETYPE *samples, ///< Pointer to sample buffer. const SAMPLETYPE *samples, ///< Pointer to sample buffer.
uint numSamples ///< Number of samples in buffer. Notice uint numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample ///< that in case of stereo-sound a single sample
///< contains data for both channels. ///< contains data for both channels.
) override; ) override;
/// Output samples from beginning of the sample buffer. Copies requested samples to /// 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 /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) override; ) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) override; ) override;
/// Clears all the samples in the object's output and internal processing /// Clears all the samples in the object's output and internal processing
/// buffers. /// buffers.
virtual void clear() override; virtual void clear() override;
/// Changes a setting controlling the processing system behaviour. See the /// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's. /// 'SETTING_...' defines for available setting ID's.
/// ///
/// \return 'true' if the setting was successfully changed /// \return 'true' if the setting was successfully changed
bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
int value ///< New setting value. int value ///< New setting value.
); );
/// Reads a setting controlling the processing system behaviour. See the /// Reads a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's. /// 'SETTING_...' defines for available setting ID's.
/// ///
/// \return the setting value. /// \return the setting value.
int getSetting(int settingId ///< Setting ID number, see SETTING_... defines. int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
) const; ) const;
/// Returns number of samples currently unprocessed. /// Returns number of samples currently unprocessed.
virtual uint numUnprocessedSamples() const; virtual uint numUnprocessedSamples() const;
/// Return number of channels /// Return number of channels
uint numChannels() const uint numChannels() const
{ {
return channels; return channels;
} }
/// Other handy functions that are implemented in the ancestor classes (see /// Other handy functions that are implemented in the ancestor classes (see
/// classes 'FIFOProcessor' and 'FIFOSamplePipe') /// classes 'FIFOProcessor' and 'FIFOSamplePipe')
/// ///
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
/// - numSamples() : Get number of 'ready' samples that can be received with /// - numSamples() : Get number of 'ready' samples that can be received with
/// function 'receiveSamples()' /// function 'receiveSamples()'
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
/// - clear() : Clears all samples from ready/processing buffers. /// - clear() : Clears all samples from ready/processing buffers.
}; };
} }
#endif #endif

View File

@ -8,7 +8,7 @@
# It also defines some flags to the configure script for specifying # It also defines some flags to the configure script for specifying
# the location to search for libSoundTouch # the location to search for libSoundTouch
# #
# A user of libSoundTouch should add @SOUNDTOUCH_LIBS@ and # A user of libSoundTouch should add @SOUNDTOUCH_LIBS@ and
# @SOUNDTOUCH_CXXFLAGS@ to the appropriate variables in his # @SOUNDTOUCH_CXXFLAGS@ to the appropriate variables in his
# Makefile.am files # Makefile.am files
# #
@ -32,10 +32,10 @@ AC_DEFUN([AM_PATH_SOUNDTOUCH],[
then then
saved_CPPFLAGS="$CPPFLAGS" saved_CPPFLAGS="$CPPFLAGS"
saved_LDFLAGS="$LDFLAGS" saved_LDFLAGS="$LDFLAGS"
CPPFLAGS="$CPPFLAGS -I$soundtouch_prefix/include" CPPFLAGS="$CPPFLAGS -I$soundtouch_prefix/include"
LDFLAGS="$LDFLAGS -L$soundtouch_prefix/lib" LDFLAGS="$LDFLAGS -L$soundtouch_prefix/lib"
dnl make sure SoundTouch.h header file exists dnl make sure SoundTouch.h header file exists
dnl could use AC_CHECK_HEADERS to check for all of them, but the supporting .h file names may change later dnl could use AC_CHECK_HEADERS to check for all of them, but the supporting .h file names may change later
AC_CHECK_HEADER([soundtouch/SoundTouch.h],[ AC_CHECK_HEADER([soundtouch/SoundTouch.h],[
@ -49,7 +49,7 @@ AC_DEFUN([AM_PATH_SOUNDTOUCH],[
dnl run action-if-found dnl run action-if-found
ifelse([$2], , :, [$2]) ifelse([$2], , :, [$2])
],[ ],[
dnl run action-if-not-found dnl run action-if-not-found
ifelse([$3], , :, [$3]) ifelse([$3], , :, [$3])
]) ])

View File

@ -1,258 +1,258 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Example Interface class for SoundTouch native compilation /// Example Interface class for SoundTouch native compilation
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// WWW : http://www.surina.net /// WWW : http://www.surina.net
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <jni.h> #include <jni.h>
#include <android/log.h> #include <android/log.h>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
using namespace std; using namespace std;
#include "../../../include/SoundTouch.h" #include "../../../include/SoundTouch.h"
#include "../source/SoundStretch/WavFile.h" #include "../source/SoundStretch/WavFile.h"
#define LOGV(...) __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__) #define LOGV(...) __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
//#define LOGV(...) //#define LOGV(...)
// String for keeping possible c++ exception error messages. Notice that this isn't // String for keeping possible c++ exception error messages. Notice that this isn't
// thread-safe but it's expected that exceptions are special situations that won't // thread-safe but it's expected that exceptions are special situations that won't
// occur in several threads in parallel. // occur in several threads in parallel.
static string _errMsg = ""; static string _errMsg = "";
#define DLL_PUBLIC __attribute__ ((visibility ("default"))) #define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define BUFF_SIZE 4096 #define BUFF_SIZE 4096
using namespace soundtouch; using namespace soundtouch;
// Set error message to return // Set error message to return
static void _setErrmsg(const char *msg) static void _setErrmsg(const char *msg)
{ {
_errMsg = msg; _errMsg = msg;
} }
#if 0 // apparently following workaround not needed any more with concurrent Android SDKs #if 0 // apparently following workaround not needed any more with concurrent Android SDKs
#ifdef _OPENMP #ifdef _OPENMP
#include <pthread.h> #include <pthread.h>
extern pthread_key_t gomp_tls_key; extern pthread_key_t gomp_tls_key;
static void * _p_gomp_tls = nullptr; static void * _p_gomp_tls = nullptr;
/// Function to initialize threading for OpenMP. /// Function to initialize threading for OpenMP.
/// ///
/// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if /// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if
/// called from the Android App main thread because in the main thread the gomp_tls storage is /// called from the Android App main thread because in the main thread the gomp_tls storage is
/// properly set, however, Android does not properly initialize gomp_tls storage for other threads. /// properly set, however, Android does not properly initialize gomp_tls storage for other threads.
/// Thus if OpenMP routines are invoked from some other thread than the main thread, /// Thus if OpenMP routines are invoked from some other thread than the main thread,
/// the OpenMP routine will crash the application due to nullptr access on uninitialized storage. /// the OpenMP routine will crash the application due to nullptr access on uninitialized storage.
/// ///
/// This workaround stores the gomp_tls storage from main thread, and copies to other threads. /// This workaround stores the gomp_tls storage from main thread, and copies to other threads.
/// In order this to work, the Application main thread needws to call at least "getVersionString" /// In order this to work, the Application main thread needws to call at least "getVersionString"
/// routine. /// routine.
static int _init_threading(bool warn) static int _init_threading(bool warn)
{ {
void *ptr = pthread_getspecific(gomp_tls_key); void *ptr = pthread_getspecific(gomp_tls_key);
LOGV("JNI thread-specific TLS storage %ld", (long)ptr); LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
if (ptr == nullptr) if (ptr == nullptr)
{ {
LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls); LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
pthread_setspecific(gomp_tls_key, _p_gomp_tls); pthread_setspecific(gomp_tls_key, _p_gomp_tls);
} }
else else
{ {
LOGV("JNI store this TLS storage"); LOGV("JNI store this TLS storage");
_p_gomp_tls = ptr; _p_gomp_tls = ptr;
} }
// Where critical, show warning if storage still not properly initialized // Where critical, show warning if storage still not properly initialized
if ((warn) && (_p_gomp_tls == nullptr)) if ((warn) && (_p_gomp_tls == nullptr))
{ {
_setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!"); _setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
return -1; return -1;
} }
return 0; return 0;
} }
#else #else
static int _init_threading(bool warn) static int _init_threading(bool warn)
{ {
// do nothing if not OpenMP build // do nothing if not OpenMP build
return 0; return 0;
} }
#endif #endif
#endif #endif
// Processes the sound file // Processes the sound file
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName) static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
{ {
int nSamples; int nSamples;
int nChannels; int nChannels;
int buffSizeSamples; int buffSizeSamples;
SAMPLETYPE sampleBuffer[BUFF_SIZE]; SAMPLETYPE sampleBuffer[BUFF_SIZE];
// open input file // open input file
WavInFile inFile(inFileName); WavInFile inFile(inFileName);
int sampleRate = inFile.getSampleRate(); int sampleRate = inFile.getSampleRate();
int bits = inFile.getNumBits(); int bits = inFile.getNumBits();
nChannels = inFile.getNumChannels(); nChannels = inFile.getNumChannels();
// create output file // create output file
WavOutFile outFile(outFileName, sampleRate, bits, nChannels); WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
pSoundTouch->setSampleRate(sampleRate); pSoundTouch->setSampleRate(sampleRate);
pSoundTouch->setChannels(nChannels); pSoundTouch->setChannels(nChannels);
assert(nChannels > 0); assert(nChannels > 0);
buffSizeSamples = BUFF_SIZE / nChannels; buffSizeSamples = BUFF_SIZE / nChannels;
// Process samples read from the input file // Process samples read from the input file
while (inFile.eof() == 0) while (inFile.eof() == 0)
{ {
int num; int num;
// Read a chunk of samples from the input file // Read a chunk of samples from the input file
num = inFile.read(sampleBuffer, BUFF_SIZE); num = inFile.read(sampleBuffer, BUFF_SIZE);
nSamples = num / nChannels; nSamples = num / nChannels;
// Feed the samples into SoundTouch processor // Feed the samples into SoundTouch processor
pSoundTouch->putSamples(sampleBuffer, nSamples); pSoundTouch->putSamples(sampleBuffer, nSamples);
// Read ready samples from SoundTouch processor & write them output file. // Read ready samples from SoundTouch processor & write them output file.
// NOTES: // NOTES:
// - 'receiveSamples' doesn't necessarily return any samples at all // - 'receiveSamples' doesn't necessarily return any samples at all
// during some rounds! // during some rounds!
// - On the other hand, during some round 'receiveSamples' may have more // - On the other hand, during some round 'receiveSamples' may have more
// ready samples than would fit into 'sampleBuffer', and for this reason // ready samples than would fit into 'sampleBuffer', and for this reason
// the 'receiveSamples' call is iterated for as many times as it // the 'receiveSamples' call is iterated for as many times as it
// outputs samples. // outputs samples.
do do
{ {
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels); outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0); } while (nSamples != 0);
} }
// Now the input file is processed, yet 'flush' few last samples that are // Now the input file is processed, yet 'flush' few last samples that are
// hiding in the SoundTouch's internal processing pipeline. // hiding in the SoundTouch's internal processing pipeline.
pSoundTouch->flush(); pSoundTouch->flush();
do do
{ {
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels); outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0); } while (nSamples != 0);
} }
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz) extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
{ {
const char *verStr; const char *verStr;
LOGV("JNI call SoundTouch.getVersionString"); LOGV("JNI call SoundTouch.getVersionString");
// Call example SoundTouch routine // Call example SoundTouch routine
verStr = SoundTouch::getVersionString(); verStr = SoundTouch::getVersionString();
// gomp_tls storage bug workaround - see comments in _init_threading() function! // gomp_tls storage bug workaround - see comments in _init_threading() function!
// update: apparently this is not needed any more with concurrent Android SDKs // update: apparently this is not needed any more with concurrent Android SDKs
// _init_threading(false); // _init_threading(false);
int threads = 0; int threads = 0;
#pragma omp parallel #pragma omp parallel
{ {
#pragma omp atomic #pragma omp atomic
threads ++; threads ++;
} }
LOGV("JNI thread count %d", threads); LOGV("JNI thread count %d", threads);
// return version as string // return version as string
return env->NewStringUTF(verStr); return env->NewStringUTF(verStr);
} }
extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz) extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
{ {
return (jlong)(new SoundTouch()); return (jlong)(new SoundTouch());
} }
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle) extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
{ {
SoundTouch *ptr = (SoundTouch*)handle; SoundTouch *ptr = (SoundTouch*)handle;
delete ptr; delete ptr;
} }
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo) extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
{ {
SoundTouch *ptr = (SoundTouch*)handle; SoundTouch *ptr = (SoundTouch*)handle;
ptr->setTempo(tempo); ptr->setTempo(tempo);
} }
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch) extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
{ {
SoundTouch *ptr = (SoundTouch*)handle; SoundTouch *ptr = (SoundTouch*)handle;
ptr->setPitchSemiTones(pitch); ptr->setPitchSemiTones(pitch);
} }
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed) extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
{ {
SoundTouch *ptr = (SoundTouch*)handle; SoundTouch *ptr = (SoundTouch*)handle;
ptr->setRate(speed); ptr->setRate(speed);
} }
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz) extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
{ {
jstring result = env->NewStringUTF(_errMsg.c_str()); jstring result = env->NewStringUTF(_errMsg.c_str());
_errMsg.clear(); _errMsg.clear();
return result; return result;
} }
extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile) extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
{ {
SoundTouch *ptr = (SoundTouch*)handle; SoundTouch *ptr = (SoundTouch*)handle;
const char *inputFile = env->GetStringUTFChars(jinputFile, 0); const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
const char *outputFile = env->GetStringUTFChars(joutputFile, 0); const char *outputFile = env->GetStringUTFChars(joutputFile, 0);
LOGV("JNI process file %s", inputFile); LOGV("JNI process file %s", inputFile);
/// gomp_tls storage bug workaround - see comments in _init_threading() function! /// gomp_tls storage bug workaround - see comments in _init_threading() function!
// update: apparently this is not needed any more with concurrent Android SDKs // update: apparently this is not needed any more with concurrent Android SDKs
// if (_init_threading(true)) return -1; // if (_init_threading(true)) return -1;
try try
{ {
_processFile(ptr, inputFile, outputFile); _processFile(ptr, inputFile, outputFile);
} }
catch (const runtime_error &e) catch (const runtime_error &e)
{ {
const char *err = e.what(); const char *err = e.what();
// An exception occurred during processing, return the error message // An exception occurred during processing, return the error message
LOGV("JNI exception in SoundTouch::processFile: %s", err); LOGV("JNI exception in SoundTouch::processFile: %s", err);
_setErrmsg(err); _setErrmsg(err);
return -1; return -1;
} }
env->ReleaseStringUTFChars(jinputFile, inputFile); env->ReleaseStringUTFChars(jinputFile, inputFile);
env->ReleaseStringUTFChars(joutputFile, outputFile); env->ReleaseStringUTFChars(joutputFile, outputFile);
return 0; return 0;
} }

View File

@ -1,24 +1,24 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
## ##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
## ##
## SoundTouch is free software; you can redistribute it and/or modify it under the ## SoundTouch 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 ## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later ## Foundation; either version 2 of the License, or (at your option) any later
## version. ## version.
## ##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY ## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details. ## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
## ##
## You should have received a copy of the GNU General Public License along with ## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA ## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk include $(top_srcdir)/config/am_include.mk
SUBDIRS=SoundTouch SoundStretch SoundTouchDLL SUBDIRS=SoundTouch SoundStretch SoundTouchDLL
# set to something if you want other stuff to be included in the distribution tarball # set to something if you want other stuff to be included in the distribution tarball
#EXTRA_DIST= #EXTRA_DIST=

View File

@ -1,50 +1,50 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
## ##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
## ##
## SoundTouch is free software; you can redistribute it and/or modify it under the ## SoundTouch 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 ## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later ## Foundation; either version 2 of the License, or (at your option) any later
## version. ## version.
## ##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY ## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details. ## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
## ##
## You should have received a copy of the GNU General Public License along with ## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA ## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk include $(top_srcdir)/config/am_include.mk
## bin_PROGRAMS is the macro that tells automake the name of the programs to ## bin_PROGRAMS is the macro that tells automake the name of the programs to
## install in the bin directory (/usr/local/bin) by default. By setting ## install in the bin directory (/usr/local/bin) by default. By setting
## --prefix= at configure time the user can change this (eg: ./configure ## --prefix= at configure time the user can change this (eg: ./configure
## --prefix=/usr will install soundstretch under /usr/bin/soundstretch ) ## --prefix=/usr will install soundstretch under /usr/bin/soundstretch )
bin_PROGRAMS=soundstretch bin_PROGRAMS=soundstretch
noinst_HEADERS=RunParameters.h WavFile.h noinst_HEADERS=RunParameters.h WavFile.h
# extra files to include in distribution tarball # extra files to include in distribution tarball
EXTRA_DIST=soundstretch.sln soundstretch.vcxproj EXTRA_DIST=soundstretch.sln soundstretch.vcxproj
## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists ## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists
## all the sources in the current directory that are used to build soundstretch. ## all the sources in the current directory that are used to build soundstretch.
soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp
## soundstretch_LDADD is a list of extras to pass at link time. All the objects ## soundstretch_LDADD is a list of extras to pass at link time. All the objects
## created by the above soundstretch_SOURCES are automatically linked in, so here I ## created by the above soundstretch_SOURCES are automatically linked in, so here I
## list object files from other directories as well as flags passed to the ## list object files from other directories as well as flags passed to the
## linker. ## linker.
soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm
## linker flags. ## linker flags.
# Linker flag -s disabled to prevent stripping symbols by default # Linker flag -s disabled to prevent stripping symbols by default
#soundstretch_LDFLAGS=-s #soundstretch_LDFLAGS=-s
## additional compiler flags ## additional compiler flags
soundstretch_CXXFLAGS=$(AM_CXXFLAGS) soundstretch_CXXFLAGS=$(AM_CXXFLAGS)
#clean-local: #clean-local:
# -rm -f additional-files-to-remove-on-make-clean # -rm -f additional-files-to-remove-on-make-clean

View File

@ -1,292 +1,292 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A class for parsing the 'soundstretch' application command line parameters /// A class for parsing the 'soundstretch' application command line parameters
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <string> #include <string>
#include <cstdlib> #include <cstdlib>
#include "RunParameters.h" #include "RunParameters.h"
using namespace std; using namespace std;
namespace soundstretch namespace soundstretch
{ {
// Program usage instructions // Program usage instructions
static const char licenseText[] = static const char licenseText[] =
" LICENSE:\n" " LICENSE:\n"
" ========\n" " ========\n"
" \n" " \n"
" SoundTouch sound processing library\n" " SoundTouch sound processing library\n"
" Copyright (c) Olli Parviainen\n" " Copyright (c) Olli Parviainen\n"
" \n" " \n"
" This library is free software; you can redistribute it and/or\n" " This library is free software; you can redistribute it and/or\n"
" modify it under the terms of the GNU Lesser General Public\n" " modify it under the terms of the GNU Lesser General Public\n"
" License version 2.1 as published by the Free Software Foundation.\n" " License version 2.1 as published by the Free Software Foundation.\n"
" \n" " \n"
" This library is distributed in the hope that it will be useful,\n" " This library is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
" Lesser General Public License for more details.\n" " Lesser General Public License for more details.\n"
" \n" " \n"
" You should have received a copy of the GNU Lesser General Public\n" " You should have received a copy of the GNU Lesser General Public\n"
" License along with this library; if not, write to the Free Software\n" " License along with this library; if not, write to the Free Software\n"
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
" \n" " \n"
"This application is distributed with full source codes; however, if you\n" "This application is distributed with full source codes; however, if you\n"
"didn't receive them, please visit the author's homepage (see the link above)."; "didn't receive them, please visit the author's homepage (see the link above).";
static const char whatText[] = static const char whatText[] =
"This application processes WAV audio files by modifying the sound tempo,\n" "This application processes WAV audio files by modifying the sound tempo,\n"
"pitch and playback rate properties independently from each other.\n" "pitch and playback rate properties independently from each other.\n"
"\n"; "\n";
static const char usage[] = static const char usage[] =
"Usage :\n" "Usage :\n"
" soundstretch infilename outfilename [switches]\n" " soundstretch infilename outfilename [switches]\n"
"\n" "\n"
"To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n" "To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
"\n" "\n"
"Available switches are:\n" "Available switches are:\n"
" -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n" " -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
" -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n" " -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"
" -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n" " -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n"
" -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n" " -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"
" If '=n' is omitted, just detects the BPM rate.\n" " If '=n' is omitted, just detects the BPM rate.\n"
" -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n" " -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n"
" -naa : Don't use anti-alias filtering (gain speed, lose quality)\n" " -naa : Don't use anti-alias filtering (gain speed, lose quality)\n"
" -speech : Tune algorithm for speech processing (default is for music)\n" " -speech : Tune algorithm for speech processing (default is for music)\n"
" -license : Display the program license text (LGPL)\n"; " -license : Display the program license text (LGPL)\n";
// Converts a char into lower case // Converts a char into lower case
static int _toLowerCase(int c) static int _toLowerCase(int c)
{ {
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')
{ {
c += 'a' - 'A'; c += 'a' - 'A';
} }
return c; return c;
} }
// Constructor // Constructor
RunParameters::RunParameters(int nParams, const CHARTYPE* paramStr[]) RunParameters::RunParameters(int nParams, const CHARTYPE* paramStr[])
{ {
int i; int i;
int nFirstParam; int nFirstParam;
if (nParams < 3) if (nParams < 3)
{ {
// Too few parameters // Too few parameters
if (nParams > 1 && paramStr[1][0] == '-' && if (nParams > 1 && paramStr[1][0] == '-' &&
_toLowerCase(paramStr[1][1]) == 'l') _toLowerCase(paramStr[1][1]) == 'l')
{ {
// '-license' switch // '-license' switch
throwLicense(); throwLicense();
} }
string msg = whatText; string msg = whatText;
msg += usage; msg += usage;
throw(msg); throw(msg);
} }
// Get input & output file names // Get input & output file names
inFileName = paramStr[1]; inFileName = paramStr[1];
outFileName = paramStr[2]; outFileName = paramStr[2];
if (outFileName[0] == '-') if (outFileName[0] == '-')
{ {
// outputfile name was omitted but other parameter switches given instead // outputfile name was omitted but other parameter switches given instead
outFileName = STRING_CONST(""); outFileName = STRING_CONST("");
nFirstParam = 2; nFirstParam = 2;
} }
else else
{ {
nFirstParam = 3; nFirstParam = 3;
} }
// parse switch parameters // parse switch parameters
for (i = nFirstParam; i < nParams; i ++) for (i = nFirstParam; i < nParams; i ++)
{ {
parseSwitchParam(paramStr[i]); parseSwitchParam(paramStr[i]);
} }
checkLimits(); checkLimits();
} }
// Checks parameter limits // Checks parameter limits
void RunParameters::checkLimits() void RunParameters::checkLimits()
{ {
if (tempoDelta < -95.0f) if (tempoDelta < -95.0f)
{ {
tempoDelta = -95.0f; tempoDelta = -95.0f;
} }
else if (tempoDelta > 5000.0f) else if (tempoDelta > 5000.0f)
{ {
tempoDelta = 5000.0f; tempoDelta = 5000.0f;
} }
if (pitchDelta < -60.0f) if (pitchDelta < -60.0f)
{ {
pitchDelta = -60.0f; pitchDelta = -60.0f;
} }
else if (pitchDelta > 60.0f) else if (pitchDelta > 60.0f)
{ {
pitchDelta = 60.0f; pitchDelta = 60.0f;
} }
if (rateDelta < -95.0f) if (rateDelta < -95.0f)
{ {
rateDelta = -95.0f; rateDelta = -95.0f;
} }
else if (rateDelta > 5000.0f) else if (rateDelta > 5000.0f)
{ {
rateDelta = 5000.0f; rateDelta = 5000.0f;
} }
} }
// Convert STRING to std::string. Actually needed only if STRING is std::wstring, but conversion penalty is negligible // Convert STRING to std::string. Actually needed only if STRING is std::wstring, but conversion penalty is negligible
std::string convertString(const STRING& str) std::string convertString(const STRING& str)
{ {
std::string res; std::string res;
for (auto c : str) for (auto c : str)
{ {
res += (char)c; res += (char)c;
} }
return res; return res;
} }
// Unknown switch parameter -- throws an exception with an error message // Unknown switch parameter -- throws an exception with an error message
void RunParameters::throwIllegalParamExp(const STRING &str) const void RunParameters::throwIllegalParamExp(const STRING &str) const
{ {
string msg = "ERROR : Illegal parameter \""; string msg = "ERROR : Illegal parameter \"";
msg += convertString(str); msg += convertString(str);
msg += "\".\n\n"; msg += "\".\n\n";
msg += usage; msg += usage;
ST_THROW_RT_ERROR(msg); ST_THROW_RT_ERROR(msg);
} }
void RunParameters::throwLicense() const void RunParameters::throwLicense() const
{ {
ST_THROW_RT_ERROR(licenseText); ST_THROW_RT_ERROR(licenseText);
} }
float RunParameters::parseSwitchValue(const STRING& str) const float RunParameters::parseSwitchValue(const STRING& str) const
{ {
int pos; int pos;
pos = (int)str.find_first_of('='); pos = (int)str.find_first_of('=');
if (pos < 0) if (pos < 0)
{ {
// '=' missing // '=' missing
throwIllegalParamExp(str); throwIllegalParamExp(str);
} }
// Read numerical parameter value after '=' // Read numerical parameter value after '='
return (float)stof(str.substr(pos + 1).c_str()); return (float)stof(str.substr(pos + 1).c_str());
} }
// Interprets a single switch parameter string of format "-switch=xx" // Interprets a single switch parameter string of format "-switch=xx"
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores // Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
// switch values into 'params' structure. // switch values into 'params' structure.
void RunParameters::parseSwitchParam(const STRING& str) void RunParameters::parseSwitchParam(const STRING& str)
{ {
int upS; int upS;
if (str[0] != '-') if (str[0] != '-')
{ {
// leading hyphen missing => not a valid parameter // leading hyphen missing => not a valid parameter
throwIllegalParamExp(str); throwIllegalParamExp(str);
} }
// Take the first character of switch name & change to lower case // Take the first character of switch name & change to lower case
upS = _toLowerCase(str[1]); upS = _toLowerCase(str[1]);
// interpret the switch name & operate accordingly // interpret the switch name & operate accordingly
switch (upS) switch (upS)
{ {
case 't' : case 't' :
// switch '-tempo=xx' // switch '-tempo=xx'
tempoDelta = parseSwitchValue(str); tempoDelta = parseSwitchValue(str);
break; break;
case 'p' : case 'p' :
// switch '-pitch=xx' // switch '-pitch=xx'
pitchDelta = parseSwitchValue(str); pitchDelta = parseSwitchValue(str);
break; break;
case 'r' : case 'r' :
// switch '-rate=xx' // switch '-rate=xx'
rateDelta = parseSwitchValue(str); rateDelta = parseSwitchValue(str);
break; break;
case 'b' : case 'b' :
// switch '-bpm=xx' // switch '-bpm=xx'
detectBPM = true; detectBPM = true;
try try
{ {
goalBPM = parseSwitchValue(str); goalBPM = parseSwitchValue(str);
} }
catch (const runtime_error &) catch (const runtime_error &)
{ {
// illegal or missing bpm value => just calculate bpm // illegal or missing bpm value => just calculate bpm
goalBPM = 0; goalBPM = 0;
} }
break; break;
case 'q' : case 'q' :
// switch '-quick' // switch '-quick'
quick = 1; quick = 1;
break; break;
case 'n' : case 'n' :
// switch '-naa' // switch '-naa'
noAntiAlias = 1; noAntiAlias = 1;
break; break;
case 'l' : case 'l' :
// switch '-license' // switch '-license'
throwLicense(); throwLicense();
break; break;
case 's' : case 's' :
// switch '-speech' // switch '-speech'
speech = true; speech = true;
break; break;
default: default:
// unknown switch // unknown switch
throwIllegalParamExp(str); throwIllegalParamExp(str);
} }
} }
} }

View File

@ -1,70 +1,70 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A class for parsing the 'soundstretch' application command line parameters /// A class for parsing the 'soundstretch' application command line parameters
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef RUNPARAMETERS_H #ifndef RUNPARAMETERS_H
#define RUNPARAMETERS_H #define RUNPARAMETERS_H
#include <string> #include <string>
#include "STTypes.h" #include "STTypes.h"
#include "SS_CharTypes.h" #include "SS_CharTypes.h"
#include "WavFile.h" #include "WavFile.h"
namespace soundstretch namespace soundstretch
{ {
/// Parses command line parameters into program parameters /// Parses command line parameters into program parameters
class RunParameters class RunParameters
{ {
private: private:
void throwIllegalParamExp(const STRING& str) const; void throwIllegalParamExp(const STRING& str) const;
void throwLicense() const; void throwLicense() const;
void parseSwitchParam(const STRING& str); void parseSwitchParam(const STRING& str);
void checkLimits(); void checkLimits();
float parseSwitchValue(const STRING& tr) const; float parseSwitchValue(const STRING& tr) const;
public: public:
STRING inFileName; STRING inFileName;
STRING outFileName; STRING outFileName;
float tempoDelta{ 0 }; float tempoDelta{ 0 };
float pitchDelta{ 0 }; float pitchDelta{ 0 };
float rateDelta{ 0 }; float rateDelta{ 0 };
int quick{ 0 }; int quick{ 0 };
int noAntiAlias{ 0 }; int noAntiAlias{ 0 };
float goalBPM{ 0 }; float goalBPM{ 0 };
bool detectBPM{ false }; bool detectBPM{ false };
bool speech{ false }; bool speech{ false };
RunParameters(int nParams, const CHARTYPE* paramStr[]); RunParameters(int nParams, const CHARTYPE* paramStr[]);
}; };
} }
#endif #endif

View File

@ -1,52 +1,52 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Char type for SoundStretch /// Char type for SoundStretch
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef SS_CHARTYPE_H #ifndef SS_CHARTYPE_H
#define SS_CHARTYPE_H #define SS_CHARTYPE_H
#include <string> #include <string>
namespace soundstretch namespace soundstretch
{ {
#if _WIN32 #if _WIN32
// wide-char types for supporting non-latin file paths in Windows // wide-char types for supporting non-latin file paths in Windows
using CHARTYPE = wchar_t; using CHARTYPE = wchar_t;
using STRING = std::wstring; using STRING = std::wstring;
#define STRING_CONST(x) (L"" x) #define STRING_CONST(x) (L"" x)
#else #else
// gnu platform can natively support UTF-8 paths using "char*" set // gnu platform can natively support UTF-8 paths using "char*" set
using CHARTYPE = char; using CHARTYPE = char;
using STRING = std::string; using STRING = std::string;
#define STRING_CONST(x) (x) #define STRING_CONST(x) (x)
#endif #endif
} }
#endif //SS_CHARTYPE_H #endif //SS_CHARTYPE_H

File diff suppressed because it is too large Load Diff

View File

@ -1,281 +1,281 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Classes for easy reading & writing of WAV sound files. /// Classes for easy reading & writing of WAV sound files.
/// ///
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly /// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
/// parse the WAV files with such processors. /// parse the WAV files with such processors.
/// ///
/// Admittingly, more complete WAV reader routines may exist in public domain, but /// Admittingly, more complete WAV reader routines may exist in public domain, but
/// the reason for 'yet another' one is that those generic WAV reader libraries are /// the reason for 'yet another' one is that those generic WAV reader libraries are
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. /// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
/// something that's not already larger than rest of the SoundTouch/SoundStretch program... /// something that's not already larger than rest of the SoundTouch/SoundStretch program...
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef WAVFILE_H #ifndef WAVFILE_H
#define WAVFILE_H #define WAVFILE_H
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include "SS_CharTypes.h" #include "SS_CharTypes.h"
namespace soundstretch namespace soundstretch
{ {
#ifndef uint #ifndef uint
typedef unsigned int uint; typedef unsigned int uint;
#endif #endif
/// WAV audio file 'riff' section header /// WAV audio file 'riff' section header
typedef struct typedef struct
{ {
char riff_char[4]; char riff_char[4];
uint package_len; uint package_len;
char wave[4]; char wave[4];
} WavRiff; } WavRiff;
/// WAV audio file 'format' section header /// WAV audio file 'format' section header
typedef struct typedef struct
{ {
char fmt[4]; char fmt[4];
unsigned int format_len; unsigned int format_len;
unsigned short fixed; unsigned short fixed;
unsigned short channel_number; unsigned short channel_number;
unsigned int sample_rate; unsigned int sample_rate;
unsigned int byte_rate; unsigned int byte_rate;
unsigned short byte_per_sample; unsigned short byte_per_sample;
unsigned short bits_per_sample; unsigned short bits_per_sample;
} WavFormat; } WavFormat;
/// WAV audio file 'fact' section header /// WAV audio file 'fact' section header
typedef struct typedef struct
{ {
char fact_field[4]; char fact_field[4];
uint fact_len; uint fact_len;
uint fact_sample_len; uint fact_sample_len;
} WavFact; } WavFact;
/// WAV audio file 'data' section header /// WAV audio file 'data' section header
typedef struct typedef struct
{ {
char data_field[4]; char data_field[4];
uint data_len; uint data_len;
} WavData; } WavData;
/// WAV audio file header /// WAV audio file header
typedef struct typedef struct
{ {
WavRiff riff; WavRiff riff;
WavFormat format; WavFormat format;
WavFact fact; WavFact fact;
WavData data; WavData data;
} WavHeader; } WavHeader;
/// Base class for processing WAV audio files. /// Base class for processing WAV audio files.
class WavFileBase class WavFileBase
{ {
private: private:
/// Conversion working buffer; /// Conversion working buffer;
char *convBuff; char *convBuff;
int convBuffSize; int convBuffSize;
protected: protected:
WavFileBase(); WavFileBase();
virtual ~WavFileBase(); virtual ~WavFileBase();
/// Get pointer to conversion buffer of at min. given size /// Get pointer to conversion buffer of at min. given size
void *getConvBuffer(int sizeByte); void *getConvBuffer(int sizeByte);
}; };
/// Class for reading WAV audio files. /// Class for reading WAV audio files.
class WavInFile : protected WavFileBase class WavInFile : protected WavFileBase
{ {
private: private:
/// File pointer. /// File pointer.
FILE *fptr; FILE *fptr;
/// Counter of how many bytes of sample data have been read from the file. /// Counter of how many bytes of sample data have been read from the file.
long dataRead; long dataRead;
/// WAV header information /// WAV header information
WavHeader header; WavHeader header;
/// Init the WAV file stream /// Init the WAV file stream
void init(); void init();
/// Read WAV file headers. /// Read WAV file headers.
/// \return zero if all ok, nonzero if file format is invalid. /// \return zero if all ok, nonzero if file format is invalid.
int readWavHeaders(); int readWavHeaders();
/// Checks WAV file header tags. /// Checks WAV file header tags.
/// \return zero if all ok, nonzero if file format is invalid. /// \return zero if all ok, nonzero if file format is invalid.
int checkCharTags() const; int checkCharTags() const;
/// Reads a single WAV file header block. /// Reads a single WAV file header block.
/// \return zero if all ok, nonzero if file format is invalid. /// \return zero if all ok, nonzero if file format is invalid.
int readHeaderBlock(); int readHeaderBlock();
/// Reads WAV file 'riff' block /// Reads WAV file 'riff' block
int readRIFFBlock(); int readRIFFBlock();
public: public:
/// Constructor: Opens the given WAV file. If the file can't be opened, /// Constructor: Opens the given WAV file. If the file can't be opened,
/// throws 'runtime_error' exception. /// throws 'runtime_error' exception.
WavInFile(const STRING& filename); WavInFile(const STRING& filename);
WavInFile(FILE *file); WavInFile(FILE *file);
/// Destructor: Closes the file. /// Destructor: Closes the file.
~WavInFile(); ~WavInFile();
/// Rewind to beginning of the file /// Rewind to beginning of the file
void rewind(); void rewind();
/// Get sample rate. /// Get sample rate.
uint getSampleRate() const; uint getSampleRate() const;
/// Get number of bits per sample, i.e. 8 or 16. /// Get number of bits per sample, i.e. 8 or 16.
uint getNumBits() const; uint getNumBits() const;
/// Get sample data size in bytes. Ahem, this should return same information as /// Get sample data size in bytes. Ahem, this should return same information as
/// 'getBytesPerSample'... /// 'getBytesPerSample'...
uint getDataSizeInBytes() const; uint getDataSizeInBytes() const;
/// Get total number of samples in file. /// Get total number of samples in file.
uint getNumSamples() const; uint getNumSamples() const;
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
uint getBytesPerSample() const; uint getBytesPerSample() const;
/// Get number of audio channels in the file (1=mono, 2=stereo) /// Get number of audio channels in the file (1=mono, 2=stereo)
uint getNumChannels() const; uint getNumChannels() const;
/// Get the audio file length in milliseconds /// Get the audio file length in milliseconds
uint getLengthMS() const; uint getLengthMS() const;
/// Returns how many milliseconds of audio have so far been read from the file /// Returns how many milliseconds of audio have so far been read from the file
/// ///
/// \return elapsed duration in milliseconds /// \return elapsed duration in milliseconds
uint getElapsedMS() const; uint getElapsedMS() const;
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples. /// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
/// Reads given number of elements from the file or if end-of-file reached, as many /// Reads given number of elements from the file or if end-of-file reached, as many
/// elements as are left in the file. /// elements as are left in the file.
/// ///
/// \return Number of 8-bit integers read from the file. /// \return Number of 8-bit integers read from the file.
int read(unsigned char *buffer, int maxElems); int read(unsigned char *buffer, int maxElems);
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
/// of elements from the file or if end-of-file reached, as many elements as are /// of elements from the file or if end-of-file reached, as many elements as are
/// left in the file. /// left in the file.
/// ///
/// \return Number of 16-bit integers read from the file. /// \return Number of 16-bit integers read from the file.
int read(short *buffer, ///< Pointer to buffer where to read data. int read(short *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements). int maxElems ///< Size of 'buffer' array (number of array elements).
); );
/// Reads audio samples from the WAV file to floating point format, converting /// Reads audio samples from the WAV file to floating point format, converting
/// sample values to range [-1,1[. Reads given number of elements from the file /// sample values to range [-1,1[. Reads given number of elements from the file
/// or if end-of-file reached, as many elements as are left in the file. /// or if end-of-file reached, as many elements as are left in the file.
/// Notice that reading in float format supports 8/16/24/32bit sample formats. /// Notice that reading in float format supports 8/16/24/32bit sample formats.
/// ///
/// \return Number of elements read from the file. /// \return Number of elements read from the file.
int read(float *buffer, ///< Pointer to buffer where to read data. int read(float *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements). int maxElems ///< Size of 'buffer' array (number of array elements).
); );
/// Check end-of-file. /// Check end-of-file.
/// ///
/// \return Nonzero if end-of-file reached. /// \return Nonzero if end-of-file reached.
int eof() const; int eof() const;
}; };
/// Class for writing WAV audio files. /// Class for writing WAV audio files.
class WavOutFile : protected WavFileBase class WavOutFile : protected WavFileBase
{ {
private: private:
/// Pointer to the WAV file /// Pointer to the WAV file
FILE *fptr; FILE *fptr;
/// WAV file header data. /// WAV file header data.
WavHeader header; WavHeader header;
/// Counter of how many bytes have been written to the file so far. /// Counter of how many bytes have been written to the file so far.
int bytesWritten; int bytesWritten;
/// Fills in WAV file header information. /// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels); void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Finishes the WAV file header by supplementing information of amount of /// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc /// data written to file etc
void finishHeader(); void finishHeader();
/// Writes the WAV file header. /// Writes the WAV file header.
void writeHeader(); void writeHeader();
public: public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails. /// if file creation fails.
WavOutFile(const STRING& fileName, ///< Filename WavOutFile(const STRING& fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc) int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits) int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo) int channels ///< Number of channels (1=mono, 2=stereo)
); );
WavOutFile(FILE *file, int sampleRate, int bits, int channels); WavOutFile(FILE *file, int sampleRate, int bits, int channels);
/// Destructor: Finalizes & closes the WAV file. /// Destructor: Finalizes & closes the WAV file.
~WavOutFile(); ~WavOutFile();
/// Write data to WAV file. This function works only with 8bit samples. /// Write data to WAV file. This function works only with 8bit samples.
/// Throws a 'runtime_error' exception if writing to file fails. /// Throws a 'runtime_error' exception if writing to file fails.
void write(const unsigned char *buffer, ///< Pointer to sample data buffer. void write(const unsigned char *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file. int numElems ///< How many array items are to be written to file.
); );
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to /// Write data to WAV file. Throws a 'runtime_error' exception if writing to
/// file fails. /// file fails.
void write(const short *buffer, ///< Pointer to sample data buffer. void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file. int numElems ///< How many array items are to be written to file.
); );
/// Write data to WAV file in floating point format, saturating sample values to range /// Write data to WAV file in floating point format, saturating sample values to range
/// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails. /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.
void write(const float *buffer, ///< Pointer to sample data buffer. void write(const float *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file. int numElems ///< How many array items are to be written to file.
); );
}; };
} }
#endif #endif

View File

@ -1,311 +1,311 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// SoundStretch main routine. /// SoundStretch main routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <cstdio> #include <cstdio>
#include <ctime> #include <ctime>
#include "RunParameters.h" #include "RunParameters.h"
#include "WavFile.h" #include "WavFile.h"
#include "SoundTouch.h" #include "SoundTouch.h"
#include "BPMDetect.h" #include "BPMDetect.h"
using namespace soundtouch; using namespace soundtouch;
using namespace std; using namespace std;
namespace soundstretch namespace soundstretch
{ {
// Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...) // Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...)
#define BUFF_SIZE 6720 #define BUFF_SIZE 6720
#if _WIN32 #if _WIN32
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode // Macro for Win32 standard input/output stream support: Sets a file stream into binary mode
#define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY)) #define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))
#else #else
// Not needed for GNU environment... // Not needed for GNU environment...
#define SET_STREAM_TO_BIN_MODE(f) {} #define SET_STREAM_TO_BIN_MODE(f) {}
#endif #endif
static const char _helloText[] = static const char _helloText[] =
"\n" "\n"
" SoundStretch v%s - Copyright (c) Olli Parviainen\n" " SoundStretch v%s - Copyright (c) Olli Parviainen\n"
"=========================================================\n" "=========================================================\n"
"author e-mail: <oparviai" "author e-mail: <oparviai"
"@" "@"
"iki.fi> - WWW: http://www.surina.net/soundtouch\n" "iki.fi> - WWW: http://www.surina.net/soundtouch\n"
"\n" "\n"
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n" "This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
"more information.\n" "more information.\n"
"\n"; "\n";
static void openFiles(unique_ptr<WavInFile>& inFile, unique_ptr<WavOutFile>& outFile, const RunParameters& params) static void openFiles(unique_ptr<WavInFile>& inFile, unique_ptr<WavOutFile>& outFile, const RunParameters& params)
{ {
if (params.inFileName == STRING_CONST("stdin")) if (params.inFileName == STRING_CONST("stdin"))
{ {
// used 'stdin' as input file // used 'stdin' as input file
SET_STREAM_TO_BIN_MODE(stdin); SET_STREAM_TO_BIN_MODE(stdin);
inFile = make_unique<WavInFile>(stdin); inFile = make_unique<WavInFile>(stdin);
} }
else else
{ {
// open input file... // open input file...
inFile = make_unique<WavInFile>(params.inFileName.c_str()); inFile = make_unique<WavInFile>(params.inFileName.c_str());
} }
// ... open output file with same sound parameters // ... open output file with same sound parameters
const int bits = (int)inFile->getNumBits(); const int bits = (int)inFile->getNumBits();
const int samplerate = (int)inFile->getSampleRate(); const int samplerate = (int)inFile->getSampleRate();
const int channels = (int)inFile->getNumChannels(); const int channels = (int)inFile->getNumChannels();
if (!params.outFileName.empty()) if (!params.outFileName.empty())
{ {
if (params.outFileName == STRING_CONST("stdout")) if (params.outFileName == STRING_CONST("stdout"))
{ {
SET_STREAM_TO_BIN_MODE(stdout); SET_STREAM_TO_BIN_MODE(stdout);
outFile = make_unique<WavOutFile>(stdout, samplerate, bits, channels); outFile = make_unique<WavOutFile>(stdout, samplerate, bits, channels);
} }
else else
{ {
outFile = make_unique<WavOutFile>(params.outFileName.c_str(), samplerate, bits, channels); outFile = make_unique<WavOutFile>(params.outFileName.c_str(), samplerate, bits, channels);
} }
} }
} }
// Sets the 'SoundTouch' object up according to input file sound format & // Sets the 'SoundTouch' object up according to input file sound format &
// command line parameters // command line parameters
static void setup(SoundTouch& soundTouch, const WavInFile& inFile, const RunParameters& params) static void setup(SoundTouch& soundTouch, const WavInFile& inFile, const RunParameters& params)
{ {
const int sampleRate = (int)inFile.getSampleRate(); const int sampleRate = (int)inFile.getSampleRate();
const int channels = (int)inFile.getNumChannels(); const int channels = (int)inFile.getNumChannels();
soundTouch.setSampleRate(sampleRate); soundTouch.setSampleRate(sampleRate);
soundTouch.setChannels(channels); soundTouch.setChannels(channels);
soundTouch.setTempoChange(params.tempoDelta); soundTouch.setTempoChange(params.tempoDelta);
soundTouch.setPitchSemiTones(params.pitchDelta); soundTouch.setPitchSemiTones(params.pitchDelta);
soundTouch.setRateChange(params.rateDelta); soundTouch.setRateChange(params.rateDelta);
soundTouch.setSetting(SETTING_USE_QUICKSEEK, params.quick); soundTouch.setSetting(SETTING_USE_QUICKSEEK, params.quick);
soundTouch.setSetting(SETTING_USE_AA_FILTER, !(params.noAntiAlias)); soundTouch.setSetting(SETTING_USE_AA_FILTER, !(params.noAntiAlias));
if (params.speech) if (params.speech)
{ {
// use settings for speech processing // use settings for speech processing
soundTouch.setSetting(SETTING_SEQUENCE_MS, 40); soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15); soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
soundTouch.setSetting(SETTING_OVERLAP_MS, 8); soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
fprintf(stderr, "Tune processing parameters for speech processing.\n"); fprintf(stderr, "Tune processing parameters for speech processing.\n");
} }
// print processing information // print processing information
if (!params.outFileName.empty()) if (!params.outFileName.empty())
{ {
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n"); fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
#else #else
#ifndef SOUNDTOUCH_FLOAT_SAMPLES #ifndef SOUNDTOUCH_FLOAT_SAMPLES
#error "Sampletype not defined" #error "Sampletype not defined"
#endif #endif
fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n"); fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
#endif #endif
// print processing information only if outFileName given i.e. some processing will happen // print processing information only if outFileName given i.e. some processing will happen
fprintf(stderr, "Processing the file with the following changes:\n"); fprintf(stderr, "Processing the file with the following changes:\n");
fprintf(stderr, " tempo change = %+g %%\n", params.tempoDelta); fprintf(stderr, " tempo change = %+g %%\n", params.tempoDelta);
fprintf(stderr, " pitch change = %+g semitones\n", params.pitchDelta); fprintf(stderr, " pitch change = %+g semitones\n", params.pitchDelta);
fprintf(stderr, " rate change = %+g %%\n\n", params.rateDelta); fprintf(stderr, " rate change = %+g %%\n\n", params.rateDelta);
fprintf(stderr, "Working..."); fprintf(stderr, "Working...");
} }
else else
{ {
// outFileName not given // outFileName not given
fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n"); fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");
} }
fflush(stderr); fflush(stderr);
} }
// Processes the sound // Processes the sound
static void process(SoundTouch& soundTouch, WavInFile& inFile, WavOutFile& outFile) static void process(SoundTouch& soundTouch, WavInFile& inFile, WavOutFile& outFile)
{ {
SAMPLETYPE sampleBuffer[BUFF_SIZE]; SAMPLETYPE sampleBuffer[BUFF_SIZE];
int nSamples; int nSamples;
const int nChannels = (int)inFile.getNumChannels(); const int nChannels = (int)inFile.getNumChannels();
assert(nChannels > 0); assert(nChannels > 0);
const int buffSizeSamples = BUFF_SIZE / nChannels; const int buffSizeSamples = BUFF_SIZE / nChannels;
// Process samples read from the input file // Process samples read from the input file
while (inFile.eof() == 0) while (inFile.eof() == 0)
{ {
// Read a chunk of samples from the input file // Read a chunk of samples from the input file
const int num = inFile.read(sampleBuffer, BUFF_SIZE); const int num = inFile.read(sampleBuffer, BUFF_SIZE);
int nSamples = num / (int)inFile.getNumChannels(); int nSamples = num / (int)inFile.getNumChannels();
// Feed the samples into SoundTouch processor // Feed the samples into SoundTouch processor
soundTouch.putSamples(sampleBuffer, nSamples); soundTouch.putSamples(sampleBuffer, nSamples);
// Read ready samples from SoundTouch processor & write them output file. // Read ready samples from SoundTouch processor & write them output file.
// NOTES: // NOTES:
// - 'receiveSamples' doesn't necessarily return any samples at all // - 'receiveSamples' doesn't necessarily return any samples at all
// during some rounds! // during some rounds!
// - On the other hand, during some round 'receiveSamples' may have more // - On the other hand, during some round 'receiveSamples' may have more
// ready samples than would fit into 'sampleBuffer', and for this reason // ready samples than would fit into 'sampleBuffer', and for this reason
// the 'receiveSamples' call is iterated for as many times as it // the 'receiveSamples' call is iterated for as many times as it
// outputs samples. // outputs samples.
do do
{ {
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples); nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels); outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0); } while (nSamples != 0);
} }
// Now the input file is processed, yet 'flush' few last samples that are // Now the input file is processed, yet 'flush' few last samples that are
// hiding in the SoundTouch's internal processing pipeline. // hiding in the SoundTouch's internal processing pipeline.
soundTouch.flush(); soundTouch.flush();
do do
{ {
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples); nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels); outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0); } while (nSamples != 0);
} }
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary // Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
static void detectBPM(WavInFile& inFile, RunParameters& params) static void detectBPM(WavInFile& inFile, RunParameters& params)
{ {
BPMDetect bpm(inFile.getNumChannels(), inFile.getSampleRate()); BPMDetect bpm(inFile.getNumChannels(), inFile.getSampleRate());
SAMPLETYPE sampleBuffer[BUFF_SIZE]; SAMPLETYPE sampleBuffer[BUFF_SIZE];
// detect bpm rate // detect bpm rate
fprintf(stderr, "Detecting BPM rate..."); fprintf(stderr, "Detecting BPM rate...");
fflush(stderr); fflush(stderr);
const int nChannels = (int)inFile.getNumChannels(); const int nChannels = (int)inFile.getNumChannels();
int readSize = BUFF_SIZE - BUFF_SIZE % nChannels; // round read size down to multiple of num.channels int readSize = BUFF_SIZE - BUFF_SIZE % nChannels; // round read size down to multiple of num.channels
// Process the 'inFile' in small blocks, repeat until whole file has // Process the 'inFile' in small blocks, repeat until whole file has
// been processed // been processed
while (inFile.eof() == 0) while (inFile.eof() == 0)
{ {
// Read sample data from input file // Read sample data from input file
const int num = inFile.read(sampleBuffer, readSize); const int num = inFile.read(sampleBuffer, readSize);
// Enter the new samples to the bpm analyzer class // Enter the new samples to the bpm analyzer class
const int samples = num / nChannels; const int samples = num / nChannels;
bpm.inputSamples(sampleBuffer, samples); bpm.inputSamples(sampleBuffer, samples);
} }
// Now the whole song data has been analyzed. Read the resulting bpm. // Now the whole song data has been analyzed. Read the resulting bpm.
const float bpmValue = bpm.getBpm(); const float bpmValue = bpm.getBpm();
fprintf(stderr, "Done!\n"); fprintf(stderr, "Done!\n");
// rewind the file after bpm detection // rewind the file after bpm detection
inFile.rewind(); inFile.rewind();
if (bpmValue > 0) if (bpmValue > 0)
{ {
fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue); fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue);
} }
else else
{ {
fprintf(stderr, "Couldn't detect BPM rate.\n\n"); fprintf(stderr, "Couldn't detect BPM rate.\n\n");
return; return;
} }
if (params.goalBPM > 0) if (params.goalBPM > 0)
{ {
// adjust tempo to given bpm // adjust tempo to given bpm
params.tempoDelta = (params.goalBPM / bpmValue - 1.0f) * 100.0f; params.tempoDelta = (params.goalBPM / bpmValue - 1.0f) * 100.0f;
fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params.goalBPM); fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params.goalBPM);
} }
} }
void ss_main(RunParameters& params) void ss_main(RunParameters& params)
{ {
unique_ptr<WavInFile> inFile; unique_ptr<WavInFile> inFile;
unique_ptr<WavOutFile> outFile; unique_ptr<WavOutFile> outFile;
SoundTouch soundTouch; SoundTouch soundTouch;
fprintf(stderr, _helloText, soundTouch.getVersionString()); fprintf(stderr, _helloText, soundTouch.getVersionString());
// Open input & output files // Open input & output files
openFiles(inFile, outFile, params); openFiles(inFile, outFile, params);
if (params.detectBPM == true) if (params.detectBPM == true)
{ {
// detect sound BPM (and adjust processing parameters // detect sound BPM (and adjust processing parameters
// accordingly if necessary) // accordingly if necessary)
detectBPM(*inFile, params); detectBPM(*inFile, params);
} }
// Setup the 'SoundTouch' object for processing the sound // Setup the 'SoundTouch' object for processing the sound
setup(soundTouch, *inFile, params); setup(soundTouch, *inFile, params);
// clock_t cs = clock(); // for benchmarking processing duration // clock_t cs = clock(); // for benchmarking processing duration
// Process the sound // Process the sound
if (inFile && outFile) if (inFile && outFile)
{ {
process(soundTouch, *inFile, *outFile); process(soundTouch, *inFile, *outFile);
} }
// clock_t ce = clock(); // for benchmarking processing duration // clock_t ce = clock(); // for benchmarking processing duration
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC); // printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);
fprintf(stderr, "Done!\n"); fprintf(stderr, "Done!\n");
} }
} }
#if _WIN32 #if _WIN32
int wmain(int argc, const wchar_t* args[]) int wmain(int argc, const wchar_t* args[])
#else #else
int main(int argc, const char* args[]) int main(int argc, const char* args[])
#endif #endif
{ {
try try
{ {
soundstretch::RunParameters params(argc, args); soundstretch::RunParameters params(argc, args);
soundstretch::ss_main(params); soundstretch::ss_main(params);
} }
catch (const runtime_error& e) catch (const runtime_error& e)
{ {
fprintf(stderr, "%s\n", e.what()); fprintf(stderr, "%s\n", e.what());
return -1; return -1;
} }
return 0; return 0;
} }

View File

@ -1,222 +1,222 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and /// FIR low-pass (anti-alias) filter with filter coefficient design routine and
/// MMX optimization. /// MMX optimization.
/// ///
/// Anti-alias filter is used to prevent folding of high frequencies when /// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation. /// transposing the sample rate with interpolation.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <memory.h> #include <memory.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include "AAFilter.h" #include "AAFilter.h"
#include "FIRFilter.h" #include "FIRFilter.h"
using namespace soundtouch; using namespace soundtouch;
#define PI 3.14159265358979323846 #define PI 3.14159265358979323846
#define TWOPI (2 * PI) #define TWOPI (2 * PI)
// define this to save AA filter coefficients to a file // define this to save AA filter coefficients to a file
// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 // #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1
#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS #ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS
#include <stdio.h> #include <stdio.h>
static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
{ {
FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
if (fptr == nullptr) return; if (fptr == nullptr) return;
for (int i = 0; i < len; i ++) for (int i = 0; i < len; i ++)
{ {
double temp = coeffs[i]; double temp = coeffs[i];
fprintf(fptr, "%lf\n", temp); fprintf(fptr, "%lf\n", temp);
} }
fclose(fptr); fclose(fptr);
} }
#else #else
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y) #define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
#endif #endif
/***************************************************************************** /*****************************************************************************
* *
* Implementation of the class 'AAFilter' * Implementation of the class 'AAFilter'
* *
*****************************************************************************/ *****************************************************************************/
AAFilter::AAFilter(uint len) AAFilter::AAFilter(uint len)
{ {
pFIR = FIRFilter::newInstance(); pFIR = FIRFilter::newInstance();
cutoffFreq = 0.5; cutoffFreq = 0.5;
setLength(len); setLength(len);
} }
AAFilter::~AAFilter() AAFilter::~AAFilter()
{ {
delete pFIR; delete pFIR;
} }
// Sets new anti-alias filter cut-off edge frequency, scaled to // Sets new anti-alias filter cut-off edge frequency, scaled to
// sampling frequency (nyquist frequency = 0.5). // sampling frequency (nyquist frequency = 0.5).
// The filter will cut frequencies higher than the given frequency. // The filter will cut frequencies higher than the given frequency.
void AAFilter::setCutoffFreq(double newCutoffFreq) void AAFilter::setCutoffFreq(double newCutoffFreq)
{ {
cutoffFreq = newCutoffFreq; cutoffFreq = newCutoffFreq;
calculateCoeffs(); calculateCoeffs();
} }
// Sets number of FIR filter taps // Sets number of FIR filter taps
void AAFilter::setLength(uint newLength) void AAFilter::setLength(uint newLength)
{ {
length = newLength; length = newLength;
calculateCoeffs(); calculateCoeffs();
} }
// Calculates coefficients for a low-pass FIR filter using Hamming window // Calculates coefficients for a low-pass FIR filter using Hamming window
void AAFilter::calculateCoeffs() void AAFilter::calculateCoeffs()
{ {
uint i; uint i;
double cntTemp, temp, tempCoeff,h, w; double cntTemp, temp, tempCoeff,h, w;
double wc; double wc;
double scaleCoeff, sum; double scaleCoeff, sum;
double *work; double *work;
SAMPLETYPE *coeffs; SAMPLETYPE *coeffs;
assert(length >= 2); assert(length >= 2);
assert(length % 4 == 0); assert(length % 4 == 0);
assert(cutoffFreq >= 0); assert(cutoffFreq >= 0);
assert(cutoffFreq <= 0.5); assert(cutoffFreq <= 0.5);
work = new double[length]; work = new double[length];
coeffs = new SAMPLETYPE[length]; coeffs = new SAMPLETYPE[length];
wc = 2.0 * PI * cutoffFreq; wc = 2.0 * PI * cutoffFreq;
tempCoeff = TWOPI / (double)length; tempCoeff = TWOPI / (double)length;
sum = 0; sum = 0;
for (i = 0; i < length; i ++) for (i = 0; i < length; i ++)
{ {
cntTemp = (double)i - (double)(length / 2); cntTemp = (double)i - (double)(length / 2);
temp = cntTemp * wc; temp = cntTemp * wc;
if (temp != 0) if (temp != 0)
{ {
h = sin(temp) / temp; // sinc function h = sin(temp) / temp; // sinc function
} }
else else
{ {
h = 1.0; h = 1.0;
} }
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
temp = w * h; temp = w * h;
work[i] = temp; work[i] = temp;
// calc net sum of coefficients // calc net sum of coefficients
sum += temp; sum += temp;
} }
// ensure the sum of coefficients is larger than zero // ensure the sum of coefficients is larger than zero
assert(sum > 0); assert(sum > 0);
// ensure we've really designed a lowpass filter... // ensure we've really designed a lowpass filter...
assert(work[length/2] > 0); assert(work[length/2] > 0);
assert(work[length/2 + 1] > -1e-6); assert(work[length/2 + 1] > -1e-6);
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 // Calculate a scaling coefficient in such a way that the result can be
// divided by 16384 // divided by 16384
scaleCoeff = 16384.0f / sum; scaleCoeff = 16384.0f / sum;
for (i = 0; i < length; i ++) for (i = 0; i < length; i ++)
{ {
temp = work[i] * scaleCoeff; temp = work[i] * scaleCoeff;
// scale & round to nearest integer // scale & round to nearest integer
temp += (temp >= 0) ? 0.5 : -0.5; temp += (temp >= 0) ? 0.5 : -0.5;
// ensure no overfloods // ensure no overfloods
assert(temp >= -32768 && temp <= 32767); assert(temp >= -32768 && temp <= 32767);
coeffs[i] = (SAMPLETYPE)temp; coeffs[i] = (SAMPLETYPE)temp;
} }
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
pFIR->setCoefficients(coeffs, length, 14); pFIR->setCoefficients(coeffs, length, 14);
_DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
delete[] work; delete[] work;
delete[] coeffs; delete[] coeffs;
} }
// Applies the filter to the given sequence of samples. // Applies the filter to the given sequence of samples.
// Note : The amount of outputted samples is by value of 'filter length' // Note : The amount of outputted samples is by value of 'filter length'
// smaller than the amount of input samples. // smaller than the amount of input samples.
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{ {
return pFIR->evaluate(dest, src, numSamples, numChannels); return pFIR->evaluate(dest, src, numSamples, numChannels);
} }
/// Applies the filter to the given src & dest pipes, so that processed amount of /// 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 /// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length' /// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
{ {
SAMPLETYPE *pdest; SAMPLETYPE *pdest;
const SAMPLETYPE *psrc; const SAMPLETYPE *psrc;
uint numSrcSamples; uint numSrcSamples;
uint result; uint result;
int numChannels = src.getChannels(); int numChannels = src.getChannels();
assert(numChannels == dest.getChannels()); assert(numChannels == dest.getChannels());
numSrcSamples = src.numSamples(); numSrcSamples = src.numSamples();
psrc = src.ptrBegin(); psrc = src.ptrBegin();
pdest = dest.ptrEnd(numSrcSamples); pdest = dest.ptrEnd(numSrcSamples);
result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
src.receiveSamples(result); src.receiveSamples(result);
dest.putSamples(result); dest.putSamples(result);
return result; return result;
} }
uint AAFilter::getLength() const uint AAFilter::getLength() const
{ {
return pFIR->getLength(); return pFIR->getLength();
} }

View File

@ -1,93 +1,93 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method /// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks. /// with several performance-increasing tweaks.
/// ///
/// Anti-alias filter is used to prevent folding of high frequencies when /// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation. /// transposing the sample rate with interpolation.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef AAFilter_H #ifndef AAFilter_H
#define AAFilter_H #define AAFilter_H
#include "STTypes.h" #include "STTypes.h"
#include "FIFOSampleBuffer.h" #include "FIFOSampleBuffer.h"
namespace soundtouch namespace soundtouch
{ {
class AAFilter class AAFilter
{ {
protected: protected:
class FIRFilter *pFIR; class FIRFilter *pFIR;
/// Low-pass filter cut-off frequency, negative = invalid /// Low-pass filter cut-off frequency, negative = invalid
double cutoffFreq; double cutoffFreq;
/// num of filter taps /// num of filter taps
uint length; uint length;
/// Calculate the FIR coefficients realizing the given cutoff-frequency /// Calculate the FIR coefficients realizing the given cutoff-frequency
void calculateCoeffs(); void calculateCoeffs();
public: public:
AAFilter(uint length); AAFilter(uint length);
~AAFilter(); ~AAFilter();
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
/// frequency (nyquist frequency = 0.5). The filter will cut off the /// frequency (nyquist frequency = 0.5). The filter will cut off the
/// frequencies than that. /// frequencies than that.
void setCutoffFreq(double newCutoffFreq); void setCutoffFreq(double newCutoffFreq);
/// Sets number of FIR filter taps, i.e. ~filter complexity /// Sets number of FIR filter taps, i.e. ~filter complexity
void setLength(uint newLength); void setLength(uint newLength);
uint getLength() const; uint getLength() const;
/// Applies the filter to the given sequence of samples. /// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter length' /// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
uint evaluate(SAMPLETYPE *dest, uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples, uint numSamples,
uint numChannels) const; uint numChannels) const;
/// Applies the filter to the given src & dest pipes, so that processed amount of /// 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 /// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length' /// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
uint evaluate(FIFOSampleBuffer &dest, uint evaluate(FIFOSampleBuffer &dest,
FIFOSampleBuffer &src) const; FIFOSampleBuffer &src) const;
}; };
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,275 +1,275 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A buffer class for temporarily storaging sound samples, operates as a /// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe. /// first-in-first-out pipe.
/// ///
/// Samples are added to the end of the sample buffer with the 'putSamples' /// 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 /// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the /// the 'receiveSamples' function. The class automatically removes the
/// outputted samples from the buffer, as well as grows the buffer size /// outputted samples from the buffer, as well as grows the buffer size
/// whenever necessary. /// whenever necessary.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h> #include <stdlib.h>
#include <memory.h> #include <memory.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "FIFOSampleBuffer.h" #include "FIFOSampleBuffer.h"
using namespace soundtouch; using namespace soundtouch;
// Constructor // Constructor
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
{ {
assert(numChannels > 0); assert(numChannels > 0);
sizeInBytes = 0; // reasonable initial value sizeInBytes = 0; // reasonable initial value
buffer = nullptr; buffer = nullptr;
bufferUnaligned = nullptr; bufferUnaligned = nullptr;
samplesInBuffer = 0; samplesInBuffer = 0;
bufferPos = 0; bufferPos = 0;
channels = (uint)numChannels; channels = (uint)numChannels;
ensureCapacity(32); // allocate initial capacity ensureCapacity(32); // allocate initial capacity
} }
// destructor // destructor
FIFOSampleBuffer::~FIFOSampleBuffer() FIFOSampleBuffer::~FIFOSampleBuffer()
{ {
delete[] bufferUnaligned; delete[] bufferUnaligned;
bufferUnaligned = nullptr; bufferUnaligned = nullptr;
buffer = nullptr; buffer = nullptr;
} }
// Sets number of channels, 1 = mono, 2 = stereo // Sets number of channels, 1 = mono, 2 = stereo
void FIFOSampleBuffer::setChannels(int numChannels) void FIFOSampleBuffer::setChannels(int numChannels)
{ {
uint usedBytes; uint usedBytes;
if (!verifyNumberOfChannels(numChannels)) return; if (!verifyNumberOfChannels(numChannels)) return;
usedBytes = channels * samplesInBuffer; usedBytes = channels * samplesInBuffer;
channels = (uint)numChannels; channels = (uint)numChannels;
samplesInBuffer = usedBytes / channels; samplesInBuffer = usedBytes / channels;
} }
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
// zeroes this pointer by copying samples from the 'bufferPos' pointer // zeroes this pointer by copying samples from the 'bufferPos' pointer
// location on to the beginning of the buffer. // location on to the beginning of the buffer.
void FIFOSampleBuffer::rewind() void FIFOSampleBuffer::rewind()
{ {
if (buffer && bufferPos) if (buffer && bufferPos)
{ {
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
bufferPos = 0; bufferPos = 0;
} }
} }
// Adds 'numSamples' pcs of samples from the 'samples' memory position to // Adds 'numSamples' pcs of samples from the 'samples' memory position to
// the sample buffer. // the sample buffer.
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{ {
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
samplesInBuffer += nSamples; samplesInBuffer += nSamples;
} }
// Increases the number of samples in the buffer without copying any actual // Increases the number of samples in the buffer without copying any actual
// samples. // samples.
// //
// This function is used to update the number of samples in the sample buffer // This function is used to update the number of samples in the sample buffer
// when accessing the buffer directly with 'ptrEnd' function. Please be // when accessing the buffer directly with 'ptrEnd' function. Please be
// careful though! // careful though!
void FIFOSampleBuffer::putSamples(uint nSamples) void FIFOSampleBuffer::putSamples(uint nSamples)
{ {
uint req; uint req;
req = samplesInBuffer + nSamples; req = samplesInBuffer + nSamples;
ensureCapacity(req); ensureCapacity(req);
samplesInBuffer += nSamples; samplesInBuffer += nSamples;
} }
// Returns a pointer to the end of the used part of the sample buffer (i.e. // 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 // 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! // inserting new samples into the sample buffer directly. Please be careful!
// //
// Parameter 'slackCapacity' tells the function how much free capacity (in // Parameter 'slackCapacity' tells the function how much free capacity (in
// terms of samples) there _at least_ should be, in order to the caller to // terms of samples) there _at least_ should be, in order to the caller to
// successfully insert all the required samples to the buffer. When necessary, // successfully insert all the required samples to the buffer. When necessary,
// the function grows the buffer size to comply with this requirement. // the function grows the buffer size to comply with this requirement.
// //
// When using this function as means for inserting new samples, also remember // When using this function as means for inserting new samples, also remember
// to increase the sample count afterwards, by calling the // to increase the sample count afterwards, by calling the
// 'putSamples(numSamples)' function. // 'putSamples(numSamples)' function.
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
{ {
ensureCapacity(samplesInBuffer + slackCapacity); ensureCapacity(samplesInBuffer + slackCapacity);
return buffer + samplesInBuffer * channels; return buffer + samplesInBuffer * channels;
} }
// Returns a pointer to the beginning of the currently non-outputted samples. // Returns a pointer to the beginning of the currently non-outputted samples.
// This function is provided for accessing the output samples directly. // This function is provided for accessing the output samples directly.
// Please be careful! // Please be careful!
// //
// When using this function to output samples, also remember to 'remove' the // When using this function to output samples, also remember to 'remove' the
// outputted samples from the buffer by calling the // outputted samples from the buffer by calling the
// 'receiveSamples(numSamples)' function // 'receiveSamples(numSamples)' function
SAMPLETYPE *FIFOSampleBuffer::ptrBegin() SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
{ {
assert(buffer); assert(buffer);
return buffer + bufferPos * channels; return buffer + bufferPos * channels;
} }
// Ensures that the buffer has enough capacity, i.e. space for _at least_ // Ensures that the buffer has enough capacity, i.e. space for _at least_
// 'capacityRequirement' number of samples. The buffer is grown in steps of // 'capacityRequirement' number of samples. The buffer is grown in steps of
// 4 kilobytes to eliminate the need for frequently growing up the buffer, // 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. // as well as to round the buffer size up to the virtual memory page size.
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
{ {
SAMPLETYPE *tempUnaligned, *temp; SAMPLETYPE *tempUnaligned, *temp;
if (capacityRequirement > getCapacity()) if (capacityRequirement > getCapacity())
{ {
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary) // enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
assert(sizeInBytes % 2 == 0); assert(sizeInBytes % 2 == 0);
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
if (tempUnaligned == nullptr) if (tempUnaligned == nullptr)
{ {
ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
} }
// Align the buffer to begin at 16byte cache line boundary for optimal performance // Align the buffer to begin at 16byte cache line boundary for optimal performance
temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned);
if (samplesInBuffer) if (samplesInBuffer)
{ {
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
} }
delete[] bufferUnaligned; delete[] bufferUnaligned;
buffer = temp; buffer = temp;
bufferUnaligned = tempUnaligned; bufferUnaligned = tempUnaligned;
bufferPos = 0; bufferPos = 0;
} }
else else
{ {
// simply rewind the buffer (if necessary) // simply rewind the buffer (if necessary)
rewind(); rewind();
} }
} }
// Returns the current buffer capacity in terms of samples // Returns the current buffer capacity in terms of samples
uint FIFOSampleBuffer::getCapacity() const uint FIFOSampleBuffer::getCapacity() const
{ {
return sizeInBytes / (channels * sizeof(SAMPLETYPE)); return sizeInBytes / (channels * sizeof(SAMPLETYPE));
} }
// Returns the number of samples currently in the buffer // Returns the number of samples currently in the buffer
uint FIFOSampleBuffer::numSamples() const uint FIFOSampleBuffer::numSamples() const
{ {
return samplesInBuffer; return samplesInBuffer;
} }
// Output samples from beginning of the sample buffer. Copies demanded number // Output samples from beginning of the sample buffer. Copies demanded number
// of samples to output and removes them from the sample buffer. If there // of samples to output and removes them from the sample buffer. If there
// are less than 'numsample' samples in the buffer, returns all available. // are less than 'numsample' samples in the buffer, returns all available.
// //
// Returns number of samples copied. // Returns number of samples copied.
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
{ {
uint num; uint num;
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
return receiveSamples(num); return receiveSamples(num);
} }
// Removes samples from the beginning of the sample buffer without copying them // 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 // anywhere. Used to reduce the number of samples in the buffer, when accessing
// the sample buffer with the 'ptrBegin' function. // the sample buffer with the 'ptrBegin' function.
uint FIFOSampleBuffer::receiveSamples(uint maxSamples) uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
{ {
if (maxSamples >= samplesInBuffer) if (maxSamples >= samplesInBuffer)
{ {
uint temp; uint temp;
temp = samplesInBuffer; temp = samplesInBuffer;
samplesInBuffer = 0; samplesInBuffer = 0;
return temp; return temp;
} }
samplesInBuffer -= maxSamples; samplesInBuffer -= maxSamples;
bufferPos += maxSamples; bufferPos += maxSamples;
return maxSamples; return maxSamples;
} }
// Returns nonzero if the sample buffer is empty // Returns nonzero if the sample buffer is empty
int FIFOSampleBuffer::isEmpty() const int FIFOSampleBuffer::isEmpty() const
{ {
return (samplesInBuffer == 0) ? 1 : 0; return (samplesInBuffer == 0) ? 1 : 0;
} }
// Clears the sample buffer // Clears the sample buffer
void FIFOSampleBuffer::clear() void FIFOSampleBuffer::clear()
{ {
samplesInBuffer = 0; samplesInBuffer = 0;
bufferPos = 0; bufferPos = 0;
} }
/// allow trimming (downwards) amount of samples in pipeline. /// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples /// Returns adjusted amount of samples
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
{ {
if (numSamples < samplesInBuffer) if (numSamples < samplesInBuffer)
{ {
samplesInBuffer = numSamples; samplesInBuffer = numSamples;
} }
return samplesInBuffer; return samplesInBuffer;
} }
/// Add silence to end of buffer /// Add silence to end of buffer
void FIFOSampleBuffer::addSilent(uint nSamples) void FIFOSampleBuffer::addSilent(uint nSamples)
{ {
memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels); memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels);
samplesInBuffer += nSamples; samplesInBuffer += nSamples;
} }

View File

@ -1,315 +1,315 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// General FIR digital filter routines with MMX optimization. /// General FIR digital filter routines with MMX optimization.
/// ///
/// Notes : MMX optimized functions reside in a separate, platform-specific file, /// Notes : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
/// ///
/// This source file contains OpenMP optimizations that allow speeding up the /// This source file contains OpenMP optimizations that allow speeding up the
/// corss-correlation algorithm by executing it in several threads / CPU cores /// corss-correlation algorithm by executing it in several threads / CPU cores
/// in parallel. See the following article link for more detailed discussion /// in parallel. See the following article link for more detailed discussion
/// about SoundTouch OpenMP optimizations: /// about SoundTouch OpenMP optimizations:
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices /// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <memory.h> #include <memory.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include "FIRFilter.h" #include "FIRFilter.h"
#include "cpu_detect.h" #include "cpu_detect.h"
using namespace soundtouch; using namespace soundtouch;
/***************************************************************************** /*****************************************************************************
* *
* Implementation of the class 'FIRFilter' * Implementation of the class 'FIRFilter'
* *
*****************************************************************************/ *****************************************************************************/
FIRFilter::FIRFilter() FIRFilter::FIRFilter()
{ {
resultDivFactor = 0; resultDivFactor = 0;
resultDivider = 0; resultDivider = 0;
length = 0; length = 0;
lengthDiv8 = 0; lengthDiv8 = 0;
filterCoeffs = nullptr; filterCoeffs = nullptr;
filterCoeffsStereo = nullptr; filterCoeffsStereo = nullptr;
} }
FIRFilter::~FIRFilter() FIRFilter::~FIRFilter()
{ {
delete[] filterCoeffs; delete[] filterCoeffs;
delete[] filterCoeffsStereo; delete[] filterCoeffsStereo;
} }
// Usual C-version of the filter routine for stereo sound // Usual C-version of the filter routine for stereo sound
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{ {
int j, end; int j, end;
// hint compiler autovectorization that loop length is divisible by 8 // hint compiler autovectorization that loop length is divisible by 8
uint ilength = length & -8; uint ilength = length & -8;
assert((length != 0) && (length == ilength) && (src != nullptr) && (dest != nullptr) && (filterCoeffs != nullptr)); assert((length != 0) && (length == ilength) && (src != nullptr) && (dest != nullptr) && (filterCoeffs != nullptr));
assert(numSamples > ilength); assert(numSamples > ilength);
end = 2 * (numSamples - ilength); end = 2 * (numSamples - ilength);
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j += 2) for (j = 0; j < end; j += 2)
{ {
const SAMPLETYPE *ptr; const SAMPLETYPE *ptr;
LONG_SAMPLETYPE suml, sumr; LONG_SAMPLETYPE suml, sumr;
suml = sumr = 0; suml = sumr = 0;
ptr = src + j; ptr = src + j;
for (uint i = 0; i < ilength; i ++) for (uint i = 0; i < ilength; i ++)
{ {
suml += ptr[2 * i] * filterCoeffsStereo[2 * i]; suml += ptr[2 * i] * filterCoeffsStereo[2 * i];
sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1]; sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1];
} }
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
suml >>= resultDivFactor; suml >>= resultDivFactor;
sumr >>= resultDivFactor; sumr >>= resultDivFactor;
// saturate to 16 bit integer limits // saturate to 16 bit integer limits
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
// saturate to 16 bit integer limits // saturate to 16 bit integer limits
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)suml; dest[j] = (SAMPLETYPE)suml;
dest[j + 1] = (SAMPLETYPE)sumr; dest[j + 1] = (SAMPLETYPE)sumr;
} }
return numSamples - ilength; return numSamples - ilength;
} }
// Usual C-version of the filter routine for mono sound // Usual C-version of the filter routine for mono sound
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{ {
int j, end; int j, end;
// hint compiler autovectorization that loop length is divisible by 8 // hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8; int ilength = length & -8;
assert(ilength != 0); assert(ilength != 0);
end = numSamples - ilength; end = numSamples - ilength;
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j ++) for (j = 0; j < end; j ++)
{ {
const SAMPLETYPE *pSrc = src + j; const SAMPLETYPE *pSrc = src + j;
LONG_SAMPLETYPE sum; LONG_SAMPLETYPE sum;
int i; int i;
sum = 0; sum = 0;
for (i = 0; i < ilength; i ++) for (i = 0; i < ilength; i ++)
{ {
sum += pSrc[i] * filterCoeffs[i]; sum += pSrc[i] * filterCoeffs[i];
} }
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
sum >>= resultDivFactor; sum >>= resultDivFactor;
// saturate to 16 bit integer limits // saturate to 16 bit integer limits
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)sum; dest[j] = (SAMPLETYPE)sum;
} }
return end; return end;
} }
uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
{ {
int j, end; int j, end;
assert(length != 0); assert(length != 0);
assert(src != nullptr); assert(src != nullptr);
assert(dest != nullptr); assert(dest != nullptr);
assert(filterCoeffs != nullptr); assert(filterCoeffs != nullptr);
assert(numChannels < 16); assert(numChannels < 16);
// hint compiler autovectorization that loop length is divisible by 8 // hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8; int ilength = length & -8;
end = numChannels * (numSamples - ilength); end = numChannels * (numSamples - ilength);
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j += numChannels) for (j = 0; j < end; j += numChannels)
{ {
const SAMPLETYPE *ptr; const SAMPLETYPE *ptr;
LONG_SAMPLETYPE sums[16]; LONG_SAMPLETYPE sums[16];
uint c; uint c;
int i; int i;
for (c = 0; c < numChannels; c ++) for (c = 0; c < numChannels; c ++)
{ {
sums[c] = 0; sums[c] = 0;
} }
ptr = src + j; ptr = src + j;
for (i = 0; i < ilength; i ++) for (i = 0; i < ilength; i ++)
{ {
SAMPLETYPE coef=filterCoeffs[i]; SAMPLETYPE coef=filterCoeffs[i];
for (c = 0; c < numChannels; c ++) for (c = 0; c < numChannels; c ++)
{ {
sums[c] += ptr[0] * coef; sums[c] += ptr[0] * coef;
ptr ++; ptr ++;
} }
} }
for (c = 0; c < numChannels; c ++) for (c = 0; c < numChannels; c ++)
{ {
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
sums[c] >>= resultDivFactor; sums[c] >>= resultDivFactor;
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j+c] = (SAMPLETYPE)sums[c]; dest[j+c] = (SAMPLETYPE)sums[c];
} }
} }
return numSamples - ilength; return numSamples - ilength;
} }
// Set filter coeffiecients and length. // Set filter coeffiecients and length.
// //
// Throws an exception if filter length isn't divisible by 8 // Throws an exception if filter length isn't divisible by 8
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
{ {
assert(newLength > 0); assert(newLength > 0);
if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");
#ifdef SOUNDTOUCH_FLOAT_SAMPLES #ifdef SOUNDTOUCH_FLOAT_SAMPLES
// scale coefficients already here if using floating samples // scale coefficients already here if using floating samples
double scale = 1.0 / resultDivider; double scale = 1.0 / resultDivider;
#else #else
short scale = 1; short scale = 1;
#endif #endif
lengthDiv8 = newLength / 8; lengthDiv8 = newLength / 8;
length = lengthDiv8 * 8; length = lengthDiv8 * 8;
assert(length == newLength); assert(length == newLength);
resultDivFactor = uResultDivFactor; resultDivFactor = uResultDivFactor;
resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
delete[] filterCoeffs; delete[] filterCoeffs;
filterCoeffs = new SAMPLETYPE[length]; filterCoeffs = new SAMPLETYPE[length];
delete[] filterCoeffsStereo; delete[] filterCoeffsStereo;
filterCoeffsStereo = new SAMPLETYPE[length*2]; filterCoeffsStereo = new SAMPLETYPE[length*2];
for (uint i = 0; i < length; i ++) for (uint i = 0; i < length; i ++)
{ {
filterCoeffs[i] = (SAMPLETYPE)(coeffs[i] * scale); filterCoeffs[i] = (SAMPLETYPE)(coeffs[i] * scale);
// create also stereo set of filter coefficients: this allows compiler // create also stereo set of filter coefficients: this allows compiler
// to autovectorize filter evaluation much more efficiently // to autovectorize filter evaluation much more efficiently
filterCoeffsStereo[2 * i] = (SAMPLETYPE)(coeffs[i] * scale); filterCoeffsStereo[2 * i] = (SAMPLETYPE)(coeffs[i] * scale);
filterCoeffsStereo[2 * i + 1] = (SAMPLETYPE)(coeffs[i] * scale); filterCoeffsStereo[2 * i + 1] = (SAMPLETYPE)(coeffs[i] * scale);
} }
} }
uint FIRFilter::getLength() const uint FIRFilter::getLength() const
{ {
return length; return length;
} }
// Applies the filter to the given sequence of samples. // Applies the filter to the given sequence of samples.
// //
// Note : The amount of outputted samples is by value of 'filter_length' // Note : The amount of outputted samples is by value of 'filter_length'
// smaller than the amount of input samples. // smaller than the amount of input samples.
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
{ {
assert(length > 0); assert(length > 0);
assert(lengthDiv8 * 8 == length); assert(lengthDiv8 * 8 == length);
if (numSamples < length) return 0; if (numSamples < length) return 0;
#ifndef USE_MULTICH_ALWAYS #ifndef USE_MULTICH_ALWAYS
if (numChannels == 1) if (numChannels == 1)
{ {
return evaluateFilterMono(dest, src, numSamples); return evaluateFilterMono(dest, src, numSamples);
} }
else if (numChannels == 2) else if (numChannels == 2)
{ {
return evaluateFilterStereo(dest, src, numSamples); return evaluateFilterStereo(dest, src, numSamples);
} }
else else
#endif // USE_MULTICH_ALWAYS #endif // USE_MULTICH_ALWAYS
{ {
assert(numChannels > 0); assert(numChannels > 0);
return evaluateFilterMulti(dest, src, numSamples, numChannels); return evaluateFilterMulti(dest, src, numSamples, numChannels);
} }
} }
// Operator 'new' is overloaded so that it automatically creates a suitable instance // Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not. // depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t) void * FIRFilter::operator new(size_t)
{ {
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! // 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!"); ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
return newInstance(); return newInstance();
} }
FIRFilter * FIRFilter::newInstance() FIRFilter * FIRFilter::newInstance()
{ {
uint uExtensions; uint uExtensions;
uExtensions = detectCPUextensions(); uExtensions = detectCPUextensions();
(void)uExtensions; (void)uExtensions;
// Check if MMX/SSE instruction set extensions supported by CPU // Check if MMX/SSE instruction set extensions supported by CPU
#ifdef SOUNDTOUCH_ALLOW_MMX #ifdef SOUNDTOUCH_ALLOW_MMX
// MMX routines available only with integer sample types // MMX routines available only with integer sample types
if (uExtensions & SUPPORT_MMX) if (uExtensions & SUPPORT_MMX)
{ {
return ::new FIRFilterMMX; return ::new FIRFilterMMX;
} }
else else
#endif // SOUNDTOUCH_ALLOW_MMX #endif // SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE #ifdef SOUNDTOUCH_ALLOW_SSE
if (uExtensions & SUPPORT_SSE) if (uExtensions & SUPPORT_SSE)
{ {
// SSE support // SSE support
return ::new FIRFilterSSE; return ::new FIRFilterSSE;
} }
else else
#endif // SOUNDTOUCH_ALLOW_SSE #endif // SOUNDTOUCH_ALLOW_SSE
{ {
// ISA optimizations not supported, use plain C version // ISA optimizations not supported, use plain C version
return ::new FIRFilter; return ::new FIRFilter;
} }
} }

View File

@ -1,140 +1,140 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// General FIR digital filter routines with MMX optimization. /// General FIR digital filter routines with MMX optimization.
/// ///
/// Note : MMX optimized functions reside in a separate, platform-specific file, /// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef FIRFilter_H #ifndef FIRFilter_H
#define FIRFilter_H #define FIRFilter_H
#include <stddef.h> #include <stddef.h>
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
class FIRFilter class FIRFilter
{ {
protected: protected:
// Number of FIR filter taps // Number of FIR filter taps
uint length; uint length;
// Number of FIR filter taps divided by 8 // Number of FIR filter taps divided by 8
uint lengthDiv8; uint lengthDiv8;
// Result divider factor in 2^k format // Result divider factor in 2^k format
uint resultDivFactor; uint resultDivFactor;
// Result divider value. // Result divider value.
SAMPLETYPE resultDivider; SAMPLETYPE resultDivider;
// Memory for filter coefficients // Memory for filter coefficients
SAMPLETYPE *filterCoeffs; SAMPLETYPE *filterCoeffs;
SAMPLETYPE *filterCoeffsStereo; SAMPLETYPE *filterCoeffsStereo;
virtual uint evaluateFilterStereo(SAMPLETYPE *dest, virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples) const; uint numSamples) const;
virtual uint evaluateFilterMono(SAMPLETYPE *dest, virtual uint evaluateFilterMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples) const; uint numSamples) const;
virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels); virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels);
public: public:
FIRFilter(); FIRFilter();
virtual ~FIRFilter(); virtual ~FIRFilter();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance /// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX-capable CPU available or not. /// depending on if we've a MMX-capable CPU available or not.
static void * operator new(size_t s); static void * operator new(size_t s);
static FIRFilter *newInstance(); static FIRFilter *newInstance();
/// Applies the filter to the given sequence of samples. /// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter_length' /// Note : The amount of outputted samples is by value of 'filter_length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
/// ///
/// \return Number of samples copied to 'dest'. /// \return Number of samples copied to 'dest'.
uint evaluate(SAMPLETYPE *dest, uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples, uint numSamples,
uint numChannels); uint numChannels);
uint getLength() const; uint getLength() const;
virtual void setCoefficients(const SAMPLETYPE *coeffs, virtual void setCoefficients(const SAMPLETYPE *coeffs,
uint newLength, uint newLength,
uint uResultDivFactor); uint uResultDivFactor);
}; };
// Optional subclasses that implement CPU-specific optimizations: // Optional subclasses that implement CPU-specific optimizations:
#ifdef SOUNDTOUCH_ALLOW_MMX #ifdef SOUNDTOUCH_ALLOW_MMX
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type. /// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
class FIRFilterMMX : public FIRFilter class FIRFilterMMX : public FIRFilter
{ {
protected: protected:
short *filterCoeffsUnalign; short *filterCoeffsUnalign;
short *filterCoeffsAlign; short *filterCoeffsAlign;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const override; virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const override;
public: public:
FIRFilterMMX(); FIRFilterMMX();
~FIRFilterMMX(); ~FIRFilterMMX();
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) override; virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) override;
}; };
#endif // SOUNDTOUCH_ALLOW_MMX #endif // SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE #ifdef SOUNDTOUCH_ALLOW_SSE
/// Class that implements SSE optimized functions exclusive for floating point samples type. /// Class that implements SSE optimized functions exclusive for floating point samples type.
class FIRFilterSSE : public FIRFilter class FIRFilterSSE : public FIRFilter
{ {
protected: protected:
float *filterCoeffsUnalign; float *filterCoeffsUnalign;
float *filterCoeffsAlign; float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const override; virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const override;
public: public:
FIRFilterSSE(); FIRFilterSSE();
~FIRFilterSSE(); ~FIRFilterSSE();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) override; virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) override;
}; };
#endif // SOUNDTOUCH_ALLOW_SSE #endif // SOUNDTOUCH_ALLOW_SSE
} }
#endif // FIRFilter_H #endif // FIRFilter_H

View File

@ -1,196 +1,196 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Cubic interpolation routine. /// Cubic interpolation routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <stddef.h> #include <stddef.h>
#include <math.h> #include <math.h>
#include "InterpolateCubic.h" #include "InterpolateCubic.h"
#include "STTypes.h" #include "STTypes.h"
using namespace soundtouch; using namespace soundtouch;
// cubic interpolation coefficients // cubic interpolation coefficients
static const float _coeffs[]= static const float _coeffs[]=
{ -0.5f, 1.0f, -0.5f, 0.0f, { -0.5f, 1.0f, -0.5f, 0.0f,
1.5f, -2.5f, 0.0f, 1.0f, 1.5f, -2.5f, 0.0f, 1.0f,
-1.5f, 2.0f, 0.5f, 0.0f, -1.5f, 2.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f}; 0.5f, -0.5f, 0.0f, 0.0f};
InterpolateCubic::InterpolateCubic() InterpolateCubic::InterpolateCubic()
{ {
fract = 0; fract = 0;
} }
void InterpolateCubic::resetRegisters() void InterpolateCubic::resetRegisters()
{ {
fract = 0; fract = 0;
} }
/// Transpose mono audio. Returns number of produced output samples, and /// Transpose mono audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, int InterpolateCubic::transposeMono(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 4; int srcSampleEnd = srcSamples - 4;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
float out; float out;
const float x3 = 1.0f; const float x3 = 1.0f;
const float x2 = (float)fract; // x const float x2 = (float)fract; // x
const float x1 = x2*x2; // x^2 const float x1 = x2*x2; // x^2
const float x0 = x1*x2; // x^3 const float x0 = x1*x2; // x^3
float y0, y1, y2, y3; float y0, y1, y2, y3;
assert(fract < 1.0); assert(fract < 1.0);
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; 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; 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; 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; 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]; out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3];
pdest[i] = (SAMPLETYPE)out; pdest[i] = (SAMPLETYPE)out;
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
psrc += whole; psrc += whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 4; int srcSampleEnd = srcSamples - 4;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
const float x3 = 1.0f; const float x3 = 1.0f;
const float x2 = (float)fract; // x const float x2 = (float)fract; // x
const float x1 = x2*x2; // x^2 const float x1 = x2*x2; // x^2
const float x0 = x1*x2; // x^3 const float x0 = x1*x2; // x^3
float y0, y1, y2, y3; float y0, y1, y2, y3;
float out0, out1; float out0, out1;
assert(fract < 1.0); assert(fract < 1.0);
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; 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; 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; 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; 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]; 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]; out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7];
pdest[2*i] = (SAMPLETYPE)out0; pdest[2*i] = (SAMPLETYPE)out0;
pdest[2*i+1] = (SAMPLETYPE)out1; pdest[2*i+1] = (SAMPLETYPE)out1;
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
psrc += 2*whole; psrc += 2*whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
/// Transpose multi-channel audio. Returns number of produced output samples, and /// Transpose multi-channel audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 4; int srcSampleEnd = srcSamples - 4;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
const float x3 = 1.0f; const float x3 = 1.0f;
const float x2 = (float)fract; // x const float x2 = (float)fract; // x
const float x1 = x2*x2; // x^2 const float x1 = x2*x2; // x^2
const float x0 = x1*x2; // x^3 const float x0 = x1*x2; // x^3
float y0, y1, y2, y3; float y0, y1, y2, y3;
assert(fract < 1.0); assert(fract < 1.0);
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; 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; 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; 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; y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
for (int c = 0; c < numChannels; c ++) for (int c = 0; c < numChannels; c ++)
{ {
float out; float out;
out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels];
pdest[0] = (SAMPLETYPE)out; pdest[0] = (SAMPLETYPE)out;
pdest ++; pdest ++;
} }
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
psrc += numChannels*whole; psrc += numChannels*whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }

View File

@ -1,69 +1,69 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Cubic interpolation routine. /// Cubic interpolation routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _InterpolateCubic_H_ #ifndef _InterpolateCubic_H_
#define _InterpolateCubic_H_ #define _InterpolateCubic_H_
#include "RateTransposer.h" #include "RateTransposer.h"
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
class InterpolateCubic : public TransposerBase class InterpolateCubic : public TransposerBase
{ {
protected: protected:
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
double fract; double fract;
public: public:
InterpolateCubic(); InterpolateCubic();
virtual void resetRegisters() override; virtual void resetRegisters() override;
virtual int getLatency() const override virtual int getLatency() const override
{ {
return 1; return 1;
} }
}; };
} }
#endif #endif

View File

@ -1,296 +1,296 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Linear interpolation algorithm. /// Linear interpolation algorithm.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include "InterpolateLinear.h" #include "InterpolateLinear.h"
using namespace soundtouch; using namespace soundtouch;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// InterpolateLinearInteger - integer arithmetic implementation // InterpolateLinearInteger - integer arithmetic implementation
// //
/// fixed-point interpolation routine precision /// fixed-point interpolation routine precision
#define SCALE 65536 #define SCALE 65536
// Constructor // Constructor
InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase()
{ {
// Notice: use local function calling syntax for sake of clarity, // Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions. // to indicate the fact that C++ constructor can't call virtual functions.
resetRegisters(); resetRegisters();
setRate(1.0f); setRate(1.0f);
} }
void InterpolateLinearInteger::resetRegisters() void InterpolateLinearInteger::resetRegisters()
{ {
iFract = 0; iFract = 0;
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in // 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 1; int srcSampleEnd = srcSamples - 1;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
LONG_SAMPLETYPE temp; LONG_SAMPLETYPE temp;
assert(iFract < SCALE); assert(iFract < SCALE);
temp = (SCALE - iFract) * src[0] + iFract * src[1]; temp = (SCALE - iFract) * src[0] + iFract * src[1];
dest[i] = (SAMPLETYPE)(temp / SCALE); dest[i] = (SAMPLETYPE)(temp / SCALE);
i++; i++;
iFract += iRate; iFract += iRate;
int iWhole = iFract / SCALE; int iWhole = iFract / SCALE;
iFract -= iWhole * SCALE; iFract -= iWhole * SCALE;
srcCount += iWhole; srcCount += iWhole;
src += iWhole; src += iWhole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Stereo' version of the routine. Returns the number of samples returned in // 'Stereo' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 1; int srcSampleEnd = srcSamples - 1;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
LONG_SAMPLETYPE temp0; LONG_SAMPLETYPE temp0;
LONG_SAMPLETYPE temp1; LONG_SAMPLETYPE temp1;
assert(iFract < SCALE); assert(iFract < SCALE);
temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; temp0 = (SCALE - iFract) * src[0] + iFract * src[2];
temp1 = (SCALE - iFract) * src[1] + iFract * src[3]; temp1 = (SCALE - iFract) * src[1] + iFract * src[3];
dest[0] = (SAMPLETYPE)(temp0 / SCALE); dest[0] = (SAMPLETYPE)(temp0 / SCALE);
dest[1] = (SAMPLETYPE)(temp1 / SCALE); dest[1] = (SAMPLETYPE)(temp1 / SCALE);
dest += 2; dest += 2;
i++; i++;
iFract += iRate; iFract += iRate;
int iWhole = iFract / SCALE; int iWhole = iFract / SCALE;
iFract -= iWhole * SCALE; iFract -= iWhole * SCALE;
srcCount += iWhole; srcCount += iWhole;
src += 2*iWhole; src += 2*iWhole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 1; int srcSampleEnd = srcSamples - 1;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
LONG_SAMPLETYPE temp, vol1; LONG_SAMPLETYPE temp, vol1;
assert(iFract < SCALE); assert(iFract < SCALE);
vol1 = (LONG_SAMPLETYPE)(SCALE - iFract); vol1 = (LONG_SAMPLETYPE)(SCALE - iFract);
for (int c = 0; c < numChannels; c ++) for (int c = 0; c < numChannels; c ++)
{ {
temp = vol1 * src[c] + iFract * src[c + numChannels]; temp = vol1 * src[c] + iFract * src[c + numChannels];
dest[0] = (SAMPLETYPE)(temp / SCALE); dest[0] = (SAMPLETYPE)(temp / SCALE);
dest ++; dest ++;
} }
i++; i++;
iFract += iRate; iFract += iRate;
int iWhole = iFract / SCALE; int iWhole = iFract / SCALE;
iFract -= iWhole * SCALE; iFract -= iWhole * SCALE;
srcCount += iWhole; srcCount += iWhole;
src += iWhole * numChannels; src += iWhole * numChannels;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates. // iRate, larger faster iRates.
void InterpolateLinearInteger::setRate(double newRate) void InterpolateLinearInteger::setRate(double newRate)
{ {
iRate = (int)(newRate * SCALE + 0.5); iRate = (int)(newRate * SCALE + 0.5);
TransposerBase::setRate(newRate); TransposerBase::setRate(newRate);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// InterpolateLinearFloat - floating point arithmetic implementation // InterpolateLinearFloat - floating point arithmetic implementation
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase()
{ {
// Notice: use local function calling syntax for sake of clarity, // Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions. // to indicate the fact that C++ constructor can't call virtual functions.
resetRegisters(); resetRegisters();
setRate(1.0); setRate(1.0);
} }
void InterpolateLinearFloat::resetRegisters() void InterpolateLinearFloat::resetRegisters()
{ {
fract = 0; fract = 0;
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in // 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 1; int srcSampleEnd = srcSamples - 1;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
double out; double out;
assert(fract < 1.0); assert(fract < 1.0);
out = (1.0 - fract) * src[0] + fract * src[1]; out = (1.0 - fract) * src[0] + fract * src[1];
dest[i] = (SAMPLETYPE)out; dest[i] = (SAMPLETYPE)out;
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
src += whole; src += whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in // 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 1; int srcSampleEnd = srcSamples - 1;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
double out0, out1; double out0, out1;
assert(fract < 1.0); assert(fract < 1.0);
out0 = (1.0 - fract) * src[0] + fract * src[2]; out0 = (1.0 - fract) * src[0] + fract * src[2];
out1 = (1.0 - fract) * src[1] + fract * src[3]; out1 = (1.0 - fract) * src[1] + fract * src[3];
dest[2*i] = (SAMPLETYPE)out0; dest[2*i] = (SAMPLETYPE)out0;
dest[2*i+1] = (SAMPLETYPE)out1; dest[2*i+1] = (SAMPLETYPE)out1;
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
src += 2*whole; src += 2*whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 1; int srcSampleEnd = srcSamples - 1;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
float temp, vol1, fract_float; float temp, vol1, fract_float;
vol1 = (float)(1.0 - fract); vol1 = (float)(1.0 - fract);
fract_float = (float)fract; fract_float = (float)fract;
for (int c = 0; c < numChannels; c ++) for (int c = 0; c < numChannels; c ++)
{ {
temp = vol1 * src[c] + fract_float * src[c + numChannels]; temp = vol1 * src[c] + fract_float * src[c + numChannels];
*dest = (SAMPLETYPE)temp; *dest = (SAMPLETYPE)temp;
dest ++; dest ++;
} }
i++; i++;
fract += rate; fract += rate;
int iWhole = (int)fract; int iWhole = (int)fract;
fract -= iWhole; fract -= iWhole;
srcCount += iWhole; srcCount += iWhole;
src += iWhole * numChannels; src += iWhole * numChannels;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }

View File

@ -1,98 +1,98 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Linear interpolation routine. /// Linear interpolation routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _InterpolateLinear_H_ #ifndef _InterpolateLinear_H_
#define _InterpolateLinear_H_ #define _InterpolateLinear_H_
#include "RateTransposer.h" #include "RateTransposer.h"
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
/// Linear transposer class that uses integer arithmetic /// Linear transposer class that uses integer arithmetic
class InterpolateLinearInteger : public TransposerBase class InterpolateLinearInteger : public TransposerBase
{ {
protected: protected:
int iFract; int iFract;
int iRate; int iRate;
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override; virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override;
public: public:
InterpolateLinearInteger(); InterpolateLinearInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates. /// rate, larger faster rates.
virtual void setRate(double newRate) override; virtual void setRate(double newRate) override;
virtual void resetRegisters() override; virtual void resetRegisters() override;
virtual int getLatency() const override virtual int getLatency() const override
{ {
return 0; return 0;
} }
}; };
/// Linear transposer class that uses floating point arithmetic /// Linear transposer class that uses floating point arithmetic
class InterpolateLinearFloat : public TransposerBase class InterpolateLinearFloat : public TransposerBase
{ {
protected: protected:
double fract; double fract;
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples);
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples);
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
public: public:
InterpolateLinearFloat(); InterpolateLinearFloat();
virtual void resetRegisters(); virtual void resetRegisters();
int getLatency() const int getLatency() const
{ {
return 0; return 0;
} }
}; };
} }
#endif #endif

View File

@ -1,181 +1,181 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation /// Sample interpolation routine using 8-tap band-limited Shannon interpolation
/// with kaiser window. /// with kaiser window.
/// ///
/// Notice. This algorithm is remarkably much heavier than linear or cubic /// Notice. This algorithm is remarkably much heavier than linear or cubic
/// interpolation, and not remarkably better than cubic algorithm. Thus mostly /// interpolation, and not remarkably better than cubic algorithm. Thus mostly
/// for experimental purposes /// for experimental purposes
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <math.h> #include <math.h>
#include "InterpolateShannon.h" #include "InterpolateShannon.h"
#include "STTypes.h" #include "STTypes.h"
using namespace soundtouch; using namespace soundtouch;
/// Kaiser window with beta = 2.0 /// Kaiser window with beta = 2.0
/// Values scaled down by 5% to avoid overflows /// Values scaled down by 5% to avoid overflows
static const double _kaiser8[8] = static const double _kaiser8[8] =
{ {
0.41778693317814, 0.41778693317814,
0.64888025049173, 0.64888025049173,
0.83508562409944, 0.83508562409944,
0.93887857733412, 0.93887857733412,
0.93887857733412, 0.93887857733412,
0.83508562409944, 0.83508562409944,
0.64888025049173, 0.64888025049173,
0.41778693317814 0.41778693317814
}; };
InterpolateShannon::InterpolateShannon() InterpolateShannon::InterpolateShannon()
{ {
fract = 0; fract = 0;
} }
void InterpolateShannon::resetRegisters() void InterpolateShannon::resetRegisters()
{ {
fract = 0; fract = 0;
} }
#define PI 3.1415926536 #define PI 3.1415926536
#define sinc(x) (sin(PI * (x)) / (PI * (x))) #define sinc(x) (sin(PI * (x)) / (PI * (x)))
/// Transpose mono audio. Returns number of produced output samples, and /// Transpose mono audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, int InterpolateShannon::transposeMono(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 8; int srcSampleEnd = srcSamples - 8;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
double out; double out;
assert(fract < 1.0); assert(fract < 1.0);
out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0]; out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0];
out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1]; out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1];
out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2]; out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2];
if (fract < 1e-6) if (fract < 1e-6)
{ {
out += psrc[3] * _kaiser8[3]; // sinc(0) = 1 out += psrc[3] * _kaiser8[3]; // sinc(0) = 1
} }
else else
{ {
out += psrc[3] * sinc(- fract) * _kaiser8[3]; out += psrc[3] * sinc(- fract) * _kaiser8[3];
} }
out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4]; out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4];
out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5]; out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5];
out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6]; out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6];
out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7]; out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7];
pdest[i] = (SAMPLETYPE)out; pdest[i] = (SAMPLETYPE)out;
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
psrc += whole; psrc += whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
int srcSampleEnd = srcSamples - 8; int srcSampleEnd = srcSamples - 8;
int srcCount = 0; int srcCount = 0;
i = 0; i = 0;
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
double out0, out1, w; double out0, out1, w;
assert(fract < 1.0); assert(fract < 1.0);
w = sinc(-3.0 - fract) * _kaiser8[0]; w = sinc(-3.0 - fract) * _kaiser8[0];
out0 = psrc[0] * w; out1 = psrc[1] * w; out0 = psrc[0] * w; out1 = psrc[1] * w;
w = sinc(-2.0 - fract) * _kaiser8[1]; w = sinc(-2.0 - fract) * _kaiser8[1];
out0 += psrc[2] * w; out1 += psrc[3] * w; out0 += psrc[2] * w; out1 += psrc[3] * w;
w = sinc(-1.0 - fract) * _kaiser8[2]; w = sinc(-1.0 - fract) * _kaiser8[2];
out0 += psrc[4] * w; out1 += psrc[5] * w; out0 += psrc[4] * w; out1 += psrc[5] * w;
w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1 w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1
out0 += psrc[6] * w; out1 += psrc[7] * w; out0 += psrc[6] * w; out1 += psrc[7] * w;
w = sinc( 1.0 - fract) * _kaiser8[4]; w = sinc( 1.0 - fract) * _kaiser8[4];
out0 += psrc[8] * w; out1 += psrc[9] * w; out0 += psrc[8] * w; out1 += psrc[9] * w;
w = sinc( 2.0 - fract) * _kaiser8[5]; w = sinc( 2.0 - fract) * _kaiser8[5];
out0 += psrc[10] * w; out1 += psrc[11] * w; out0 += psrc[10] * w; out1 += psrc[11] * w;
w = sinc( 3.0 - fract) * _kaiser8[6]; w = sinc( 3.0 - fract) * _kaiser8[6];
out0 += psrc[12] * w; out1 += psrc[13] * w; out0 += psrc[12] * w; out1 += psrc[13] * w;
w = sinc( 4.0 - fract) * _kaiser8[7]; w = sinc( 4.0 - fract) * _kaiser8[7];
out0 += psrc[14] * w; out1 += psrc[15] * w; out0 += psrc[14] * w; out1 += psrc[15] * w;
pdest[2*i] = (SAMPLETYPE)out0; pdest[2*i] = (SAMPLETYPE)out0;
pdest[2*i+1] = (SAMPLETYPE)out1; pdest[2*i+1] = (SAMPLETYPE)out1;
i ++; i ++;
// update position fraction // update position fraction
fract += rate; fract += rate;
// update whole positions // update whole positions
int whole = (int)fract; int whole = (int)fract;
fract -= whole; fract -= whole;
psrc += 2*whole; psrc += 2*whole;
srcCount += whole; srcCount += whole;
} }
srcSamples = srcCount; srcSamples = srcCount;
return i; return i;
} }
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMulti(SAMPLETYPE *, int InterpolateShannon::transposeMulti(SAMPLETYPE *,
const SAMPLETYPE *, const SAMPLETYPE *,
int &) int &)
{ {
// not implemented // not implemented
assert(false); assert(false);
return 0; return 0;
} }

View File

@ -1,74 +1,74 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation /// Sample interpolation routine using 8-tap band-limited Shannon interpolation
/// with kaiser window. /// with kaiser window.
/// ///
/// Notice. This algorithm is remarkably much heavier than linear or cubic /// Notice. This algorithm is remarkably much heavier than linear or cubic
/// interpolation, and not remarkably better than cubic algorithm. Thus mostly /// interpolation, and not remarkably better than cubic algorithm. Thus mostly
/// for experimental purposes /// for experimental purposes
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _InterpolateShannon_H_ #ifndef _InterpolateShannon_H_
#define _InterpolateShannon_H_ #define _InterpolateShannon_H_
#include "RateTransposer.h" #include "RateTransposer.h"
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
class InterpolateShannon : public TransposerBase class InterpolateShannon : public TransposerBase
{ {
protected: protected:
int transposeMono(SAMPLETYPE *dest, int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
int transposeStereo(SAMPLETYPE *dest, int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
int transposeMulti(SAMPLETYPE *dest, int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
double fract; double fract;
public: public:
InterpolateShannon(); InterpolateShannon();
void resetRegisters() override; void resetRegisters() override;
virtual int getLatency() const override virtual int getLatency() const override
{ {
return 3; return 3;
} }
}; };
} }
#endif #endif

View File

@ -1,74 +1,74 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
## ##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
## ##
## SoundTouch is free software; you can redistribute it and/or modify it under the ## SoundTouch 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 ## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later ## Foundation; either version 2 of the License, or (at your option) any later
## version. ## version.
## ##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY ## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details. ## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
## ##
## You should have received a copy of the GNU General Public License along with ## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA ## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk include $(top_srcdir)/config/am_include.mk
# set to something if you want other stuff to be included in the distribution tarball # set to something if you want other stuff to be included in the distribution tarball
EXTRA_DIST=SoundTouch.sln SoundTouch.vcxproj EXTRA_DIST=SoundTouch.sln SoundTouch.vcxproj
noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h \ noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h \
InterpolateCubic.h InterpolateLinear.h InterpolateShannon.h InterpolateCubic.h InterpolateLinear.h InterpolateShannon.h
lib_LTLIBRARIES=libSoundTouch.la lib_LTLIBRARIES=libSoundTouch.la
# #
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \ libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \
RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp \ RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp \
BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \ BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \
InterpolateShannon.cpp InterpolateShannon.cpp
# Compiler flags # Compiler flags
#AM_CXXFLAGS+= #AM_CXXFLAGS+=
# Compile the files that need MMX and SSE individually. # Compile the files that need MMX and SSE individually.
libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la
noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la
libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp
libSoundTouchSSE_la_SOURCES=sse_optimized.cpp libSoundTouchSSE_la_SOURCES=sse_optimized.cpp
# We enable optimizations by default. # We enable optimizations by default.
# If MMX is supported compile with -mmmx. # If MMX is supported compile with -mmmx.
# Do not assume -msse is also supported. # Do not assume -msse is also supported.
if HAVE_MMX if HAVE_MMX
libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS) libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS)
else else
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS) libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
endif endif
# We enable optimizations by default. # We enable optimizations by default.
# If SSE is supported compile with -msse. # If SSE is supported compile with -msse.
if HAVE_SSE if HAVE_SSE
libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS) libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS)
else else
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS) libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
endif endif
# Let the user disable optimizations if he wishes to. # Let the user disable optimizations if he wishes to.
if !X86_OPTIMIZATIONS if !X86_OPTIMIZATIONS
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS) libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS) libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
endif endif
# Modify the default 0.0.0 to LIB_SONAME.0.0 # Modify the default 0.0.0 to LIB_SONAME.0.0
libSoundTouch_la_LDFLAGS=-version-info @LIB_SONAME@ libSoundTouch_la_LDFLAGS=-version-info @LIB_SONAME@
# other linking flags to add # other linking flags to add
# noinst_LTLIBRARIES = libSoundTouchOpt.la # noinst_LTLIBRARIES = libSoundTouchOpt.la
# libSoundTouch_la_LIBADD = libSoundTouchOpt.la # libSoundTouch_la_LIBADD = libSoundTouchOpt.la
# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp # libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp
# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include # libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include

View File

@ -1,277 +1,277 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Peak detection routine. /// Peak detection routine.
/// ///
/// The routine detects highest value on an array of values and calculates the /// 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. /// precise peak location as a mass-center of the 'hump' around the peak value.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include "PeakFinder.h" #include "PeakFinder.h"
using namespace soundtouch; using namespace soundtouch;
#define max(x, y) (((x) > (y)) ? (x) : (y)) #define max(x, y) (((x) > (y)) ? (x) : (y))
PeakFinder::PeakFinder() PeakFinder::PeakFinder()
{ {
minPos = maxPos = 0; minPos = maxPos = 0;
} }
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
int PeakFinder::findTop(const float *data, int peakpos) const int PeakFinder::findTop(const float *data, int peakpos) const
{ {
int i; int i;
int start, end; int start, end;
float refvalue; float refvalue;
refvalue = data[peakpos]; refvalue = data[peakpos];
// seek within ±10 points // seek within ±10 points
start = peakpos - 10; start = peakpos - 10;
if (start < minPos) start = minPos; if (start < minPos) start = minPos;
end = peakpos + 10; end = peakpos + 10;
if (end > maxPos) end = maxPos; if (end > maxPos) end = maxPos;
for (i = start; i <= end; i ++) for (i = start; i <= end; i ++)
{ {
if (data[i] > refvalue) if (data[i] > refvalue)
{ {
peakpos = i; peakpos = i;
refvalue = data[i]; refvalue = data[i];
} }
} }
// failure if max value is at edges of seek range => it's not peak, it's at slope. // 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; if ((peakpos == start) || (peakpos == end)) return 0;
return peakpos; return peakpos;
} }
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding // 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 // to direction defined by 'direction' until next 'hump' after minimum value will
// begin // begin
int PeakFinder::findGround(const float *data, int peakpos, int direction) const int PeakFinder::findGround(const float *data, int peakpos, int direction) const
{ {
int lowpos; int lowpos;
int pos; int pos;
int climb_count; int climb_count;
float refvalue; float refvalue;
float delta; float delta;
climb_count = 0; climb_count = 0;
refvalue = data[peakpos]; refvalue = data[peakpos];
lowpos = peakpos; lowpos = peakpos;
pos = peakpos; pos = peakpos;
while ((pos > minPos+1) && (pos < maxPos-1)) while ((pos > minPos+1) && (pos < maxPos-1))
{ {
int prevpos; int prevpos;
prevpos = pos; prevpos = pos;
pos += direction; pos += direction;
// calculate derivate // calculate derivate
delta = data[pos] - data[prevpos]; delta = data[pos] - data[prevpos];
if (delta <= 0) if (delta <= 0)
{ {
// going downhill, ok // going downhill, ok
if (climb_count) if (climb_count)
{ {
climb_count --; // decrease climb count climb_count --; // decrease climb count
} }
// check if new minimum found // check if new minimum found
if (data[pos] < refvalue) if (data[pos] < refvalue)
{ {
// new minimum found // new minimum found
lowpos = pos; lowpos = pos;
refvalue = data[pos]; refvalue = data[pos];
} }
} }
else else
{ {
// going uphill, increase climbing counter // going uphill, increase climbing counter
climb_count ++; climb_count ++;
if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit
} }
} }
return lowpos; return lowpos;
} }
// Find offset where the value crosses the given level, when starting from 'peakpos' and // Find offset where the value crosses the given level, when starting from 'peakpos' and
// proceeds to direction defined in 'direction' // proceeds to direction defined in 'direction'
int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
{ {
float peaklevel; float peaklevel;
int pos; int pos;
peaklevel = data[peakpos]; peaklevel = data[peakpos];
assert(peaklevel >= level); assert(peaklevel >= level);
pos = peakpos; pos = peakpos;
while ((pos >= minPos) && (pos + direction < maxPos)) while ((pos >= minPos) && (pos + direction < maxPos))
{ {
if (data[pos + direction] < level) return pos; // crossing found if (data[pos + direction] < level) return pos; // crossing found
pos += direction; pos += direction;
} }
return -1; // not found return -1; // not found
} }
// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos' // 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 double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
{ {
int i; int i;
float sum; float sum;
float wsum; float wsum;
sum = 0; sum = 0;
wsum = 0; wsum = 0;
for (i = firstPos; i <= lastPos; i ++) for (i = firstPos; i <= lastPos; i ++)
{ {
sum += (float)i * data[i]; sum += (float)i * data[i];
wsum += data[i]; wsum += data[i];
} }
if (wsum < 1e-6) return 0; if (wsum < 1e-6) return 0;
return sum / wsum; return sum / wsum;
} }
/// get exact center of peak near given position by calculating local mass of center /// get exact center of peak near given position by calculating local mass of center
double PeakFinder::getPeakCenter(const float *data, int peakpos) const double PeakFinder::getPeakCenter(const float *data, int peakpos) const
{ {
float peakLevel; // peak level float peakLevel; // peak level
int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level
float cutLevel; // cutting value float cutLevel; // cutting value
float groundLevel; // ground level of the peak float groundLevel; // ground level of the peak
int gp1, gp2; // bottom positions of the peak 'hump' int gp1, gp2; // bottom positions of the peak 'hump'
// find ground positions. // find ground positions.
gp1 = findGround(data, peakpos, -1); gp1 = findGround(data, peakpos, -1);
gp2 = findGround(data, peakpos, 1); gp2 = findGround(data, peakpos, 1);
peakLevel = data[peakpos]; peakLevel = data[peakpos];
if (gp1 == gp2) if (gp1 == gp2)
{ {
// avoid rounding errors when all are equal // avoid rounding errors when all are equal
assert(gp1 == peakpos); assert(gp1 == peakpos);
cutLevel = groundLevel = peakLevel; cutLevel = groundLevel = peakLevel;
} else { } else {
// get average of the ground levels // get average of the ground levels
groundLevel = 0.5f * (data[gp1] + data[gp2]); groundLevel = 0.5f * (data[gp1] + data[gp2]);
// calculate 70%-level of the peak // calculate 70%-level of the peak
cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
} }
// find mid-level crossings // find mid-level crossings
crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1); crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1); crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak.. if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak..
// calculate mass center of the peak surroundings // calculate mass center of the peak surroundings
return calcMassCenter(data, crosspos1, crosspos2); return calcMassCenter(data, crosspos1, crosspos2);
} }
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
{ {
int i; int i;
int peakpos; // position of peak level int peakpos; // position of peak level
double highPeak, peak; double highPeak, peak;
this->minPos = aminPos; this->minPos = aminPos;
this->maxPos = amaxPos; this->maxPos = amaxPos;
// find absolute peak // find absolute peak
peakpos = minPos; peakpos = minPos;
peak = data[minPos]; peak = data[minPos];
for (i = minPos + 1; i < maxPos; i ++) for (i = minPos + 1; i < maxPos; i ++)
{ {
if (data[i] > peak) if (data[i] > peak)
{ {
peak = data[i]; peak = data[i];
peakpos = i; peakpos = i;
} }
} }
// Calculate exact location of the highest peak mass center // Calculate exact location of the highest peak mass center
highPeak = getPeakCenter(data, peakpos); highPeak = getPeakCenter(data, peakpos);
peak = highPeak; peak = highPeak;
// Now check if the highest peak were in fact harmonic of the true base beat peak // 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 // - sometimes the highest peak can be Nth harmonic of the true base peak yet
// just a slightly higher than the true base // just a slightly higher than the true base
for (i = 1; i < 3; i ++) for (i = 1; i < 3; i ++)
{ {
double peaktmp, harmonic; double peaktmp, harmonic;
int i1,i2; int i1,i2;
harmonic = (double)pow(2.0, i); harmonic = (double)pow(2.0, i);
peakpos = (int)(highPeak / harmonic + 0.5f); peakpos = (int)(highPeak / harmonic + 0.5f);
if (peakpos < minPos) break; if (peakpos < minPos) break;
peakpos = findTop(data, peakpos); // seek true local maximum index peakpos = findTop(data, peakpos); // seek true local maximum index
if (peakpos == 0) continue; // no local max here if (peakpos == 0) continue; // no local max here
// calculate mass-center of possible harmonic peak // calculate mass-center of possible harmonic peak
peaktmp = getPeakCenter(data, peakpos); peaktmp = getPeakCenter(data, peakpos);
// accept harmonic peak if // accept harmonic peak if
// (a) it is found // (a) it is found
// (b) is within ±4% of the expected harmonic interval // (b) is within ±4% of the expected harmonic interval
// (c) has at least half x-corr value of the max. peak // (c) has at least half x-corr value of the max. peak
double diff = harmonic * peaktmp / highPeak; double diff = harmonic * peaktmp / highPeak;
if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected
// now compare to highest detected peak // now compare to highest detected peak
i1 = (int)(highPeak + 0.5); i1 = (int)(highPeak + 0.5);
i2 = (int)(peaktmp + 0.5); i2 = (int)(peaktmp + 0.5);
if (data[i2] >= 0.4*data[i1]) if (data[i2] >= 0.4*data[i1])
{ {
// The harmonic is at least half as high primary peak, // The harmonic is at least half as high primary peak,
// thus use the harmonic peak instead // thus use the harmonic peak instead
peak = peaktmp; peak = peaktmp;
} }
} }
return peak; return peak;
} }

View File

@ -1,90 +1,90 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// The routine detects highest value on an array of values and calculates the /// 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. /// precise peak location as a mass-center of the 'hump' around the peak value.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _PeakFinder_H_ #ifndef _PeakFinder_H_
#define _PeakFinder_H_ #define _PeakFinder_H_
namespace soundtouch namespace soundtouch
{ {
class PeakFinder class PeakFinder
{ {
protected: protected:
/// Min, max allowed peak positions within the data vector /// Min, max allowed peak positions within the data vector
int minPos, maxPos; int minPos, maxPos;
/// Calculates the mass center between given vector items. /// Calculates the mass center between given vector items.
double calcMassCenter(const float *data, ///< Data vector. double calcMassCenter(const float *data, ///< Data vector.
int firstPos, ///< Index of first vector item belonging to the peak. int firstPos, ///< Index of first vector item belonging to the peak.
int lastPos ///< Index of last vector item belonging to the peak. int lastPos ///< Index of last vector item belonging to the peak.
) const; ) const;
/// Finds the data vector index where the monotoniously decreasing signal crosses the /// Finds the data vector index where the monotoniously decreasing signal crosses the
/// given level. /// given level.
int findCrossingLevel(const float *data, ///< Data vector. int findCrossingLevel(const float *data, ///< Data vector.
float level, ///< Goal crossing level. float level, ///< Goal crossing level.
int peakpos, ///< Peak position index within the data vector. int peakpos, ///< Peak position index within the data vector.
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const; ) const;
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
int findTop(const float *data, int peakpos) const; int findTop(const float *data, int peakpos) const;
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
/// or left-hand side of the given peak position. /// or left-hand side of the given peak position.
int findGround(const float *data, /// Data vector. int findGround(const float *data, /// Data vector.
int peakpos, /// Peak position index within the data vector. int peakpos, /// Peak position index within the data vector.
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const; ) const;
/// get exact center of peak near given position by calculating local mass of center /// get exact center of peak near given position by calculating local mass of center
double getPeakCenter(const float *data, int peakpos) const; double getPeakCenter(const float *data, int peakpos) const;
public: public:
/// Constructor. /// Constructor.
PeakFinder(); PeakFinder();
/// Detect exact peak position of the data vector by finding the largest peak 'hump' /// Detect exact peak position of the data vector by finding the largest peak 'hump'
/// and calculating the mass-center location of the peak hump. /// and calculating the mass-center location of the peak hump.
/// ///
/// \return The location of the largest base harmonic 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 double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has
/// to be at least 'maxPos' items long. /// to be at least 'maxPos' items long.
int minPos, ///< Min allowed peak location within the vector data. int minPos, ///< Min allowed peak location within the vector data.
int maxPos ///< Max allowed peak location within the vector data. int maxPos ///< Max allowed peak location within the vector data.
); );
}; };
} }
#endif // _PeakFinder_H_ #endif // _PeakFinder_H_

View File

@ -1,313 +1,313 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample rate transposer. Changes sample rate by using linear interpolation /// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti- /// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application) /// alias filtering should be quite adequate for this application)
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <memory.h> #include <memory.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "RateTransposer.h" #include "RateTransposer.h"
#include "InterpolateLinear.h" #include "InterpolateLinear.h"
#include "InterpolateCubic.h" #include "InterpolateCubic.h"
#include "InterpolateShannon.h" #include "InterpolateShannon.h"
#include "AAFilter.h" #include "AAFilter.h"
using namespace soundtouch; using namespace soundtouch;
// Define default interpolation algorithm here // Define default interpolation algorithm here
TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC; TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
// Constructor // Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{ {
bUseAAFilter = bUseAAFilter =
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
true; true;
#else #else
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
false; false;
#endif #endif
// Instantiates the anti-alias filter // Instantiates the anti-alias filter
pAAFilter = new AAFilter(64); pAAFilter = new AAFilter(64);
pTransposer = TransposerBase::newInstance(); pTransposer = TransposerBase::newInstance();
clear(); clear();
} }
RateTransposer::~RateTransposer() RateTransposer::~RateTransposer()
{ {
delete pAAFilter; delete pAAFilter;
delete pTransposer; delete pTransposer;
} }
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void RateTransposer::enableAAFilter(bool newMode) void RateTransposer::enableAAFilter(bool newMode)
{ {
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
bUseAAFilter = newMode; bUseAAFilter = newMode;
clear(); clear();
#endif #endif
} }
/// Returns nonzero if anti-alias filter is enabled. /// Returns nonzero if anti-alias filter is enabled.
bool RateTransposer::isAAFilterEnabled() const bool RateTransposer::isAAFilterEnabled() const
{ {
return bUseAAFilter; return bUseAAFilter;
} }
AAFilter *RateTransposer::getAAFilter() AAFilter *RateTransposer::getAAFilter()
{ {
return pAAFilter; return pAAFilter;
} }
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates. // iRate, larger faster iRates.
void RateTransposer::setRate(double newRate) void RateTransposer::setRate(double newRate)
{ {
double fCutoff; double fCutoff;
pTransposer->setRate(newRate); pTransposer->setRate(newRate);
// design a new anti-alias filter // design a new anti-alias filter
if (newRate > 1.0) if (newRate > 1.0)
{ {
fCutoff = 0.5 / newRate; fCutoff = 0.5 / newRate;
} }
else else
{ {
fCutoff = 0.5 * newRate; fCutoff = 0.5 * newRate;
} }
pAAFilter->setCutoffFreq(fCutoff); pAAFilter->setCutoffFreq(fCutoff);
} }
// Adds 'nSamples' pcs of samples from the 'samples' memory position into // Adds 'nSamples' pcs of samples from the 'samples' memory position into
// the input of the object. // the input of the object.
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples) void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{ {
processSamples(samples, nSamples); processSamples(samples, nSamples);
} }
// Transposes sample rate by applying anti-alias filter to prevent folding. // Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "dest" buffer. // 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 maximum amount of samples that can be returned at a time is set by
// the 'set_returnBuffer_size' function. // the 'set_returnBuffer_size' function.
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
{ {
if (nSamples == 0) return; if (nSamples == 0) return;
// Store samples to input buffer // Store samples to input buffer
inputBuffer.putSamples(src, nSamples); inputBuffer.putSamples(src, nSamples);
// If anti-alias filter is turned off, simply transpose without applying // If anti-alias filter is turned off, simply transpose without applying
// the filter // the filter
if (bUseAAFilter == false) if (bUseAAFilter == false)
{ {
(void)pTransposer->transpose(outputBuffer, inputBuffer); (void)pTransposer->transpose(outputBuffer, inputBuffer);
return; return;
} }
assert(pAAFilter); assert(pAAFilter);
// Transpose with anti-alias filter // Transpose with anti-alias filter
if (pTransposer->rate < 1.0f) if (pTransposer->rate < 1.0f)
{ {
// If the parameter 'Rate' value is smaller than 1, first transpose // If the parameter 'Rate' value is smaller than 1, first transpose
// the samples and then apply the anti-alias filter to remove aliasing. // the samples and then apply the anti-alias filter to remove aliasing.
// Transpose the samples, store the result to end of "midBuffer" // Transpose the samples, store the result to end of "midBuffer"
pTransposer->transpose(midBuffer, inputBuffer); pTransposer->transpose(midBuffer, inputBuffer);
// Apply the anti-alias filter for transposed samples in midBuffer // Apply the anti-alias filter for transposed samples in midBuffer
pAAFilter->evaluate(outputBuffer, midBuffer); pAAFilter->evaluate(outputBuffer, midBuffer);
} }
else else
{ {
// If the parameter 'Rate' value is larger than 1, first apply the // If the parameter 'Rate' value is larger than 1, first apply the
// anti-alias filter to remove high frequencies (prevent them from folding // anti-alias filter to remove high frequencies (prevent them from folding
// over the lover frequencies), then transpose. // over the lover frequencies), then transpose.
// Apply the anti-alias filter for samples in inputBuffer // Apply the anti-alias filter for samples in inputBuffer
pAAFilter->evaluate(midBuffer, inputBuffer); pAAFilter->evaluate(midBuffer, inputBuffer);
// Transpose the AA-filtered samples in "midBuffer" // Transpose the AA-filtered samples in "midBuffer"
pTransposer->transpose(outputBuffer, midBuffer); pTransposer->transpose(outputBuffer, midBuffer);
} }
} }
// Sets the number of channels, 1 = mono, 2 = stereo // Sets the number of channels, 1 = mono, 2 = stereo
void RateTransposer::setChannels(int nChannels) void RateTransposer::setChannels(int nChannels)
{ {
if (!verifyNumberOfChannels(nChannels) || if (!verifyNumberOfChannels(nChannels) ||
(pTransposer->numChannels == nChannels)) return; (pTransposer->numChannels == nChannels)) return;
pTransposer->setChannels(nChannels); pTransposer->setChannels(nChannels);
inputBuffer.setChannels(nChannels); inputBuffer.setChannels(nChannels);
midBuffer.setChannels(nChannels); midBuffer.setChannels(nChannels);
outputBuffer.setChannels(nChannels); outputBuffer.setChannels(nChannels);
} }
// Clears all the samples in the object // Clears all the samples in the object
void RateTransposer::clear() void RateTransposer::clear()
{ {
outputBuffer.clear(); outputBuffer.clear();
midBuffer.clear(); midBuffer.clear();
inputBuffer.clear(); inputBuffer.clear();
pTransposer->resetRegisters(); pTransposer->resetRegisters();
// prefill buffer to avoid losing first samples at beginning of stream // prefill buffer to avoid losing first samples at beginning of stream
int prefill = getLatency(); int prefill = getLatency();
inputBuffer.addSilent(prefill); inputBuffer.addSilent(prefill);
} }
// Returns nonzero if there aren't any samples available for outputting. // Returns nonzero if there aren't any samples available for outputting.
int RateTransposer::isEmpty() const int RateTransposer::isEmpty() const
{ {
int res; int res;
res = FIFOProcessor::isEmpty(); res = FIFOProcessor::isEmpty();
if (res == 0) return 0; if (res == 0) return 0;
return inputBuffer.isEmpty(); return inputBuffer.isEmpty();
} }
/// Return approximate initial input-output latency /// Return approximate initial input-output latency
int RateTransposer::getLatency() const int RateTransposer::getLatency() const
{ {
return pTransposer->getLatency() + return pTransposer->getLatency() +
((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0); ((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// TransposerBase - Base class for interpolation // TransposerBase - Base class for interpolation
// //
// static function to set interpolation algorithm // static function to set interpolation algorithm
void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a) void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
{ {
TransposerBase::algorithm = a; TransposerBase::algorithm = a;
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer // Returns the number of samples returned in the "dest" buffer
int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{ {
int numSrcSamples = src.numSamples(); int numSrcSamples = src.numSamples();
int sizeDemand = (int)((double)numSrcSamples / rate) + 8; int sizeDemand = (int)((double)numSrcSamples / rate) + 8;
int numOutput; int numOutput;
SAMPLETYPE *psrc = src.ptrBegin(); SAMPLETYPE *psrc = src.ptrBegin();
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand); SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
#ifndef USE_MULTICH_ALWAYS #ifndef USE_MULTICH_ALWAYS
if (numChannels == 1) if (numChannels == 1)
{ {
numOutput = transposeMono(pdest, psrc, numSrcSamples); numOutput = transposeMono(pdest, psrc, numSrcSamples);
} }
else if (numChannels == 2) else if (numChannels == 2)
{ {
numOutput = transposeStereo(pdest, psrc, numSrcSamples); numOutput = transposeStereo(pdest, psrc, numSrcSamples);
} }
else else
#endif // USE_MULTICH_ALWAYS #endif // USE_MULTICH_ALWAYS
{ {
assert(numChannels > 0); assert(numChannels > 0);
numOutput = transposeMulti(pdest, psrc, numSrcSamples); numOutput = transposeMulti(pdest, psrc, numSrcSamples);
} }
dest.putSamples(numOutput); dest.putSamples(numOutput);
src.receiveSamples(numSrcSamples); src.receiveSamples(numSrcSamples);
return numOutput; return numOutput;
} }
TransposerBase::TransposerBase() TransposerBase::TransposerBase()
{ {
numChannels = 0; numChannels = 0;
rate = 1.0f; rate = 1.0f;
} }
TransposerBase::~TransposerBase() TransposerBase::~TransposerBase()
{ {
} }
void TransposerBase::setChannels(int channels) void TransposerBase::setChannels(int channels)
{ {
numChannels = channels; numChannels = channels;
resetRegisters(); resetRegisters();
} }
void TransposerBase::setRate(double newRate) void TransposerBase::setRate(double newRate)
{ {
rate = newRate; rate = newRate;
} }
// static factory function // static factory function
TransposerBase *TransposerBase::newInstance() TransposerBase *TransposerBase::newInstance()
{ {
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
// Notice: For integer arithmetic support only linear algorithm (due to simplest calculus) // Notice: For integer arithmetic support only linear algorithm (due to simplest calculus)
return ::new InterpolateLinearInteger; return ::new InterpolateLinearInteger;
#else #else
switch (algorithm) switch (algorithm)
{ {
case LINEAR: case LINEAR:
return new InterpolateLinearFloat; return new InterpolateLinearFloat;
case CUBIC: case CUBIC:
return new InterpolateCubic; return new InterpolateCubic;
case SHANNON: case SHANNON:
return new InterpolateShannon; return new InterpolateShannon;
default: default:
assert(false); assert(false);
return nullptr; return nullptr;
} }
#endif #endif
} }

View File

@ -1,164 +1,164 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample rate transposer. Changes sample rate by using linear interpolation /// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti- /// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application). /// alias filtering should be quite adequate for this application).
/// ///
/// Use either of the derived classes of 'RateTransposerInteger' or /// Use either of the derived classes of 'RateTransposerInteger' or
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing /// 'RateTransposerFloat' for corresponding integer/floating point tranposing
/// algorithm implementation. /// algorithm implementation.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef RateTransposer_H #ifndef RateTransposer_H
#define RateTransposer_H #define RateTransposer_H
#include <stddef.h> #include <stddef.h>
#include "AAFilter.h" #include "AAFilter.h"
#include "FIFOSamplePipe.h" #include "FIFOSamplePipe.h"
#include "FIFOSampleBuffer.h" #include "FIFOSampleBuffer.h"
#include "STTypes.h" #include "STTypes.h"
namespace soundtouch namespace soundtouch
{ {
/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc) /// Abstract base class for transposer implementations (linear, advanced vs integer, float etc)
class TransposerBase class TransposerBase
{ {
public: public:
enum ALGORITHM { enum ALGORITHM {
LINEAR = 0, LINEAR = 0,
CUBIC, CUBIC,
SHANNON SHANNON
}; };
protected: protected:
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
virtual int transposeMulti(SAMPLETYPE *dest, virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
static ALGORITHM algorithm; static ALGORITHM algorithm;
public: public:
double rate; double rate;
int numChannels; int numChannels;
TransposerBase(); TransposerBase();
virtual ~TransposerBase(); virtual ~TransposerBase();
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src); virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
virtual void setRate(double newRate); virtual void setRate(double newRate);
virtual void setChannels(int channels); virtual void setChannels(int channels);
virtual int getLatency() const = 0; virtual int getLatency() const = 0;
virtual void resetRegisters() = 0; virtual void resetRegisters() = 0;
// static factory function // static factory function
static TransposerBase *newInstance(); static TransposerBase *newInstance();
// static function to set interpolation algorithm // static function to set interpolation algorithm
static void setAlgorithm(ALGORITHM a); static void setAlgorithm(ALGORITHM a);
}; };
/// A common linear samplerate transposer class. /// A common linear samplerate transposer class.
/// ///
class RateTransposer : public FIFOProcessor class RateTransposer : public FIFOProcessor
{ {
protected: protected:
/// Anti-alias filter object /// Anti-alias filter object
AAFilter *pAAFilter; AAFilter *pAAFilter;
TransposerBase *pTransposer; TransposerBase *pTransposer;
/// Buffer for collecting samples to feed the anti-alias filter between /// Buffer for collecting samples to feed the anti-alias filter between
/// two batches /// two batches
FIFOSampleBuffer inputBuffer; FIFOSampleBuffer inputBuffer;
/// Buffer for keeping samples between transposing & anti-alias filter /// Buffer for keeping samples between transposing & anti-alias filter
FIFOSampleBuffer midBuffer; FIFOSampleBuffer midBuffer;
/// Output sample buffer /// Output sample buffer
FIFOSampleBuffer outputBuffer; FIFOSampleBuffer outputBuffer;
bool bUseAAFilter; bool bUseAAFilter;
/// Transposes sample rate by applying anti-alias filter to prevent folding. /// Transposes sample rate by applying anti-alias filter to prevent folding.
/// Returns amount of samples returned in the "dest" buffer. /// 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 maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function. /// the 'set_returnBuffer_size' function.
void processSamples(const SAMPLETYPE *src, void processSamples(const SAMPLETYPE *src,
uint numSamples); uint numSamples);
public: public:
RateTransposer(); RateTransposer();
virtual ~RateTransposer() override; virtual ~RateTransposer() override;
/// Returns the output buffer object /// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; }; FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Return anti-alias filter object /// Return anti-alias filter object
AAFilter *getAAFilter(); AAFilter *getAAFilter();
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void enableAAFilter(bool newMode); void enableAAFilter(bool newMode);
/// Returns nonzero if anti-alias filter is enabled. /// Returns nonzero if anti-alias filter is enabled.
bool isAAFilterEnabled() const; bool isAAFilterEnabled() const;
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates. /// rate, larger faster rates.
virtual void setRate(double newRate); virtual void setRate(double newRate);
/// Sets the number of channels, 1 = mono, 2 = stereo /// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int channels); void setChannels(int channels);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object. /// the input of the object.
void putSamples(const SAMPLETYPE *samples, uint numSamples) override; void putSamples(const SAMPLETYPE *samples, uint numSamples) override;
/// Clears all the samples in the object /// Clears all the samples in the object
void clear() override; void clear() override;
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
int isEmpty() const override; int isEmpty() const override;
/// Return approximate initial input-output latency /// Return approximate initial input-output latency
int getLatency() const; int getLatency() const;
}; };
} }
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,279 +1,279 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method /// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks. /// with several performance-increasing tweaks.
/// ///
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files /// Note : MMX/SSE optimized functions reside in separate, platform-specific files
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp' /// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef TDStretch_H #ifndef TDStretch_H
#define TDStretch_H #define TDStretch_H
#include <stddef.h> #include <stddef.h>
#include "STTypes.h" #include "STTypes.h"
#include "RateTransposer.h" #include "RateTransposer.h"
#include "FIFOSamplePipe.h" #include "FIFOSamplePipe.h"
namespace soundtouch namespace soundtouch
{ {
/// Default values for sound processing parameters: /// Default values for sound processing parameters:
/// Notice that the default parameters are tuned for contemporary popular music /// Notice that the default parameters are tuned for contemporary popular music
/// processing. For speech processing applications these parameters suit better: /// processing. For speech processing applications these parameters suit better:
/// #define DEFAULT_SEQUENCE_MS 40 /// #define DEFAULT_SEQUENCE_MS 40
/// #define DEFAULT_SEEKWINDOW_MS 15 /// #define DEFAULT_SEEKWINDOW_MS 15
/// #define DEFAULT_OVERLAP_MS 8 /// #define DEFAULT_OVERLAP_MS 8
/// ///
/// Default length of a single processing sequence, in milliseconds. This determines to how /// 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. /// 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 /// 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 /// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
/// and vice versa. /// and vice versa.
/// ///
/// Increasing this value reduces computational burden & vice versa. /// Increasing this value reduces computational burden & vice versa.
//#define DEFAULT_SEQUENCE_MS 40 //#define DEFAULT_SEQUENCE_MS 40
#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN #define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
/// Giving this value for the sequence length sets automatic parameter value /// Giving this value for the sequence length sets automatic parameter value
/// according to tempo setting (recommended) /// according to tempo setting (recommended)
#define USE_AUTO_SEQUENCE_LEN 0 #define USE_AUTO_SEQUENCE_LEN 0
/// Seeking window default length in milliseconds for algorithm that finds the best possible /// 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 /// overlapping location. This determines from how wide window the algorithm may look for an
/// optimal joining location when mixing the sound sequences back together. /// 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 /// 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 /// 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. /// 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 /// If there's a disturbing artifact that sounds as if a constant frequency was drifting
/// around, try reducing this setting. /// around, try reducing this setting.
/// ///
/// Increasing this value increases computational burden & vice versa. /// Increasing this value increases computational burden & vice versa.
//#define DEFAULT_SEEKWINDOW_MS 15 //#define DEFAULT_SEEKWINDOW_MS 15
#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN #define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
/// Giving this value for the seek window length sets automatic parameter value /// Giving this value for the seek window length sets automatic parameter value
/// according to tempo setting (recommended) /// according to tempo setting (recommended)
#define USE_AUTO_SEEKWINDOW_LEN 0 #define USE_AUTO_SEEKWINDOW_LEN 0
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, /// 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 /// to form a continuous sound stream, this parameter defines over how long period the two
/// consecutive sequences are let to overlap each other. /// consecutive sequences are let to overlap each other.
/// ///
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting /// 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. /// by a large amount, you might wish to try a smaller value on this.
/// ///
/// Increasing this value increases computational burden & vice versa. /// Increasing this value increases computational burden & vice versa.
#define DEFAULT_OVERLAP_MS 8 #define DEFAULT_OVERLAP_MS 8
/// Class that does the time-stretch (tempo change) effect for the processed /// Class that does the time-stretch (tempo change) effect for the processed
/// sound. /// sound.
class TDStretch : public FIFOProcessor class TDStretch : public FIFOProcessor
{ {
protected: protected:
int channels; int channels;
int sampleReq; int sampleReq;
int overlapLength; int overlapLength;
int seekLength; int seekLength;
int seekWindowLength; int seekWindowLength;
int overlapDividerBitsNorm; int overlapDividerBitsNorm;
int overlapDividerBitsPure; int overlapDividerBitsPure;
int slopingDivider; int slopingDivider;
int sampleRate; int sampleRate;
int sequenceMs; int sequenceMs;
int seekWindowMs; int seekWindowMs;
int overlapMs; int overlapMs;
unsigned long maxnorm; unsigned long maxnorm;
float maxnormf; float maxnormf;
double tempo; double tempo;
double nominalSkip; double nominalSkip;
double skipFract; double skipFract;
bool bQuickSeek; bool bQuickSeek;
bool bAutoSeqSetting; bool bAutoSeqSetting;
bool bAutoSeekSetting; bool bAutoSeekSetting;
bool isBeginning; bool isBeginning;
SAMPLETYPE *pMidBuffer; SAMPLETYPE *pMidBuffer;
SAMPLETYPE *pMidBufferUnaligned; SAMPLETYPE *pMidBufferUnaligned;
FIFOSampleBuffer outputBuffer; FIFOSampleBuffer outputBuffer;
FIFOSampleBuffer inputBuffer; FIFOSampleBuffer inputBuffer;
void acceptNewOverlapLength(int newOverlapLength); void acceptNewOverlapLength(int newOverlapLength);
virtual void clearCrossCorrState(); virtual void clearCrossCorrState();
void calculateOverlapLength(int overlapMs); void calculateOverlapLength(int overlapMs);
virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
virtual double calcCrossCorrAccumulate(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 seekBestOverlapPositionFull(const SAMPLETYPE *refPos);
virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);
virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos); virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos);
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const; virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const;
void clearMidBuffer(); void clearMidBuffer();
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
void calcSeqParameters(); void calcSeqParameters();
void adaptNormalizer(); void adaptNormalizer();
/// Changes the tempo of the given sound samples. /// Changes the tempo of the given sound samples.
/// Returns amount of samples returned in the "output" buffer. /// 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 maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function. /// the 'set_returnBuffer_size' function.
void processSamples(); void processSamples();
public: public:
TDStretch(); TDStretch();
virtual ~TDStretch() override; virtual ~TDStretch() override;
/// Operator 'new' is overloaded so that it automatically creates a suitable instance /// 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. /// depending on if we've a MMX/SSE/etc-capable CPU available or not.
static void *operator new(size_t s); static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class. /// 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 /// This function automatically chooses a correct feature set depending on if the CPU
/// supports MMX/SSE/etc extensions. /// supports MMX/SSE/etc extensions.
static TDStretch *newInstance(); static TDStretch *newInstance();
/// Returns the output buffer object /// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; }; FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the input buffer object /// Returns the input buffer object
FIFOSamplePipe *getInput() { return &inputBuffer; }; FIFOSamplePipe *getInput() { return &inputBuffer; };
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
/// tempo, larger faster tempo. /// tempo, larger faster tempo.
void setTempo(double newTempo); void setTempo(double newTempo);
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
virtual void clear() override; virtual void clear() override;
/// Clears the input buffer /// Clears the input buffer
void clearInput(); void clearInput();
/// Sets the number of channels, 1 = mono, 2 = stereo /// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int numChannels); void setChannels(int numChannels);
/// Enables/disables the quick position seeking algorithm. Zero to disable, /// Enables/disables the quick position seeking algorithm. Zero to disable,
/// nonzero to enable /// nonzero to enable
void enableQuickSeek(bool enable); void enableQuickSeek(bool enable);
/// Returns nonzero if the quick seeking algorithm is enabled. /// Returns nonzero if the quick seeking algorithm is enabled.
bool isQuickSeekEnabled() const; bool isQuickSeekEnabled() const;
/// Sets routine control parameters. These control are certain time constants /// Sets routine control parameters. These control are certain time constants
/// defining how the sound is stretched to the desired duration. /// defining how the sound is stretched to the desired duration.
// //
/// 'sampleRate' = sample rate of the sound /// 'sampleRate' = sample rate of the sound
/// 'sequenceMS' = one processing sequence length in milliseconds /// 'sequenceMS' = one processing sequence length in milliseconds
/// 'seekwindowMS' = seeking window length for scanning the best overlapping /// 'seekwindowMS' = seeking window length for scanning the best overlapping
/// position /// position
/// 'overlapMS' = overlapping length /// 'overlapMS' = overlapping length
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz) void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
int sequenceMS = -1, ///< Single processing sequence length (ms) int sequenceMS = -1, ///< Single processing sequence length (ms)
int seekwindowMS = -1, ///< Offset seeking window length (ms) int seekwindowMS = -1, ///< Offset seeking window length (ms)
int overlapMS = -1 ///< Sequence overlapping length (ms) int overlapMS = -1 ///< Sequence overlapping length (ms)
); );
/// Get routine control parameters, see setParameters() function. /// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be nullptr, in such case corresponding parameter /// Any of the parameters to this function can be nullptr, in such case corresponding parameter
/// value isn't returned. /// value isn't returned.
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const; void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into /// Adds 'numsamples' pcs of samples from the 'samples' memory position into
/// the input of the object. /// the input of the object.
virtual void putSamples( virtual void putSamples(
const SAMPLETYPE *samples, ///< Input sample data const SAMPLETYPE *samples, ///< Input sample data
uint numSamples ///< Number of samples in 'samples' so that one sample uint numSamples ///< Number of samples in 'samples' so that one sample
///< contains both channels if stereo ///< contains both channels if stereo
) override; ) override;
/// return nominal input sample requirement for triggering a processing batch /// return nominal input sample requirement for triggering a processing batch
int getInputSampleReq() const int getInputSampleReq() const
{ {
return (int)(nominalSkip + 0.5); return (int)(nominalSkip + 0.5);
} }
/// return nominal output sample amount when running a processing batch /// return nominal output sample amount when running a processing batch
int getOutputBatchSize() const int getOutputBatchSize() const
{ {
return seekWindowLength - overlapLength; return seekWindowLength - overlapLength;
} }
/// return approximate initial input-output latency /// return approximate initial input-output latency
int getLatency() const int getLatency() const
{ {
return sampleReq; return sampleReq;
} }
}; };
// Implementation-specific class declarations: // Implementation-specific class declarations:
#ifdef SOUNDTOUCH_ALLOW_MMX #ifdef SOUNDTOUCH_ALLOW_MMX
/// Class that implements MMX optimized routines for 16bit integer samples type. /// Class that implements MMX optimized routines for 16bit integer samples type.
class TDStretchMMX : public TDStretch class TDStretchMMX : public TDStretch
{ {
protected: protected:
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) override; double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) override;
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) override; double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) override;
virtual void overlapStereo(short *output, const short *input) const override; virtual void overlapStereo(short *output, const short *input) const override;
virtual void clearCrossCorrState() override; virtual void clearCrossCorrState() override;
}; };
#endif /// SOUNDTOUCH_ALLOW_MMX #endif /// SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE #ifdef SOUNDTOUCH_ALLOW_SSE
/// Class that implements SSE optimized routines for floating point samples type. /// Class that implements SSE optimized routines for floating point samples type.
class TDStretchSSE : public TDStretch class TDStretchSSE : public TDStretch
{ {
protected: protected:
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) override; double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) override;
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) override; double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) override;
}; };
#endif /// SOUNDTOUCH_ALLOW_SSE #endif /// SOUNDTOUCH_ALLOW_SSE
} }
#endif /// TDStretch_H #endif /// TDStretch_H

View File

@ -1,55 +1,55 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A header file for detecting the Intel MMX instructions set extension. /// 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 /// 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 /// routine implementations for x86 Windows, x86 gnu version and non-x86
/// platforms, respectively. /// platforms, respectively.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _CPU_DETECT_H_ #ifndef _CPU_DETECT_H_
#define _CPU_DETECT_H_ #define _CPU_DETECT_H_
#include "STTypes.h" #include "STTypes.h"
#define SUPPORT_MMX 0x0001 #define SUPPORT_MMX 0x0001
#define SUPPORT_3DNOW 0x0002 #define SUPPORT_3DNOW 0x0002
#define SUPPORT_ALTIVEC 0x0004 #define SUPPORT_ALTIVEC 0x0004
#define SUPPORT_SSE 0x0008 #define SUPPORT_SSE 0x0008
#define SUPPORT_SSE2 0x0010 #define SUPPORT_SSE2 0x0010
/// Checks which instruction set extensions are supported by the CPU. /// Checks which instruction set extensions are supported by the CPU.
/// ///
/// \return A bitmask of supported extensions, see SUPPORT_... defines. /// \return A bitmask of supported extensions, see SUPPORT_... defines.
uint detectCPUextensions(void); uint detectCPUextensions(void);
/// Disables given set of instruction extensions. See SUPPORT_... defines. /// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint wDisableMask); void disableExtensions(uint wDisableMask);
#endif // _CPU_DETECT_H_ #endif // _CPU_DETECT_H_

View File

@ -1,130 +1,130 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Generic version of the x86 CPU extension detection routine. /// Generic version of the x86 CPU extension detection routine.
/// ///
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' /// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
/// for the Microsoft compiler version. /// for the Microsoft compiler version.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h" #include "cpu_detect.h"
#include "STTypes.h" #include "STTypes.h"
#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) #if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
#if defined(__GNUC__) && defined(__i386__) #if defined(__GNUC__) && defined(__i386__)
// gcc // gcc
#include "cpuid.h" #include "cpuid.h"
#elif defined(_M_IX86) #elif defined(_M_IX86)
// windows non-gcc // windows non-gcc
#include <intrin.h> #include <intrin.h>
#endif #endif
#define bit_MMX (1 << 23) #define bit_MMX (1 << 23)
#define bit_SSE (1 << 25) #define bit_SSE (1 << 25)
#define bit_SSE2 (1 << 26) #define bit_SSE2 (1 << 26)
#endif #endif
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// processor instructions extension detection routines // processor instructions extension detection routines
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Flag variable indicating whick ISA extensions are disabled (for debugging) // Flag variable indicating whick ISA extensions are disabled (for debugging)
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
// Disables given set of instruction extensions. See SUPPORT_... defines. // Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint dwDisableMask) void disableExtensions(uint dwDisableMask)
{ {
_dwDisabledISA = dwDisableMask; _dwDisabledISA = dwDisableMask;
} }
/// Checks which instruction set extensions are supported by the CPU. /// Checks which instruction set extensions are supported by the CPU.
uint detectCPUextensions(void) uint detectCPUextensions(void)
{ {
/// If building for a 64bit system (no Itanium) and the user wants optimizations. /// If building for a 64bit system (no Itanium) and the user wants optimizations.
/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19. /// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). /// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
#if ((defined(__GNUC__) && defined(__x86_64__)) \ #if ((defined(__GNUC__) && defined(__x86_64__)) \
|| defined(_M_X64)) \ || defined(_M_X64)) \
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
return 0x19 & ~_dwDisabledISA; return 0x19 & ~_dwDisabledISA;
/// If building for a 32bit system and the user wants optimizations. /// If building for a 32bit system and the user wants optimizations.
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). /// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
#elif ((defined(__GNUC__) && defined(__i386__)) \ #elif ((defined(__GNUC__) && defined(__i386__)) \
|| defined(_M_IX86)) \ || defined(_M_IX86)) \
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
if (_dwDisabledISA == 0xffffffff) return 0; if (_dwDisabledISA == 0xffffffff) return 0;
uint res = 0; uint res = 0;
#if defined(__GNUC__) #if defined(__GNUC__)
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support. // 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. 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. // Check if no cpuid support.
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions. if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.
if (edx & bit_MMX) res = res | SUPPORT_MMX; if (edx & bit_MMX) res = res | SUPPORT_MMX;
if (edx & bit_SSE) res = res | SUPPORT_SSE; if (edx & bit_SSE) res = res | SUPPORT_SSE;
if (edx & bit_SSE2) res = res | SUPPORT_SSE2; if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
#else #else
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
// for __cpuid intrinsic support. // for __cpuid intrinsic support.
int reg[4] = {-1}; int reg[4] = {-1};
// Check if no cpuid support. // Check if no cpuid support.
__cpuid(reg,0); __cpuid(reg,0);
if ((unsigned int)reg[0] == 0) return 0; // always disable extensions. if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.
__cpuid(reg,1); __cpuid(reg,1);
if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX; 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_SSE) res = res | SUPPORT_SSE;
if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2; if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;
#endif #endif
return res & ~_dwDisabledISA; return res & ~_dwDisabledISA;
#else #else
/// One of these is true: /// One of these is true:
/// 1) We don't want optimizations. /// 1) We don't want optimizations.
/// 2) Using an unsupported compiler. /// 2) Using an unsupported compiler.
/// 3) Running on a non-x86 platform. /// 3) Running on a non-x86 platform.
return 0; return 0;
#endif #endif
} }

View File

@ -1,396 +1,396 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// MMX optimized routines. All MMX optimized functions have been gathered into /// MMX optimized routines. All MMX optimized functions have been gathered into
/// this single source code file, regardless to their class or original source /// 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 /// code file, in order to ease porting the library to other compiler and
/// processor platforms. /// processor platforms.
/// ///
/// The MMX-optimizations are programmed using MMX compiler intrinsics that /// The MMX-optimizations are programmed using MMX compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets. /// should compile with both toolsets.
/// ///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// 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 /// 6.0 processor pack" update to support compiler intrinsic syntax. The update
/// is available for download at Microsoft Developers Network, see here: /// is available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "STTypes.h" #include "STTypes.h"
#ifdef SOUNDTOUCH_ALLOW_MMX #ifdef SOUNDTOUCH_ALLOW_MMX
// MMX routines available only with integer sample type // MMX routines available only with integer sample type
using namespace soundtouch; using namespace soundtouch;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// implementation of MMX optimized functions of class 'TDStretchMMX' // implementation of MMX optimized functions of class 'TDStretchMMX'
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h" #include "TDStretch.h"
#include <mmintrin.h> #include <mmintrin.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
// Calculates cross correlation of two buffers // Calculates cross correlation of two buffers
double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm) double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm)
{ {
const __m64 *pVec1, *pVec2; const __m64 *pVec1, *pVec2;
__m64 shifter; __m64 shifter;
__m64 accu, normaccu; __m64 accu, normaccu;
long corr, norm; long corr, norm;
int i; int i;
pVec1 = (__m64*)pV1; pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2; pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBitsNorm); shifter = _m_from_int(overlapDividerBitsNorm);
normaccu = accu = _mm_setzero_si64(); normaccu = accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization. // during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
__m64 temp, temp2; __m64 temp, temp2;
// dictionary of instructions: // dictionary of instructions:
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
// _mm_add_pi32 : 2*32bit add // _mm_add_pi32 : 2*32bit add
// _m_psrad : 32bit right-shift // _m_psrad : 32bit right-shift
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), 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)); _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), 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)); _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter));
accu = _mm_add_pi32(accu, temp); accu = _mm_add_pi32(accu, temp);
normaccu = _mm_add_pi32(normaccu, temp2); normaccu = _mm_add_pi32(normaccu, temp2);
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), 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)); _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), 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)); _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter));
accu = _mm_add_pi32(accu, temp); accu = _mm_add_pi32(accu, temp);
normaccu = _mm_add_pi32(normaccu, temp2); normaccu = _mm_add_pi32(normaccu, temp2);
pVec1 += 4; pVec1 += 4;
pVec2 += 4; pVec2 += 4;
} }
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
// and finally store the result into the variable "corr" // and finally store the result into the variable "corr"
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
corr = _m_to_int(accu); corr = _m_to_int(accu);
normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32)); normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));
norm = _m_to_int(normaccu); norm = _m_to_int(normaccu);
// Clear MMS state // Clear MMS state
_m_empty(); _m_empty();
if (norm > (long)maxnorm) if (norm > (long)maxnorm)
{ {
// modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
#pragma omp critical #pragma omp critical
if (norm > (long)maxnorm) if (norm > (long)maxnorm)
{ {
maxnorm = norm; maxnorm = norm;
} }
} }
// Normalize result by dividing by sqrt(norm) - this step is easiest // Normalize result by dividing by sqrt(norm) - this step is easiest
// done using floating point operation // done using floating point operation
dnorm = (double)norm; dnorm = (double)norm;
return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm); return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm);
// Note: Warning about the missing EMMS instruction is harmless // Note: Warning about the missing EMMS instruction is harmless
// as it'll be called elsewhere. // as it'll be called elsewhere.
} }
/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value /// Update cross-correlation by accumulating "norm" coefficient by previously calculated value
double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm) double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm)
{ {
const __m64 *pVec1, *pVec2; const __m64 *pVec1, *pVec2;
__m64 shifter; __m64 shifter;
__m64 accu; __m64 accu;
long corr, lnorm; long corr, lnorm;
int i; int i;
// cancel first normalizer tap from previous round // cancel first normalizer tap from previous round
lnorm = 0; lnorm = 0;
for (i = 1; i <= channels; i ++) for (i = 1; i <= channels; i ++)
{ {
lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm; lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm;
} }
pVec1 = (__m64*)pV1; pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2; pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBitsNorm); shifter = _m_from_int(overlapDividerBitsNorm);
accu = _mm_setzero_si64(); accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization. // during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
__m64 temp; __m64 temp;
// dictionary of instructions: // dictionary of instructions:
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
// _mm_add_pi32 : 2*32bit add // _mm_add_pi32 : 2*32bit add
// _m_psrad : 32bit right-shift // _m_psrad : 32bit right-shift
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), 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)); _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));
accu = _mm_add_pi32(accu, temp); accu = _mm_add_pi32(accu, temp);
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), 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)); _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));
accu = _mm_add_pi32(accu, temp); accu = _mm_add_pi32(accu, temp);
pVec1 += 4; pVec1 += 4;
pVec2 += 4; pVec2 += 4;
} }
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
// and finally store the result into the variable "corr" // and finally store the result into the variable "corr"
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
corr = _m_to_int(accu); corr = _m_to_int(accu);
// Clear MMS state // Clear MMS state
_m_empty(); _m_empty();
// update normalizer with last samples of this round // update normalizer with last samples of this round
pV1 = (short *)pVec1; pV1 = (short *)pVec1;
for (int j = 1; j <= channels; j ++) for (int j = 1; j <= channels; j ++)
{ {
lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm; lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm;
} }
dnorm += (double)lnorm; dnorm += (double)lnorm;
if (lnorm > (long)maxnorm) if (lnorm > (long)maxnorm)
{ {
maxnorm = lnorm; maxnorm = lnorm;
} }
// Normalize result by dividing by sqrt(norm) - this step is easiest // Normalize result by dividing by sqrt(norm) - this step is easiest
// done using floating point operation // done using floating point operation
return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm); return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm);
} }
void TDStretchMMX::clearCrossCorrState() void TDStretchMMX::clearCrossCorrState()
{ {
// Clear MMS state // Clear MMS state
_m_empty(); _m_empty();
//_asm EMMS; //_asm EMMS;
} }
// MMX-optimized version of the function overlapStereo // MMX-optimized version of the function overlapStereo
void TDStretchMMX::overlapStereo(short *output, const short *input) const void TDStretchMMX::overlapStereo(short *output, const short *input) const
{ {
const __m64 *pVinput, *pVMidBuf; const __m64 *pVinput, *pVMidBuf;
__m64 *pVdest; __m64 *pVdest;
__m64 mix1, mix2, adder, shifter; __m64 mix1, mix2, adder, shifter;
int i; int i;
pVinput = (const __m64*)input; pVinput = (const __m64*)input;
pVMidBuf = (const __m64*)pMidBuffer; pVMidBuf = (const __m64*)pMidBuffer;
pVdest = (__m64*)output; pVdest = (__m64*)output;
// mix1 = mixer values for 1st stereo sample // mix1 = mixer values for 1st stereo sample
// mix1 = mixer values for 2nd stereo sample // mix1 = mixer values for 2nd stereo sample
// adder = adder for updating mixer values after each round // adder = adder for updating mixer values after each round
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
adder = _mm_set_pi16(1, -1, 1, -1); adder = _mm_set_pi16(1, -1, 1, -1);
mix2 = _mm_add_pi16(mix1, adder); mix2 = _mm_add_pi16(mix1, adder);
adder = _mm_add_pi16(adder, adder); adder = _mm_add_pi16(adder, adder);
// Overlaplength-division by shifter. "+1" is to account for "-1" deduced in // Overlaplength-division by shifter. "+1" is to account for "-1" deduced in
// overlapDividerBits calculation earlier. // overlapDividerBits calculation earlier.
shifter = _m_from_int(overlapDividerBitsPure + 1); shifter = _m_from_int(overlapDividerBitsPure + 1);
for (i = 0; i < overlapLength / 4; i ++) for (i = 0; i < overlapLength / 4; i ++)
{ {
__m64 temp1, temp2; __m64 temp1, temp2;
// load & shuffle data so that input & mixbuffer data samples are paired // load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
// temp = (temp .* mix) >> shifter // temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder // update mix += adder
mix1 = _mm_add_pi16(mix1, adder); mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder); mix2 = _mm_add_pi16(mix2, adder);
// --- second round begins here --- // --- second round begins here ---
// load & shuffle data so that input & mixbuffer data samples are paired // load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
// temp = (temp .* mix) >> shifter // temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder // update mix += adder
mix1 = _mm_add_pi16(mix1, adder); mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder); mix2 = _mm_add_pi16(mix2, adder);
pVinput += 2; pVinput += 2;
pVMidBuf += 2; pVMidBuf += 2;
pVdest += 2; pVdest += 2;
} }
_m_empty(); // clear MMS state _m_empty(); // clear MMS state
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// implementation of MMX optimized functions of class 'FIRFilter' // implementation of MMX optimized functions of class 'FIRFilter'
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h" #include "FIRFilter.h"
FIRFilterMMX::FIRFilterMMX() : FIRFilter() FIRFilterMMX::FIRFilterMMX() : FIRFilter()
{ {
filterCoeffsAlign = nullptr; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = nullptr; filterCoeffsUnalign = nullptr;
} }
FIRFilterMMX::~FIRFilterMMX() FIRFilterMMX::~FIRFilterMMX()
{ {
delete[] filterCoeffsUnalign; delete[] filterCoeffsUnalign;
} }
// (overloaded) Calculates filter coefficients for MMX routine // (overloaded) Calculates filter coefficients for MMX routine
void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
{ {
uint i; uint i;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Ensure that filter coeffs array is aligned to 16-byte boundary // Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign; delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new short[2 * newLength + 8]; filterCoeffsUnalign = new short[2 * newLength + 8];
filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
// rearrange the filter coefficients for mmx routines // rearrange the filter coefficients for mmx routines
for (i = 0;i < length; i += 4) for (i = 0;i < length; i += 4)
{ {
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
} }
} }
// mmx-optimized version of the filter routine for stereo sound // mmx-optimized version of the filter routine for stereo sound
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
{ {
// Create stack copies of the needed member variables for asm routines : // Create stack copies of the needed member variables for asm routines :
uint i, j; uint i, j;
__m64 *pVdest = (__m64*)dest; __m64 *pVdest = (__m64*)dest;
if (length < 2) return 0; if (length < 2) return 0;
for (i = 0; i < (numSamples - length) / 2; i ++) for (i = 0; i < (numSamples - length) / 2; i ++)
{ {
__m64 accu1; __m64 accu1;
__m64 accu2; __m64 accu2;
const __m64 *pVsrc = (const __m64*)src; const __m64 *pVsrc = (const __m64*)src;
const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
accu1 = accu2 = _mm_setzero_si64(); accu1 = accu2 = _mm_setzero_si64();
for (j = 0; j < lengthDiv8 * 2; j ++) for (j = 0; j < lengthDiv8 * 2; j ++)
{ {
__m64 temp1, temp2; __m64 temp1, temp2;
temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 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(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 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 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(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 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 // accu1 += l2*f2+l0*f0 r2*f2+r0*f0
// += l3*f3+l1*f1 r3*f3+r1*f1 // += l3*f3+l1*f1 r3*f3+r1*f1
// accu2 += l3*f2+l1*f0 r3*f2+r1*f0 // accu2 += l3*f2+l1*f0 r3*f2+r1*f0
// l4*f3+l2*f1 r4*f3+r2*f1 // l4*f3+l2*f1 r4*f3+r2*f1
pVfilter += 2; pVfilter += 2;
pVsrc += 2; pVsrc += 2;
} }
// accu >>= resultDivFactor // accu >>= resultDivFactor
accu1 = _mm_srai_pi32(accu1, resultDivFactor); accu1 = _mm_srai_pi32(accu1, resultDivFactor);
accu2 = _mm_srai_pi32(accu2, resultDivFactor); accu2 = _mm_srai_pi32(accu2, resultDivFactor);
// pack 2*2*32bits => 4*16 bits // pack 2*2*32bits => 4*16 bits
pVdest[0] = _mm_packs_pi32(accu1, accu2); pVdest[0] = _mm_packs_pi32(accu1, accu2);
src += 4; src += 4;
pVdest ++; pVdest ++;
} }
_m_empty(); // clear emms state _m_empty(); // clear emms state
return (numSamples & 0xfffffffe) - length; return (numSamples & 0xfffffffe) - length;
} }
#else #else
// workaround to not complain about empty module // workaround to not complain about empty module
bool _dontcomplain_mmx_empty; bool _dontcomplain_mmx_empty;
#endif // SOUNDTOUCH_ALLOW_MMX #endif // SOUNDTOUCH_ALLOW_MMX

View File

@ -1,365 +1,365 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE /// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
/// optimized functions have been gathered into this single source /// optimized functions have been gathered into this single source
/// code file, regardless to their class or original source code file, in order /// code file, regardless to their class or original source code file, in order
/// to ease porting the library to other compiler and processor platforms. /// to ease porting the library to other compiler and processor platforms.
/// ///
/// The SSE-optimizations are programmed using SSE compiler intrinsics that /// The SSE-optimizations are programmed using SSE compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets. /// should compile with both toolsets.
/// ///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// 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 /// 6.0 processor pack" update to support SSE instruction set. The update is
/// available for download at Microsoft Developers Network, see here: /// available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
/// ///
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and /// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
/// perform a search with keywords "processor pack". /// perform a search with keywords "processor pack".
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h" #include "cpu_detect.h"
#include "STTypes.h" #include "STTypes.h"
using namespace soundtouch; using namespace soundtouch;
#ifdef SOUNDTOUCH_ALLOW_SSE #ifdef SOUNDTOUCH_ALLOW_SSE
// SSE routines available only with float sample type // SSE routines available only with float sample type
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// implementation of SSE optimized functions of class 'TDStretchSSE' // implementation of SSE optimized functions of class 'TDStretchSSE'
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h" #include "TDStretch.h"
#include <xmmintrin.h> #include <xmmintrin.h>
#include <math.h> #include <math.h>
// Calculates cross correlation of two buffers // Calculates cross correlation of two buffers
double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm) double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm)
{ {
int i; int i;
const float *pVec1; const float *pVec1;
const __m128 *pVec2; const __m128 *pVec2;
__m128 vSum, vNorm; __m128 vSum, vNorm;
// Note. It means a major slow-down if the routine needs to tolerate // 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 __m128 memory accesses. It's way faster if we can skip
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. // 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 // This can mean up to ~ 10-fold difference (incl. part of which is
// due to skipping every second round for stereo sound though). // due to skipping every second round for stereo sound though).
// //
// Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
// for choosing if this little cheating is allowed. // for choosing if this little cheating is allowed.
#ifdef ST_SIMD_AVOID_UNALIGNED #ifdef ST_SIMD_AVOID_UNALIGNED
// Little cheating allowed, return valid correlation only for // Little cheating allowed, return valid correlation only for
// aligned locations, meaning every second round for stereo sound. // aligned locations, meaning every second round for stereo sound.
#define _MM_LOAD _mm_load_ps #define _MM_LOAD _mm_load_ps
if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations
#else #else
// No cheating allowed, use unaligned load & take the resulting // No cheating allowed, use unaligned load & take the resulting
// performance hit. // performance hit.
#define _MM_LOAD _mm_loadu_ps #define _MM_LOAD _mm_loadu_ps
#endif #endif
// ensure overlapLength is divisible by 8 // ensure overlapLength is divisible by 8
assert((overlapLength % 8) == 0); assert((overlapLength % 8) == 0);
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
// Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
pVec1 = (const float*)pV1; pVec1 = (const float*)pV1;
pVec2 = (const __m128*)pV2; pVec2 = (const __m128*)pV2;
vSum = vNorm = _mm_setzero_ps(); vSum = vNorm = _mm_setzero_ps();
// Unroll the loop by factor of 4 * 4 operations. Use same routine for // 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. // stereo & mono, for mono it just means twice the amount of unrolling.
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
__m128 vTemp; __m128 vTemp;
// vSum += pV1[0..3] * pV2[0..3] // vSum += pV1[0..3] * pV2[0..3]
vTemp = _MM_LOAD(pVec1); vTemp = _MM_LOAD(pVec1);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0])); vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[4..7] * pV2[4..7] // vSum += pV1[4..7] * pV2[4..7]
vTemp = _MM_LOAD(pVec1 + 4); vTemp = _MM_LOAD(pVec1 + 4);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1])); vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[8..11] * pV2[8..11] // vSum += pV1[8..11] * pV2[8..11]
vTemp = _MM_LOAD(pVec1 + 8); vTemp = _MM_LOAD(pVec1 + 8);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2])); vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[12..15] * pV2[12..15] // vSum += pV1[12..15] * pV2[12..15]
vTemp = _MM_LOAD(pVec1 + 12); vTemp = _MM_LOAD(pVec1 + 12);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3])); vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
pVec1 += 16; pVec1 += 16;
pVec2 += 4; pVec2 += 4;
} }
// return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
float *pvNorm = (float*)&vNorm; float *pvNorm = (float*)&vNorm;
float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);
anorm = norm; anorm = norm;
float *pvSum = (float*)&vSum; float *pvSum = (float*)&vSum;
return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm); 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: /* This is approximately corresponding routine in C-language yet without normalization:
double corr, norm; double corr, norm;
uint i; uint i;
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
corr = norm = 0.0; corr = norm = 0.0;
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
corr += pV1[0] * pV2[0] + corr += pV1[0] * pV2[0] +
pV1[1] * pV2[1] + pV1[1] * pV2[1] +
pV1[2] * pV2[2] + pV1[2] * pV2[2] +
pV1[3] * pV2[3] + pV1[3] * pV2[3] +
pV1[4] * pV2[4] + pV1[4] * pV2[4] +
pV1[5] * pV2[5] + pV1[5] * pV2[5] +
pV1[6] * pV2[6] + pV1[6] * pV2[6] +
pV1[7] * pV2[7] + pV1[7] * pV2[7] +
pV1[8] * pV2[8] + pV1[8] * pV2[8] +
pV1[9] * pV2[9] + pV1[9] * pV2[9] +
pV1[10] * pV2[10] + pV1[10] * pV2[10] +
pV1[11] * pV2[11] + pV1[11] * pV2[11] +
pV1[12] * pV2[12] + pV1[12] * pV2[12] +
pV1[13] * pV2[13] + pV1[13] * pV2[13] +
pV1[14] * pV2[14] + pV1[14] * pV2[14] +
pV1[15] * pV2[15]; pV1[15] * pV2[15];
for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j]; for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];
pV1 += 16; pV1 += 16;
pV2 += 16; pV2 += 16;
} }
return corr / sqrt(norm); return corr / sqrt(norm);
*/ */
} }
double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm) double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm)
{ {
// call usual calcCrossCorr function because SSE does not show big benefit of // call usual calcCrossCorr function because SSE does not show big benefit of
// accumulating "norm" value, and also the "norm" rolling algorithm would get // accumulating "norm" value, and also the "norm" rolling algorithm would get
// complicated due to SSE-specific alignment-vs-nonexact correlation rules. // complicated due to SSE-specific alignment-vs-nonexact correlation rules.
return calcCrossCorr(pV1, pV2, norm); return calcCrossCorr(pV1, pV2, norm);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// implementation of SSE optimized functions of class 'FIRFilter' // implementation of SSE optimized functions of class 'FIRFilter'
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h" #include "FIRFilter.h"
FIRFilterSSE::FIRFilterSSE() : FIRFilter() FIRFilterSSE::FIRFilterSSE() : FIRFilter()
{ {
filterCoeffsAlign = nullptr; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = nullptr; filterCoeffsUnalign = nullptr;
} }
FIRFilterSSE::~FIRFilterSSE() FIRFilterSSE::~FIRFilterSSE()
{ {
delete[] filterCoeffsUnalign; delete[] filterCoeffsUnalign;
filterCoeffsAlign = nullptr; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = nullptr; filterCoeffsUnalign = nullptr;
} }
// (overloaded) Calculates filter coefficients for SSE routine // (overloaded) Calculates filter coefficients for SSE routine
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
{ {
uint i; uint i;
float fDivider; float fDivider;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Scale the filter coefficients so that it won't be necessary to scale the filtering result // Scale the filter coefficients so that it won't be necessary to scale the filtering result
// also rearrange coefficients suitably for SSE // also rearrange coefficients suitably for SSE
// Ensure that filter coeffs array is aligned to 16-byte boundary // Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign; delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new float[2 * newLength + 4]; filterCoeffsUnalign = new float[2 * newLength + 4];
filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
fDivider = (float)resultDivider; fDivider = (float)resultDivider;
// rearrange the filter coefficients for mmx routines // rearrange the filter coefficients for mmx routines
for (i = 0; i < newLength; i ++) for (i = 0; i < newLength; i ++)
{ {
filterCoeffsAlign[2 * i + 0] = filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
} }
} }
// SSE-optimized version of the filter routine for stereo sound // SSE-optimized version of the filter routine for stereo sound
uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
{ {
int count = (int)((numSamples - length) & (uint)-2); int count = (int)((numSamples - length) & (uint)-2);
int j; int j;
assert(count % 2 == 0); assert(count % 2 == 0);
if (count < 2) return 0; if (count < 2) return 0;
assert(source != nullptr); assert(source != nullptr);
assert(dest != nullptr); assert(dest != nullptr);
assert((length % 8) == 0); assert((length % 8) == 0);
assert(filterCoeffsAlign != nullptr); assert(filterCoeffsAlign != nullptr);
assert(((ulongptr)filterCoeffsAlign) % 16 == 0); assert(((ulongptr)filterCoeffsAlign) % 16 == 0);
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < count; j += 2) for (j = 0; j < count; j += 2)
{ {
const float *pSrc; const float *pSrc;
float *pDest; float *pDest;
const __m128 *pFil; const __m128 *pFil;
__m128 sum1, sum2; __m128 sum1, sum2;
uint i; uint i;
pSrc = (const float*)source + j * 2; // source audio data pSrc = (const float*)source + j * 2; // source audio data
pDest = dest + j * 2; // destination audio data pDest = dest + j * 2; // destination audio data
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
// are aligned to 16-byte boundary // are aligned to 16-byte boundary
sum1 = sum2 = _mm_setzero_ps(); sum1 = sum2 = _mm_setzero_ps();
for (i = 0; i < length / 8; i ++) for (i = 0; i < length / 8; i ++)
{ {
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples // Unroll loop for efficiency & calculate filter for 2*2 stereo samples
// at each pass // at each pass
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset // 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. // 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])); 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])); 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])); 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])); 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])); 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])); 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])); 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])); sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
pSrc += 16; pSrc += 16;
pFil += 4; pFil += 4;
} }
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need // 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. // to sum the two hi- and lo-floats of these registers together.
// post-shuffle & add the filtered values and store to dest. // post-shuffle & add the filtered values and store to dest.
_mm_storeu_ps(pDest, _mm_add_ps( _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(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 _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
)); ));
} }
// Ideas for further improvement: // Ideas for further improvement:
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte // 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. // 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 // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
// boundary, a faster '_mm_store_ps' instruction could be used. // boundary, a faster '_mm_store_ps' instruction could be used.
return (uint)count; return (uint)count;
/* original routine in C-language. please notice the C-version has differently /* original routine in C-language. please notice the C-version has differently
organized coefficients though. organized coefficients though.
double suml1, suml2; double suml1, suml2;
double sumr1, sumr2; double sumr1, sumr2;
uint i, j; uint i, j;
for (j = 0; j < count; j += 2) for (j = 0; j < count; j += 2)
{ {
const float *ptr; const float *ptr;
const float *pFil; const float *pFil;
suml1 = sumr1 = 0.0; suml1 = sumr1 = 0.0;
suml2 = sumr2 = 0.0; suml2 = sumr2 = 0.0;
ptr = src; ptr = src;
pFil = filterCoeffs; pFil = filterCoeffs;
for (i = 0; i < lengthLocal; i ++) for (i = 0; i < lengthLocal; i ++)
{ {
// unroll loop for efficiency. // unroll loop for efficiency.
suml1 += ptr[0] * pFil[0] + suml1 += ptr[0] * pFil[0] +
ptr[2] * pFil[2] + ptr[2] * pFil[2] +
ptr[4] * pFil[4] + ptr[4] * pFil[4] +
ptr[6] * pFil[6]; ptr[6] * pFil[6];
sumr1 += ptr[1] * pFil[1] + sumr1 += ptr[1] * pFil[1] +
ptr[3] * pFil[3] + ptr[3] * pFil[3] +
ptr[5] * pFil[5] + ptr[5] * pFil[5] +
ptr[7] * pFil[7]; ptr[7] * pFil[7];
suml2 += ptr[8] * pFil[0] + suml2 += ptr[8] * pFil[0] +
ptr[10] * pFil[2] + ptr[10] * pFil[2] +
ptr[12] * pFil[4] + ptr[12] * pFil[4] +
ptr[14] * pFil[6]; ptr[14] * pFil[6];
sumr2 += ptr[9] * pFil[1] + sumr2 += ptr[9] * pFil[1] +
ptr[11] * pFil[3] + ptr[11] * pFil[3] +
ptr[13] * pFil[5] + ptr[13] * pFil[5] +
ptr[15] * pFil[7]; ptr[15] * pFil[7];
ptr += 16; ptr += 16;
pFil += 8; pFil += 8;
} }
dest[0] = (float)suml1; dest[0] = (float)suml1;
dest[1] = (float)sumr1; dest[1] = (float)sumr1;
dest[2] = (float)suml2; dest[2] = (float)suml2;
dest[3] = (float)sumr2; dest[3] = (float)sumr2;
src += 4; src += 4;
dest += 4; dest += 4;
} }
*/ */
} }
#endif // SOUNDTOUCH_ALLOW_SSE #endif // SOUNDTOUCH_ALLOW_SSE

View File

@ -1,115 +1,115 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// DllTest.cpp : This is small app main routine used for testing sound processing /// DllTest.cpp : This is small app main routine used for testing sound processing
/// with SoundTouch.dll API /// with SoundTouch.dll API
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include "../SoundTouchDLL.h" #include "../SoundTouchDLL.h"
#include "../../SoundStretch/WavFile.h" #include "../../SoundStretch/WavFile.h"
using namespace std; using namespace std;
using namespace soundstretch; using namespace soundstretch;
// DllTest main // DllTest main
int wmain(int argc, const wchar_t *argv[]) int wmain(int argc, const wchar_t *argv[])
{ {
// Check program arguments // Check program arguments
if (argc < 4) if (argc < 4)
{ {
cout << "Too few arguments. Usage: DllTest [infile.wav] [outfile.wav] [sampletype]" << endl; cout << "Too few arguments. Usage: DllTest [infile.wav] [outfile.wav] [sampletype]" << endl;
return -1; return -1;
} }
wstring inFileName = argv[1]; wstring inFileName = argv[1];
wstring outFileName = argv[2]; wstring outFileName = argv[2];
wstring str_sampleType = argv[3]; wstring str_sampleType = argv[3];
bool floatSample; bool floatSample;
if (str_sampleType == L"float") if (str_sampleType == L"float")
{ {
floatSample = true; floatSample = true;
} }
else if (str_sampleType == L"short") else if (str_sampleType == L"short")
{ {
floatSample = false; floatSample = false;
} }
else else
{ {
cerr << "Missing or invalid sampletype. Expected either short or float" << endl; cerr << "Missing or invalid sampletype. Expected either short or float" << endl;
return -1; return -1;
} }
try try
{ {
// Open input & output WAV files // Open input & output WAV files
WavInFile inFile(inFileName); WavInFile inFile(inFileName);
int numChannels = inFile.getNumChannels(); int numChannels = inFile.getNumChannels();
int sampleRate = inFile.getSampleRate(); int sampleRate = inFile.getSampleRate();
WavOutFile outFile(outFileName, sampleRate, inFile.getNumBits(), numChannels); WavOutFile outFile(outFileName, sampleRate, inFile.getNumBits(), numChannels);
// Create SoundTouch DLL instance // Create SoundTouch DLL instance
HANDLE st = soundtouch_createInstance(); HANDLE st = soundtouch_createInstance();
soundtouch_setChannels(st, numChannels); soundtouch_setChannels(st, numChannels);
soundtouch_setSampleRate(st, sampleRate); soundtouch_setSampleRate(st, sampleRate);
soundtouch_setPitchSemiTones(st, 2); soundtouch_setPitchSemiTones(st, 2);
cout << "processing with soundtouch.dll routines"; cout << "processing with soundtouch.dll routines";
if (floatSample) if (floatSample)
{ {
// Process file with SoundTouch.DLL float sample (default) API // Process file with SoundTouch.DLL float sample (default) API
float fbuffer[2048]; float fbuffer[2048];
int nmax = 2048 / numChannels; int nmax = 2048 / numChannels;
cout << " using float api ..." << endl; cout << " using float api ..." << endl;
while (inFile.eof() == false) while (inFile.eof() == false)
{ {
int n = inFile.read(fbuffer, nmax * numChannels) / numChannels; int n = inFile.read(fbuffer, nmax * numChannels) / numChannels;
soundtouch_putSamples(st, fbuffer, n); soundtouch_putSamples(st, fbuffer, n);
do do
{ {
n = soundtouch_receiveSamples(st, fbuffer, nmax); n = soundtouch_receiveSamples(st, fbuffer, nmax);
outFile.write(fbuffer, n * numChannels); outFile.write(fbuffer, n * numChannels);
} while (n > 0); } while (n > 0);
} }
} }
else else
{ {
// Process file with SoundTouch.DLL int16 (short) sample API. // Process file with SoundTouch.DLL int16 (short) sample API.
// Notice that SoundTouch.dll does internally processing using floating // Notice that SoundTouch.dll does internally processing using floating
// point routines so the int16 API is not any faster, but provided for // point routines so the int16 API is not any faster, but provided for
// convenience. // convenience.
short i16buffer[2048]; short i16buffer[2048];
int nmax = 2048 / numChannels; int nmax = 2048 / numChannels;
cout << " using i16 api ..." << endl; cout << " using i16 api ..." << endl;
while (inFile.eof() == false) while (inFile.eof() == false)
{ {
int n = inFile.read(i16buffer, nmax * numChannels) / numChannels; int n = inFile.read(i16buffer, nmax * numChannels) / numChannels;
soundtouch_putSamples_i16(st, i16buffer, n); soundtouch_putSamples_i16(st, i16buffer, n);
do do
{ {
n = soundtouch_receiveSamples_i16(st, i16buffer, nmax); n = soundtouch_receiveSamples_i16(st, i16buffer, nmax);
outFile.write(i16buffer, n * numChannels); outFile.write(i16buffer, n * numChannels);
} while (n > 0); } while (n > 0);
} }
} }
soundtouch_destroyInstance(st); soundtouch_destroyInstance(st);
cout << "done." << endl; cout << "done." << endl;
} }
catch (const runtime_error &e) catch (const runtime_error &e)
{ {
cerr << e.what() << endl; cerr << e.what() << endl;
} }
return 0; return 0;
} }

View File

@ -1,47 +1,47 @@
## Process this file with automake to create Makefile.in ## Process this file with automake to create Makefile.in
## ##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
## ##
## SoundTouch is free software; you can redistribute it and/or modify it under the ## SoundTouch 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 ## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later ## Foundation; either version 2 of the License, or (at your option) any later
## version. ## version.
## ##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY ## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR ## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details. ## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
## ##
## You should have received a copy of the GNU General Public License along with ## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA ## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk include $(top_srcdir)/config/am_include.mk
noinst_HEADERS=../SoundTouch/AAFilter.h ../SoundTouch/cpu_detect.h ../SoundTouch/cpu_detect_x86.cpp ../SoundTouch/FIRFilter.h \ noinst_HEADERS=../SoundTouch/AAFilter.h ../SoundTouch/cpu_detect.h ../SoundTouch/cpu_detect_x86.cpp ../SoundTouch/FIRFilter.h \
../SoundTouch/RateTransposer.h ../SoundTouch/TDStretch.h ../SoundTouch/PeakFinder.h ../SoundTouch/InterpolateCubic.h \ ../SoundTouch/RateTransposer.h ../SoundTouch/TDStretch.h ../SoundTouch/PeakFinder.h ../SoundTouch/InterpolateCubic.h \
../SoundTouch/InterpolateLinear.h ../SoundTouch/InterpolateShannon.h ../SoundTouch/InterpolateLinear.h ../SoundTouch/InterpolateShannon.h
include_HEADERS=SoundTouchDLL.h include_HEADERS=SoundTouchDLL.h
lib_LTLIBRARIES=libSoundTouchDll.la lib_LTLIBRARIES=libSoundTouchDll.la
# #
libSoundTouchDll_la_SOURCES=../SoundTouch/AAFilter.cpp ../SoundTouch/FIRFilter.cpp \ libSoundTouchDll_la_SOURCES=../SoundTouch/AAFilter.cpp ../SoundTouch/FIRFilter.cpp \
../SoundTouch/FIFOSampleBuffer.cpp ../SoundTouch/RateTransposer.cpp ../SoundTouch/SoundTouch.cpp \ ../SoundTouch/FIFOSampleBuffer.cpp ../SoundTouch/RateTransposer.cpp ../SoundTouch/SoundTouch.cpp \
../SoundTouch/TDStretch.cpp ../SoundTouch/sse_optimized.cpp ../SoundTouch/cpu_detect_x86.cpp \ ../SoundTouch/TDStretch.cpp ../SoundTouch/sse_optimized.cpp ../SoundTouch/cpu_detect_x86.cpp \
../SoundTouch/BPMDetect.cpp ../SoundTouch/PeakFinder.cpp ../SoundTouch/InterpolateLinear.cpp \ ../SoundTouch/BPMDetect.cpp ../SoundTouch/PeakFinder.cpp ../SoundTouch/InterpolateLinear.cpp \
../SoundTouch/InterpolateCubic.cpp ../SoundTouch/InterpolateShannon.cpp SoundTouchDLL.cpp ../SoundTouch/InterpolateCubic.cpp ../SoundTouch/InterpolateShannon.cpp SoundTouchDLL.cpp
# Compiler flags # Compiler flags
# Modify the default 0.0.0 to LIB_SONAME.0.0 # Modify the default 0.0.0 to LIB_SONAME.0.0
AM_LDFLAGS=$(LDFLAGS) -version-info @LIB_SONAME@ AM_LDFLAGS=$(LDFLAGS) -version-info @LIB_SONAME@
if X86 if X86
CXXFLAGS1=-mstackrealign -msse CXXFLAGS1=-mstackrealign -msse
endif endif
if X86_64 if X86_64
CXXFLAGS2=-fPIC CXXFLAGS2=-fPIC
endif endif
AM_CXXFLAGS=$(CXXFLAGS) $(CXXFLAGS1) $(CXXFLAGS2) -shared -DDLL_EXPORTS -fvisibility=hidden AM_CXXFLAGS=$(CXXFLAGS) $(CXXFLAGS1) $(CXXFLAGS2) -shared -DDLL_EXPORTS -fvisibility=hidden

File diff suppressed because it is too large Load Diff

View File

@ -1,240 +1,240 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// ///
/// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load /// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load
/// Library interface. /// Library interface.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// License : // License :
// //
// SoundTouch audio processing library // SoundTouch audio processing library
// Copyright (c) Olli Parviainen // Copyright (c) Olli Parviainen
// //
// This library is free software; you can redistribute it and/or // This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public // modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either // License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version. // 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, // This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details. // Lesser General Public License for more details.
// //
// You should have received a copy of the GNU Lesser General Public // You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software // License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef _SoundTouchDLL_h_ #ifndef _SoundTouchDLL_h_
#define _SoundTouchDLL_h_ #define _SoundTouchDLL_h_
#if defined(_WIN32) || defined(WIN32) #if defined(_WIN32) || defined(WIN32)
// Windows // Windows
#ifndef __cplusplus #ifndef __cplusplus
#error "Expected g++" #error "Expected g++"
#endif #endif
#ifdef DLL_EXPORTS #ifdef DLL_EXPORTS
#define SOUNDTOUCHDLL_API extern "C" __declspec(dllexport) #define SOUNDTOUCHDLL_API extern "C" __declspec(dllexport)
#else #else
#define SOUNDTOUCHDLL_API extern "C" __declspec(dllimport) #define SOUNDTOUCHDLL_API extern "C" __declspec(dllimport)
#endif #endif
#else #else
// GNU version // GNU version
#if defined(DLL_EXPORTS) || defined(SoundTouchDLL_EXPORTS) #if defined(DLL_EXPORTS) || defined(SoundTouchDLL_EXPORTS)
// GCC declaration for exporting functions // GCC declaration for exporting functions
#define SOUNDTOUCHDLL_API extern "C" __attribute__((__visibility__("default"))) #define SOUNDTOUCHDLL_API extern "C" __attribute__((__visibility__("default")))
#else #else
// import function // import function
#define SOUNDTOUCHDLL_API extern "C" #define SOUNDTOUCHDLL_API extern "C"
#endif #endif
// Linux-replacements for Windows declarations: // Linux-replacements for Windows declarations:
#define __cdecl #define __cdecl
typedef unsigned int DWORD; typedef unsigned int DWORD;
#define FALSE 0 #define FALSE 0
#define TRUE 1 #define TRUE 1
#endif #endif
typedef void * HANDLE; typedef void * HANDLE;
/// Create a new instance of SoundTouch processor. /// Create a new instance of SoundTouch processor.
SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance(); SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance();
/// Destroys a SoundTouch processor instance. /// Destroys a SoundTouch processor instance.
SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h); SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h);
/// Get SoundTouch library version string /// Get SoundTouch library version string
SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString(); SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString();
/// Get SoundTouch library version string - alternative function for /// Get SoundTouch library version string - alternative function for
/// environments that can't properly handle character string as return value /// environments that can't properly handle character string as return value
SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize); SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize);
/// Get SoundTouch library version Id /// Get SoundTouch library version Id
SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_getVersionId(); SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_getVersionId();
/// Sets new rate control value. Normal rate = 1.0, smaller values /// Sets new rate control value. Normal rate = 1.0, smaller values
/// represent slower rate, larger faster rates. /// represent slower rate, larger faster rates.
SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate); SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate);
/// Sets new tempo control value. Normal tempo = 1.0, smaller values /// Sets new tempo control value. Normal tempo = 1.0, smaller values
/// represent slower tempo, larger faster tempo. /// represent slower tempo, larger faster tempo.
SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo); SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo);
/// Sets new rate control value as a difference in percents compared /// Sets new rate control value as a difference in percents compared
/// to the original rate (-50 .. +100 %); /// to the original rate (-50 .. +100 %);
SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate); SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate);
/// Sets new tempo control value as a difference in percents compared /// Sets new tempo control value as a difference in percents compared
/// to the original tempo (-50 .. +100 %); /// to the original tempo (-50 .. +100 %);
SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo); SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo);
/// Sets new pitch control value. Original pitch = 1.0, smaller values /// Sets new pitch control value. Original pitch = 1.0, smaller values
/// represent lower pitches, larger values higher pitch. /// represent lower pitches, larger values higher pitch.
SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch); SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch);
/// Sets pitch change in octaves compared to the original pitch /// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00); /// (-1.00 .. +1.00);
SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch); SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch);
/// Sets pitch change in semi-tones compared to the original pitch /// Sets pitch change in semi-tones compared to the original pitch
/// (-12 .. +12); /// (-12 .. +12);
SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch); SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch);
/// Sets the number of channels, 1 = mono, 2 = stereo, n = multichannel /// Sets the number of channels, 1 = mono, 2 = stereo, n = multichannel
SOUNDTOUCHDLL_API int __cdecl soundtouch_setChannels(HANDLE h, unsigned int numChannels); SOUNDTOUCHDLL_API int __cdecl soundtouch_setChannels(HANDLE h, unsigned int numChannels);
/// Sets sample rate. /// Sets sample rate.
SOUNDTOUCHDLL_API int __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int srate); SOUNDTOUCHDLL_API int __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int srate);
/// Flushes the last samples from the processing pipeline to the output. /// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers. /// Clears also the internal processing buffers.
// //
/// Note: This function is meant for extracting the last samples of a sound /// Note: This function is meant for extracting the last samples of a sound
/// stream. This function may introduce additional blank samples in the end /// stream. This function may introduce additional blank samples in the end
/// of the sound stream, and thus it's not recommended to call this function /// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream. /// in the middle of a sound stream.
SOUNDTOUCHDLL_API int __cdecl soundtouch_flush(HANDLE h); SOUNDTOUCHDLL_API int __cdecl soundtouch_flush(HANDLE h);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into /// 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 /// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception. /// calling this function, otherwise throws a runtime_error exception.
SOUNDTOUCHDLL_API int __cdecl soundtouch_putSamples(HANDLE h, SOUNDTOUCHDLL_API int __cdecl soundtouch_putSamples(HANDLE h,
const float *samples, ///< Pointer to sample buffer. const float *samples, ///< Pointer to sample buffer.
unsigned int numSamples ///< Number of sample frames in buffer. Notice unsigned int numSamples ///< Number of sample frames in buffer. Notice
///< that in case of multi-channel sound a single ///< that in case of multi-channel sound a single
///< sample frame contains data for all channels. ///< sample frame contains data for all channels.
); );
/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data /// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data
/// and internally converts it to float format before processing /// and internally converts it to float format before processing
SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h, SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h,
const short *samples, ///< Pointer to sample buffer. const short *samples, ///< Pointer to sample buffer.
unsigned int numSamples ///< Number of sample frames in buffer. Notice unsigned int numSamples ///< Number of sample frames in buffer. Notice
///< that in case of multi-channel sound a single ///< that in case of multi-channel sound a single
///< sample frame contains data for all channels. ///< sample frame contains data for all channels.
); );
/// Clears all the samples in the object's output and internal processing /// Clears all the samples in the object's output and internal processing
/// buffers. /// buffers.
SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h); SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h);
/// Changes a setting controlling the processing system behaviour. See the /// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's. /// 'SETTING_...' defines for available setting ID's.
/// ///
/// \return 'nonzero' if the setting was successfully changed, otherwise zero /// \return 'nonzero' if the setting was successfully changed, otherwise zero
SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h, SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h,
int settingId, ///< Setting ID number. see SETTING_... defines. int settingId, ///< Setting ID number. see SETTING_... defines.
int value ///< New setting value. int value ///< New setting value.
); );
/// Reads a setting controlling the processing system behaviour. See the /// Reads a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's. /// 'SETTING_...' defines for available setting ID's.
/// ///
/// \return the setting value. /// \return the setting value.
SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h, SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h,
int settingId ///< Setting ID number, see SETTING_... defines. int settingId ///< Setting ID number, see SETTING_... defines.
); );
/// Returns number of samples currently unprocessed. /// Returns number of samples currently unprocessed.
SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numUnprocessedSamples(HANDLE h); SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numUnprocessedSamples(HANDLE h);
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples(HANDLE h, SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples(HANDLE h,
float *outBuffer, ///< Buffer where to copy output samples. float *outBuffer, ///< Buffer where to copy output samples.
unsigned int maxSamples ///< How many samples to receive at max. unsigned int maxSamples ///< How many samples to receive at max.
); );
/// int16 version of soundtouch_receiveSamples(): This converts internal float samples /// int16 version of soundtouch_receiveSamples(): This converts internal float samples
/// into int16 (short) return data type /// into int16 (short) return data type
SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples_i16(HANDLE h, SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples_i16(HANDLE h,
short *outBuffer, ///< Buffer where to copy output samples. short *outBuffer, ///< Buffer where to copy output samples.
unsigned int maxSamples ///< How many samples to receive at max. unsigned int maxSamples ///< How many samples to receive at max.
); );
/// Returns number of samples currently available. /// Returns number of samples currently available.
SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numSamples(HANDLE h); SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numSamples(HANDLE h);
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h); SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h);
/// Create a new instance of BPM detector /// Create a new instance of BPM detector
SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate); SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate);
/// Destroys a BPM detector instance. /// Destroys a BPM detector instance.
SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h); SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h);
/// Feed 'numSamples' sample frames from 'samples' into the BPM detector. /// Feed 'numSamples' sample frames from 'samples' into the BPM detector.
SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h, SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h,
const float *samples, ///< Pointer to sample buffer. const float *samples, ///< Pointer to sample buffer.
unsigned int numSamples ///< Number of samples in buffer. Notice unsigned int numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample ///< that in case of stereo-sound a single sample
///< contains data for both channels. ///< contains data for both channels.
); );
/// Feed 'numSamples' sample frames from 'samples' into the BPM detector. /// Feed 'numSamples' sample frames from 'samples' into the BPM detector.
/// 16bit int sample format version. /// 16bit int sample format version.
SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h, SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h,
const short *samples, ///< Pointer to sample buffer. const short *samples, ///< Pointer to sample buffer.
unsigned int numSamples ///< Number of samples in buffer. Notice unsigned int numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample ///< that in case of stereo-sound a single sample
///< contains data for both channels. ///< contains data for both channels.
); );
/// Analyzes the results and returns the BPM rate. Use this function to read result /// 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 /// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function. /// 'inputSamples' function.
/// ///
/// \return Beats-per-minute rate, or zero if detection failed. /// \return Beats-per-minute rate, or zero if detection failed.
SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h); SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h);
/// Get beat position arrays. Note: The array includes also really low beat detection values /// Get beat position arrays. Note: The array includes also really low beat detection values
/// in absence of clear strong beats. Consumer may wish to filter low values away. /// in absence of clear strong beats. Consumer may wish to filter low values away.
/// - "pos" receive array of beat positions /// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths /// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array. /// - max_num indicates max.size of "pos" and "values" array.
/// ///
/// You can query a suitable array sized by calling this with nullptr in "pos" & "values". /// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
/// ///
/// \return number of beats in the arrays. /// \return number of beats in the arrays.
SOUNDTOUCHDLL_API int __cdecl bpm_getBeats(HANDLE h, float *pos, float *strength, int count); SOUNDTOUCHDLL_API int __cdecl bpm_getBeats(HANDLE h, float *pos, float *strength, int count);
#endif // _SoundTouchDLL_h_ #endif // _SoundTouchDLL_h_

View File

@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""afxres.h""\r\n" "#include ""afxres.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"

View File

@ -1,15 +1,15 @@
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by SoundTouchDLL.rc // Used by SoundTouchDLL.rc
// //
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif