Stripped down version of SoundTouch 1.9.2
This commit is contained in:
parent
5bbd6f6d94
commit
5274ec4dec
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
set(SRCS
|
||||||
|
src/AAFilter.cpp
|
||||||
|
src/cpu_detect_x86.cpp
|
||||||
|
src/FIFOSampleBuffer.cpp
|
||||||
|
src/FIRFilter.cpp
|
||||||
|
src/InterpolateLinear.cpp
|
||||||
|
src/RateTransposer.cpp
|
||||||
|
src/SoundTouch.cpp
|
||||||
|
src/TDStretch.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(src include)
|
||||||
|
|
||||||
|
add_library(SoundTouch STATIC ${SRCS})
|
184
include/FIFOSampleBuffer.h
Normal file
184
include/FIFOSampleBuffer.h
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// A buffer class for temporarily storaging sound samples, operates as a
|
||||||
|
/// first-in-first-out pipe.
|
||||||
|
///
|
||||||
|
/// Samples are added to the end of the sample buffer with the 'putSamples'
|
||||||
|
/// function, and are received from the beginning of the buffer by calling
|
||||||
|
/// the 'receiveSamples' function. The class automatically removes the
|
||||||
|
/// output samples from the buffer as well as grows the storage size
|
||||||
|
/// whenever necessary.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: FIFOSampleBuffer.h 177 2014-01-05 21:40:22Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef FIFOSampleBuffer_H
|
||||||
|
#define FIFOSampleBuffer_H
|
||||||
|
|
||||||
|
#include "FIFOSamplePipe.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
|
||||||
|
/// care of storage size adjustment and data moving during input/output operations.
|
||||||
|
///
|
||||||
|
/// Notice that in case of stereo audio, one sample is considered to consist of
|
||||||
|
/// both channel data.
|
||||||
|
class FIFOSampleBuffer : public FIFOSamplePipe
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// Sample buffer.
|
||||||
|
SAMPLETYPE *buffer;
|
||||||
|
|
||||||
|
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
|
||||||
|
// 16-byte aligned location of this buffer
|
||||||
|
SAMPLETYPE *bufferUnaligned;
|
||||||
|
|
||||||
|
/// Sample buffer size in bytes
|
||||||
|
uint sizeInBytes;
|
||||||
|
|
||||||
|
/// How many samples are currently in buffer.
|
||||||
|
uint samplesInBuffer;
|
||||||
|
|
||||||
|
/// Channels, 1=mono, 2=stereo.
|
||||||
|
uint channels;
|
||||||
|
|
||||||
|
/// Current position pointer to the buffer. This pointer is increased when samples are
|
||||||
|
/// removed from the pipe so that it's necessary to actually rewind buffer (move data)
|
||||||
|
/// only new data when is put to the pipe.
|
||||||
|
uint bufferPos;
|
||||||
|
|
||||||
|
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
|
||||||
|
/// beginning of the buffer.
|
||||||
|
void rewind();
|
||||||
|
|
||||||
|
/// Ensures that the buffer has capacity for at least this many samples.
|
||||||
|
void ensureCapacity(uint capacityRequirement);
|
||||||
|
|
||||||
|
/// Returns current capacity.
|
||||||
|
uint getCapacity() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Constructor
|
||||||
|
FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
|
||||||
|
///< Default is stereo.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// destructor
|
||||||
|
~FIFOSampleBuffer();
|
||||||
|
|
||||||
|
/// Returns a pointer to the beginning of the output samples.
|
||||||
|
/// This function is provided for accessing the output samples directly.
|
||||||
|
/// Please be careful for not to corrupt the book-keeping!
|
||||||
|
///
|
||||||
|
/// When using this function to output samples, also remember to 'remove' the
|
||||||
|
/// output samples from the buffer by calling the
|
||||||
|
/// 'receiveSamples(numSamples)' function
|
||||||
|
virtual SAMPLETYPE *ptrBegin();
|
||||||
|
|
||||||
|
/// Returns a pointer to the end of the used part of the sample buffer (i.e.
|
||||||
|
/// where the new samples are to be inserted). This function may be used for
|
||||||
|
/// inserting new samples into the sample buffer directly. Please be careful
|
||||||
|
/// not corrupt the book-keeping!
|
||||||
|
///
|
||||||
|
/// When using this function as means for inserting new samples, also remember
|
||||||
|
/// to increase the sample count afterwards, by calling the
|
||||||
|
/// 'putSamples(numSamples)' function.
|
||||||
|
SAMPLETYPE *ptrEnd(
|
||||||
|
uint slackCapacity ///< How much free capacity (in samples) there _at least_
|
||||||
|
///< should be so that the caller can succesfully insert the
|
||||||
|
///< desired samples to the buffer. If necessary, the function
|
||||||
|
///< grows the buffer size to comply with this requirement.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
||||||
|
/// the sample buffer.
|
||||||
|
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
|
||||||
|
uint numSamples ///< Number of samples to insert.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Adjusts the book-keeping to increase number of samples in the buffer without
|
||||||
|
/// copying any actual samples.
|
||||||
|
///
|
||||||
|
/// This function is used to update the number of samples in the sample buffer
|
||||||
|
/// when accessing the buffer directly with 'ptrEnd' function. Please be
|
||||||
|
/// careful though!
|
||||||
|
virtual void putSamples(uint numSamples ///< Number of samples been inserted.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
|
/// \return Number of samples returned.
|
||||||
|
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
||||||
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
|
/// with 'ptrBegin' function.
|
||||||
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Returns number of samples currently available.
|
||||||
|
virtual uint numSamples() const;
|
||||||
|
|
||||||
|
/// Sets number of channels, 1 = mono, 2 = stereo.
|
||||||
|
void setChannels(int numChannels);
|
||||||
|
|
||||||
|
/// Get number of channels
|
||||||
|
int getChannels()
|
||||||
|
{
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
virtual int isEmpty() const;
|
||||||
|
|
||||||
|
/// Clears all the samples.
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
|
/// Returns adjusted amount of samples
|
||||||
|
uint adjustAmountOfSamples(uint numSamples);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
234
include/FIFOSamplePipe.h
Normal file
234
include/FIFOSamplePipe.h
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
|
||||||
|
/// samples by operating like a first-in-first-out pipe: New samples are fed
|
||||||
|
/// into one end of the pipe with the 'putSamples' function, and the processed
|
||||||
|
/// samples are received from the other end with the 'receiveSamples' function.
|
||||||
|
///
|
||||||
|
/// 'FIFOProcessor' : A base class for classes the do signal processing with
|
||||||
|
/// the samples while operating like a first-in-first-out pipe. When samples
|
||||||
|
/// are input with the 'putSamples' function, the class processes them
|
||||||
|
/// and moves the processed samples to the given 'output' pipe object, which
|
||||||
|
/// may be either another processing stage, or a fifo sample buffer object.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2012-06-13 22:29:53 +0300 (Wed, 13 Jun 2012) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef FIFOSamplePipe_H
|
||||||
|
#define FIFOSamplePipe_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
|
||||||
|
class FIFOSamplePipe
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// virtual default destructor
|
||||||
|
virtual ~FIFOSamplePipe() {}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns a pointer to the beginning of the output samples.
|
||||||
|
/// This function is provided for accessing the output samples directly.
|
||||||
|
/// Please be careful for not to corrupt the book-keeping!
|
||||||
|
///
|
||||||
|
/// When using this function to output samples, also remember to 'remove' the
|
||||||
|
/// output samples from the buffer by calling the
|
||||||
|
/// 'receiveSamples(numSamples)' function
|
||||||
|
virtual SAMPLETYPE *ptrBegin() = 0;
|
||||||
|
|
||||||
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
||||||
|
/// the sample buffer.
|
||||||
|
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
|
||||||
|
uint numSamples ///< Number of samples to insert.
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Moves samples from the 'other' pipe instance to this instance.
|
||||||
|
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int oNumSamples = other.numSamples();
|
||||||
|
|
||||||
|
putSamples(other.ptrBegin(), oNumSamples);
|
||||||
|
other.receiveSamples(oNumSamples);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
|
/// \return Number of samples returned.
|
||||||
|
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
||||||
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
|
/// with 'ptrBegin' function.
|
||||||
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
|
) = 0;
|
||||||
|
|
||||||
|
/// Returns number of samples currently available.
|
||||||
|
virtual uint numSamples() const = 0;
|
||||||
|
|
||||||
|
// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
virtual int isEmpty() const = 0;
|
||||||
|
|
||||||
|
/// Clears all the samples.
|
||||||
|
virtual void clear() = 0;
|
||||||
|
|
||||||
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
|
/// Returns adjusted amount of samples
|
||||||
|
virtual uint adjustAmountOfSamples(uint numSamples) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Base-class for sound processing routines working in FIFO principle. With this base
|
||||||
|
/// class it's easy to implement sound processing stages that can be chained together,
|
||||||
|
/// so that samples that are fed into beginning of the pipe automatically go through
|
||||||
|
/// all the processing stages.
|
||||||
|
///
|
||||||
|
/// When samples are input to this class, they're first processed and then put to
|
||||||
|
/// the FIFO pipe that's defined as output of this class. This output pipe can be
|
||||||
|
/// either other processing stage or a FIFO sample buffer.
|
||||||
|
class FIFOProcessor :public FIFOSamplePipe
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/// Internal pipe where processed samples are put.
|
||||||
|
FIFOSamplePipe *output;
|
||||||
|
|
||||||
|
/// Sets output pipe.
|
||||||
|
void setOutPipe(FIFOSamplePipe *pOutput)
|
||||||
|
{
|
||||||
|
assert(output == NULL);
|
||||||
|
assert(pOutput != NULL);
|
||||||
|
output = pOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Constructor. Doesn't define output pipe; it has to be set be
|
||||||
|
/// 'setOutPipe' function.
|
||||||
|
FIFOProcessor()
|
||||||
|
{
|
||||||
|
output = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Constructor. Configures output pipe.
|
||||||
|
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
output = pOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Destructor.
|
||||||
|
virtual ~FIFOProcessor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns a pointer to the beginning of the output samples.
|
||||||
|
/// This function is provided for accessing the output samples directly.
|
||||||
|
/// Please be careful for not to corrupt the book-keeping!
|
||||||
|
///
|
||||||
|
/// When using this function to output samples, also remember to 'remove' the
|
||||||
|
/// output samples from the buffer by calling the
|
||||||
|
/// 'receiveSamples(numSamples)' function
|
||||||
|
virtual SAMPLETYPE *ptrBegin()
|
||||||
|
{
|
||||||
|
return output->ptrBegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
|
/// \return Number of samples returned.
|
||||||
|
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
|
||||||
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return output->receiveSamples(outBuffer, maxSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
|
/// with 'ptrBegin' function.
|
||||||
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return output->receiveSamples(maxSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns number of samples currently available.
|
||||||
|
virtual uint numSamples() const
|
||||||
|
{
|
||||||
|
return output->numSamples();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
virtual int isEmpty() const
|
||||||
|
{
|
||||||
|
return output->isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
|
/// Returns adjusted amount of samples
|
||||||
|
virtual uint adjustAmountOfSamples(uint numSamples)
|
||||||
|
{
|
||||||
|
return output->adjustAmountOfSamples(numSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
177
include/STTypes.h
Normal file
177
include/STTypes.h
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Common type definitions for SoundTouch audio processing library.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-05-18 18:25:07 +0300 (Mon, 18 May 2015) $
|
||||||
|
// File revision : $Revision: 3 $
|
||||||
|
//
|
||||||
|
// $Id: STTypes.h 215 2015-05-18 15:25:07Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef STTypes_H
|
||||||
|
#define STTypes_H
|
||||||
|
|
||||||
|
typedef unsigned int uint;
|
||||||
|
typedef unsigned long ulong;
|
||||||
|
|
||||||
|
// Patch for MinGW: on Win64 long is 32-bit
|
||||||
|
#ifdef _WIN64
|
||||||
|
typedef unsigned long long ulongptr;
|
||||||
|
#else
|
||||||
|
typedef ulong ulongptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Helper macro for aligning pointer up to next 16-byte boundary
|
||||||
|
#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 )
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
/// Activate these undef's to overrule the possible sampletype
|
||||||
|
/// setting inherited from some other header file:
|
||||||
|
//#undef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
//#undef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
|
||||||
|
/// If following flag is defined, always uses multichannel processing
|
||||||
|
/// routines also for mono and stero sound. This is for routine testing
|
||||||
|
/// purposes; output should be same with either routines, yet disabling
|
||||||
|
/// the dedicated mono/stereo processing routines will result in slower
|
||||||
|
/// runtime performance so recommendation is to keep this off.
|
||||||
|
// #define USE_MULTICH_ALWAYS
|
||||||
|
|
||||||
|
#if (defined(__SOFTFP__) && defined(ANDROID))
|
||||||
|
// For Android compilation: Force use of Integer samples in case that
|
||||||
|
// compilation uses soft-floating point emulation - soft-fp is way too slow
|
||||||
|
#undef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
#define SOUNDTOUCH_INTEGER_SAMPLES 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
|
||||||
|
|
||||||
|
/// Choose either 32bit floating point or 16bit integer sampletype
|
||||||
|
/// by choosing one of the following defines, unless this selection
|
||||||
|
/// has already been done in some other file.
|
||||||
|
////
|
||||||
|
/// Notes:
|
||||||
|
/// - In Windows environment, choose the sample format with the
|
||||||
|
/// following defines.
|
||||||
|
/// - In GNU environment, the floating point samples are used by
|
||||||
|
/// default, but integer samples can be chosen by giving the
|
||||||
|
/// following switch to the configure script:
|
||||||
|
/// ./configure --enable-integer-samples
|
||||||
|
/// However, if you still prefer to select the sample format here
|
||||||
|
/// also in GNU environment, then please #undef the INTEGER_SAMPLE
|
||||||
|
/// and FLOAT_SAMPLE defines first as in comments above.
|
||||||
|
#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
|
||||||
|
//#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
|
||||||
|
/// Define this to allow X86-specific assembler/intrinsic optimizations.
|
||||||
|
/// Notice that library contains also usual C++ versions of each of these
|
||||||
|
/// these routines, so if you're having difficulties getting the optimized
|
||||||
|
/// routines compiled for whatever reason, you may disable these optimizations
|
||||||
|
/// to make the library compile.
|
||||||
|
|
||||||
|
//#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
|
||||||
|
|
||||||
|
/// In GNU environment, allow the user to override this setting by
|
||||||
|
/// giving the following switch to the configure script:
|
||||||
|
/// ./configure --disable-x86-optimizations
|
||||||
|
/// ./configure --enable-x86-optimizations=no
|
||||||
|
#ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
|
||||||
|
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/// Always disable optimizations when not using a x86 systems.
|
||||||
|
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If defined, allows the SIMD-optimized routines to take minor shortcuts
|
||||||
|
// for improved performance. Undefine to require faithfully similar SIMD
|
||||||
|
// calculations as in normal C implementation.
|
||||||
|
#define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
// 16bit integer sample type
|
||||||
|
typedef short SAMPLETYPE;
|
||||||
|
// data type for sample accumulation: Use 32bit integer to prevent overflows
|
||||||
|
typedef long LONG_SAMPLETYPE;
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
// check that only one sample type is defined
|
||||||
|
#error "conflicting sample types defined"
|
||||||
|
#endif // SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
|
// Allow MMX optimizations
|
||||||
|
#define SOUNDTOUCH_ALLOW_MMX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// floating point samples
|
||||||
|
typedef float SAMPLETYPE;
|
||||||
|
// data type for sample accumulation: Use double to utilize full precision.
|
||||||
|
typedef double LONG_SAMPLETYPE;
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
|
// Allow SSE optimizations
|
||||||
|
#define SOUNDTOUCH_ALLOW_SSE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:
|
||||||
|
// #define ST_NO_EXCEPTION_HANDLING 1
|
||||||
|
#ifdef ST_NO_EXCEPTION_HANDLING
|
||||||
|
// Exceptions disabled. Throw asserts instead if enabled.
|
||||||
|
#include <assert.h>
|
||||||
|
#define ST_THROW_RT_ERROR(x) {assert((const char *)x);}
|
||||||
|
#else
|
||||||
|
// use c++ standard exceptions
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
|
||||||
|
// parameter setting crosses from value <1 to >=1 or vice versa during processing.
|
||||||
|
// Default is off as such crossover is untypical case and involves a slight sound
|
||||||
|
// quality compromise.
|
||||||
|
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1
|
||||||
|
|
||||||
|
#endif
|
301
include/SoundTouch.h
Normal file
301
include/SoundTouch.h
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
/// - Initialize the SoundTouch object instance by setting up the sound stream
|
||||||
|
/// parameters with functions 'setSampleRate' and 'setChannels', then set
|
||||||
|
/// desired tempo/pitch/rate settings with the corresponding functions.
|
||||||
|
///
|
||||||
|
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
|
||||||
|
/// samples that are to be processed are fed into one of the pipe by calling
|
||||||
|
/// function 'putSamples', while the ready processed samples can be read
|
||||||
|
/// from the other end of the pipeline with function 'receiveSamples'.
|
||||||
|
///
|
||||||
|
/// - The SoundTouch processing classes require certain sized 'batches' of
|
||||||
|
/// samples in order to process the sound. For this reason the classes buffer
|
||||||
|
/// incoming samples until there are enough of samples available for
|
||||||
|
/// processing, then they carry out the processing step and consequently
|
||||||
|
/// make the processed samples available for outputting.
|
||||||
|
///
|
||||||
|
/// - For the above reason, the processing routines introduce a certain
|
||||||
|
/// 'latency' between the input and output, so that the samples input to
|
||||||
|
/// SoundTouch may not be immediately available in the output, and neither
|
||||||
|
/// the amount of outputtable samples may not immediately be in direct
|
||||||
|
/// relationship with the amount of previously input samples.
|
||||||
|
///
|
||||||
|
/// - The tempo/pitch/rate control parameters can be altered during processing.
|
||||||
|
/// Please notice though that they aren't currently protected by semaphores,
|
||||||
|
/// so in multi-thread application external semaphore protection may be
|
||||||
|
/// required.
|
||||||
|
///
|
||||||
|
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
|
||||||
|
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
|
||||||
|
/// tempo and pitch in the same ratio) of the sound. The third available control
|
||||||
|
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
|
||||||
|
/// combining the two other controls.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-09-20 10:38:32 +0300 (Sun, 20 Sep 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: SoundTouch.h 230 2015-09-20 07:38:32Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SoundTouch_H
|
||||||
|
#define SoundTouch_H
|
||||||
|
|
||||||
|
#include "FIFOSamplePipe.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Soundtouch library version string
|
||||||
|
#define SOUNDTOUCH_VERSION "1.9.2"
|
||||||
|
|
||||||
|
/// SoundTouch library version id
|
||||||
|
#define SOUNDTOUCH_VERSION_ID (10902)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
||||||
|
|
||||||
|
/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
|
||||||
|
#define SETTING_USE_AA_FILTER 0
|
||||||
|
|
||||||
|
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
|
||||||
|
#define SETTING_AA_FILTER_LENGTH 1
|
||||||
|
|
||||||
|
/// Enable/disable quick seeking algorithm in tempo changer routine
|
||||||
|
/// (enabling quick seeking lowers CPU utilization but causes a minor sound
|
||||||
|
/// quality compromising)
|
||||||
|
#define SETTING_USE_QUICKSEEK 2
|
||||||
|
|
||||||
|
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
|
||||||
|
/// to how long sequences the original sound is chopped in the time-stretch algorithm.
|
||||||
|
/// See "STTypes.h" or README for more information.
|
||||||
|
#define SETTING_SEQUENCE_MS 3
|
||||||
|
|
||||||
|
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
|
||||||
|
/// best possible overlapping location. This determines from how wide window the algorithm
|
||||||
|
/// may look for an optimal joining location when mixing the sound sequences back together.
|
||||||
|
/// See "STTypes.h" or README for more information.
|
||||||
|
#define SETTING_SEEKWINDOW_MS 4
|
||||||
|
|
||||||
|
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
|
||||||
|
/// are mixed back together, to form a continuous sound stream, this parameter defines over
|
||||||
|
/// how long period the two consecutive sequences are let to overlap each other.
|
||||||
|
/// See "STTypes.h" or README for more information.
|
||||||
|
#define SETTING_OVERLAP_MS 5
|
||||||
|
|
||||||
|
|
||||||
|
/// Call "getSetting" with this ID to query nominal average processing sequence
|
||||||
|
/// size in samples. This value tells approcimate value how many input samples
|
||||||
|
/// SoundTouch needs to gather before it does DSP processing run for the sample batch.
|
||||||
|
///
|
||||||
|
/// Notices:
|
||||||
|
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
||||||
|
/// - Returned value is approximate average value, exact processing batch
|
||||||
|
/// size may wary from time to time
|
||||||
|
/// - This parameter value is not constant but may change depending on
|
||||||
|
/// tempo/pitch/rate/samplerate settings.
|
||||||
|
#define SETTING_NOMINAL_INPUT_SEQUENCE 6
|
||||||
|
|
||||||
|
|
||||||
|
/// Call "getSetting" with this ID to query nominal average processing output
|
||||||
|
/// size in samples. This value tells approcimate value how many output samples
|
||||||
|
/// SoundTouch outputs once it does DSP processing run for a batch of input samples.
|
||||||
|
///
|
||||||
|
/// Notices:
|
||||||
|
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
||||||
|
/// - Returned value is approximate average value, exact processing batch
|
||||||
|
/// size may wary from time to time
|
||||||
|
/// - This parameter value is not constant but may change depending on
|
||||||
|
/// tempo/pitch/rate/samplerate settings.
|
||||||
|
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
|
||||||
|
|
||||||
|
class SoundTouch : public FIFOProcessor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/// Rate transposer class instance
|
||||||
|
class RateTransposer *pRateTransposer;
|
||||||
|
|
||||||
|
/// Time-stretch class instance
|
||||||
|
class TDStretch *pTDStretch;
|
||||||
|
|
||||||
|
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
||||||
|
double virtualRate;
|
||||||
|
|
||||||
|
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
||||||
|
double virtualTempo;
|
||||||
|
|
||||||
|
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
||||||
|
double virtualPitch;
|
||||||
|
|
||||||
|
/// Flag: Has sample rate been set?
|
||||||
|
bool bSrateSet;
|
||||||
|
|
||||||
|
/// Accumulator for how many samples in total will be expected as output vs. samples put in,
|
||||||
|
/// considering current processing settings.
|
||||||
|
double samplesExpectedOut;
|
||||||
|
|
||||||
|
/// Accumulator for how many samples in total have been read out from the processing so far
|
||||||
|
long samplesOutput;
|
||||||
|
|
||||||
|
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
|
||||||
|
/// 'virtualPitch' parameters.
|
||||||
|
void calcEffectiveRateAndTempo();
|
||||||
|
|
||||||
|
protected :
|
||||||
|
/// Number of channels
|
||||||
|
uint channels;
|
||||||
|
|
||||||
|
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
|
||||||
|
double rate;
|
||||||
|
|
||||||
|
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
|
||||||
|
double tempo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SoundTouch();
|
||||||
|
virtual ~SoundTouch();
|
||||||
|
|
||||||
|
/// Get SoundTouch library version string
|
||||||
|
static const char *getVersionString();
|
||||||
|
|
||||||
|
/// Get SoundTouch library version Id
|
||||||
|
static uint getVersionId();
|
||||||
|
|
||||||
|
/// Sets new rate control value. Normal rate = 1.0, smaller values
|
||||||
|
/// represent slower rate, larger faster rates.
|
||||||
|
void setRate(double newRate);
|
||||||
|
|
||||||
|
/// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
||||||
|
/// represent slower tempo, larger faster tempo.
|
||||||
|
void setTempo(double newTempo);
|
||||||
|
|
||||||
|
/// Sets new rate control value as a difference in percents compared
|
||||||
|
/// to the original rate (-50 .. +100 %)
|
||||||
|
void setRateChange(double newRate);
|
||||||
|
|
||||||
|
/// Sets new tempo control value as a difference in percents compared
|
||||||
|
/// to the original tempo (-50 .. +100 %)
|
||||||
|
void setTempoChange(double newTempo);
|
||||||
|
|
||||||
|
/// Sets new pitch control value. Original pitch = 1.0, smaller values
|
||||||
|
/// represent lower pitches, larger values higher pitch.
|
||||||
|
void setPitch(double newPitch);
|
||||||
|
|
||||||
|
/// Sets pitch change in octaves compared to the original pitch
|
||||||
|
/// (-1.00 .. +1.00)
|
||||||
|
void setPitchOctaves(double newPitch);
|
||||||
|
|
||||||
|
/// Sets pitch change in semi-tones compared to the original pitch
|
||||||
|
/// (-12 .. +12)
|
||||||
|
void setPitchSemiTones(int newPitch);
|
||||||
|
void setPitchSemiTones(double newPitch);
|
||||||
|
|
||||||
|
/// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
|
void setChannels(uint numChannels);
|
||||||
|
|
||||||
|
/// Sets sample rate.
|
||||||
|
void setSampleRate(uint srate);
|
||||||
|
|
||||||
|
/// Flushes the last samples from the processing pipeline to the output.
|
||||||
|
/// Clears also the internal processing buffers.
|
||||||
|
//
|
||||||
|
/// Note: This function is meant for extracting the last samples of a sound
|
||||||
|
/// stream. This function may introduce additional blank samples in the end
|
||||||
|
/// of the sound stream, and thus it's not recommended to call this function
|
||||||
|
/// in the middle of a sound stream.
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
||||||
|
/// the input of the object. Notice that sample rate _has_to_ be set before
|
||||||
|
/// calling this function, otherwise throws a runtime_error exception.
|
||||||
|
virtual void putSamples(
|
||||||
|
const SAMPLETYPE *samples, ///< Pointer to sample buffer.
|
||||||
|
uint numSamples ///< Number of samples in buffer. Notice
|
||||||
|
///< that in case of stereo-sound a single sample
|
||||||
|
///< contains data for both channels.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
|
/// \return Number of samples returned.
|
||||||
|
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
||||||
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
|
/// with 'ptrBegin' function.
|
||||||
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Clears all the samples in the object's output and internal processing
|
||||||
|
/// buffers.
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
/// Changes a setting controlling the processing system behaviour. See the
|
||||||
|
/// 'SETTING_...' defines for available setting ID's.
|
||||||
|
///
|
||||||
|
/// \return 'true' if the setting was succesfully changed
|
||||||
|
bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
|
||||||
|
int value ///< New setting value.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Reads a setting controlling the processing system behaviour. See the
|
||||||
|
/// 'SETTING_...' defines for available setting ID's.
|
||||||
|
///
|
||||||
|
/// \return the setting value.
|
||||||
|
int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
|
||||||
|
) const;
|
||||||
|
|
||||||
|
/// Returns number of samples currently unprocessed.
|
||||||
|
virtual uint numUnprocessedSamples() const;
|
||||||
|
|
||||||
|
|
||||||
|
/// Other handy functions that are implemented in the ancestor classes (see
|
||||||
|
/// classes 'FIFOProcessor' and 'FIFOSamplePipe')
|
||||||
|
///
|
||||||
|
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
|
||||||
|
/// - numSamples() : Get number of 'ready' samples that can be received with
|
||||||
|
/// function 'receiveSamples()'
|
||||||
|
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
|
||||||
|
/// - clear() : Clears all samples from ready/processing buffers.
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
236
src/AAFilter.cpp
Normal file
236
src/AAFilter.cpp
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
|
||||||
|
/// MMX optimization.
|
||||||
|
///
|
||||||
|
/// Anti-alias filter is used to prevent folding of high frequencies when
|
||||||
|
/// transposing the sample rate with interpolation.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "AAFilter.h"
|
||||||
|
#include "FIRFilter.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
#define PI 3.141592655357989
|
||||||
|
#define TWOPI (2 * PI)
|
||||||
|
|
||||||
|
// define this to save AA filter coefficients to a file
|
||||||
|
// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1
|
||||||
|
|
||||||
|
#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
|
||||||
|
{
|
||||||
|
FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
|
||||||
|
if (fptr == NULL) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i ++)
|
||||||
|
{
|
||||||
|
double temp = coeffs[i];
|
||||||
|
fprintf(fptr, "%lf\n", temp);
|
||||||
|
}
|
||||||
|
fclose(fptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Implementation of the class 'AAFilter'
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
AAFilter::AAFilter(uint len)
|
||||||
|
{
|
||||||
|
pFIR = FIRFilter::newInstance();
|
||||||
|
cutoffFreq = 0.5;
|
||||||
|
setLength(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AAFilter::~AAFilter()
|
||||||
|
{
|
||||||
|
delete pFIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new anti-alias filter cut-off edge frequency, scaled to
|
||||||
|
// sampling frequency (nyquist frequency = 0.5).
|
||||||
|
// The filter will cut frequencies higher than the given frequency.
|
||||||
|
void AAFilter::setCutoffFreq(double newCutoffFreq)
|
||||||
|
{
|
||||||
|
cutoffFreq = newCutoffFreq;
|
||||||
|
calculateCoeffs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets number of FIR filter taps
|
||||||
|
void AAFilter::setLength(uint newLength)
|
||||||
|
{
|
||||||
|
length = newLength;
|
||||||
|
calculateCoeffs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Calculates coefficients for a low-pass FIR filter using Hamming window
|
||||||
|
void AAFilter::calculateCoeffs()
|
||||||
|
{
|
||||||
|
uint i;
|
||||||
|
double cntTemp, temp, tempCoeff,h, w;
|
||||||
|
double wc;
|
||||||
|
double scaleCoeff, sum;
|
||||||
|
double *work;
|
||||||
|
SAMPLETYPE *coeffs;
|
||||||
|
|
||||||
|
assert(length >= 2);
|
||||||
|
assert(length % 4 == 0);
|
||||||
|
assert(cutoffFreq >= 0);
|
||||||
|
assert(cutoffFreq <= 0.5);
|
||||||
|
|
||||||
|
work = new double[length];
|
||||||
|
coeffs = new SAMPLETYPE[length];
|
||||||
|
|
||||||
|
wc = 2.0 * PI * cutoffFreq;
|
||||||
|
tempCoeff = TWOPI / (double)length;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for (i = 0; i < length; i ++)
|
||||||
|
{
|
||||||
|
cntTemp = (double)i - (double)(length / 2);
|
||||||
|
|
||||||
|
temp = cntTemp * wc;
|
||||||
|
if (temp != 0)
|
||||||
|
{
|
||||||
|
h = sin(temp) / temp; // sinc function
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h = 1.0;
|
||||||
|
}
|
||||||
|
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
|
||||||
|
|
||||||
|
temp = w * h;
|
||||||
|
work[i] = temp;
|
||||||
|
|
||||||
|
// calc net sum of coefficients
|
||||||
|
sum += temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the sum of coefficients is larger than zero
|
||||||
|
assert(sum > 0);
|
||||||
|
|
||||||
|
// ensure we've really designed a lowpass filter...
|
||||||
|
assert(work[length/2] > 0);
|
||||||
|
assert(work[length/2 + 1] > -1e-6);
|
||||||
|
assert(work[length/2 - 1] > -1e-6);
|
||||||
|
|
||||||
|
// Calculate a scaling coefficient in such a way that the result can be
|
||||||
|
// divided by 16384
|
||||||
|
scaleCoeff = 16384.0f / sum;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i ++)
|
||||||
|
{
|
||||||
|
temp = work[i] * scaleCoeff;
|
||||||
|
//#if SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
// scale & round to nearest integer
|
||||||
|
temp += (temp >= 0) ? 0.5 : -0.5;
|
||||||
|
// ensure no overfloods
|
||||||
|
assert(temp >= -32768 && temp <= 32767);
|
||||||
|
//#endif
|
||||||
|
coeffs[i] = (SAMPLETYPE)temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
|
||||||
|
pFIR->setCoefficients(coeffs, length, 14);
|
||||||
|
|
||||||
|
_DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
|
||||||
|
|
||||||
|
delete[] work;
|
||||||
|
delete[] coeffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Applies the filter to the given sequence of samples.
|
||||||
|
// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
|
// smaller than the amount of input samples.
|
||||||
|
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
|
||||||
|
{
|
||||||
|
return pFIR->evaluate(dest, src, numSamples, numChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Applies the filter to the given src & dest pipes, so that processed amount of
|
||||||
|
/// samples get removed from src, and produced amount added to dest
|
||||||
|
/// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
|
/// smaller than the amount of input samples.
|
||||||
|
uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
|
||||||
|
{
|
||||||
|
SAMPLETYPE *pdest;
|
||||||
|
const SAMPLETYPE *psrc;
|
||||||
|
uint numSrcSamples;
|
||||||
|
uint result;
|
||||||
|
int numChannels = src.getChannels();
|
||||||
|
|
||||||
|
assert(numChannels == dest.getChannels());
|
||||||
|
|
||||||
|
numSrcSamples = src.numSamples();
|
||||||
|
psrc = src.ptrBegin();
|
||||||
|
pdest = dest.ptrEnd(numSrcSamples);
|
||||||
|
result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
|
||||||
|
src.receiveSamples(result);
|
||||||
|
dest.putSamples(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint AAFilter::getLength() const
|
||||||
|
{
|
||||||
|
return pFIR->getLength();
|
||||||
|
}
|
100
src/AAFilter.h
Normal file
100
src/AAFilter.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
|
||||||
|
/// while maintaining the original pitch by using a time domain WSOLA-like method
|
||||||
|
/// with several performance-increasing tweaks.
|
||||||
|
///
|
||||||
|
/// Anti-alias filter is used to prevent folding of high frequencies when
|
||||||
|
/// transposing the sample rate with interpolation.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2014-01-07 21:41:23 +0200 (Tue, 07 Jan 2014) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef AAFilter_H
|
||||||
|
#define AAFilter_H
|
||||||
|
|
||||||
|
#include "STTypes.h"
|
||||||
|
#include "FIFOSampleBuffer.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
class AAFilter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
class FIRFilter *pFIR;
|
||||||
|
|
||||||
|
/// Low-pass filter cut-off frequency, negative = invalid
|
||||||
|
double cutoffFreq;
|
||||||
|
|
||||||
|
/// num of filter taps
|
||||||
|
uint length;
|
||||||
|
|
||||||
|
/// Calculate the FIR coefficients realizing the given cutoff-frequency
|
||||||
|
void calculateCoeffs();
|
||||||
|
public:
|
||||||
|
AAFilter(uint length);
|
||||||
|
|
||||||
|
~AAFilter();
|
||||||
|
|
||||||
|
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
|
||||||
|
/// frequency (nyquist frequency = 0.5). The filter will cut off the
|
||||||
|
/// frequencies than that.
|
||||||
|
void setCutoffFreq(double newCutoffFreq);
|
||||||
|
|
||||||
|
/// Sets number of FIR filter taps, i.e. ~filter complexity
|
||||||
|
void setLength(uint newLength);
|
||||||
|
|
||||||
|
uint getLength() const;
|
||||||
|
|
||||||
|
/// Applies the filter to the given sequence of samples.
|
||||||
|
/// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
|
/// smaller than the amount of input samples.
|
||||||
|
uint evaluate(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples,
|
||||||
|
uint numChannels) const;
|
||||||
|
|
||||||
|
/// Applies the filter to the given src & dest pipes, so that processed amount of
|
||||||
|
/// samples get removed from src, and produced amount added to dest
|
||||||
|
/// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
|
/// smaller than the amount of input samples.
|
||||||
|
uint evaluate(FIFOSampleBuffer &dest,
|
||||||
|
FIFOSampleBuffer &src) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
274
src/FIFOSampleBuffer.cpp
Normal file
274
src/FIFOSampleBuffer.cpp
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// A buffer class for temporarily storaging sound samples, operates as a
|
||||||
|
/// first-in-first-out pipe.
|
||||||
|
///
|
||||||
|
/// Samples are added to the end of the sample buffer with the 'putSamples'
|
||||||
|
/// function, and are received from the beginning of the buffer by calling
|
||||||
|
/// the 'receiveSamples' function. The class automatically removes the
|
||||||
|
/// outputted samples from the buffer, as well as grows the buffer size
|
||||||
|
/// whenever necessary.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "FIFOSampleBuffer.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
|
||||||
|
{
|
||||||
|
assert(numChannels > 0);
|
||||||
|
sizeInBytes = 0; // reasonable initial value
|
||||||
|
buffer = NULL;
|
||||||
|
bufferUnaligned = NULL;
|
||||||
|
samplesInBuffer = 0;
|
||||||
|
bufferPos = 0;
|
||||||
|
channels = (uint)numChannels;
|
||||||
|
ensureCapacity(32); // allocate initial capacity
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
FIFOSampleBuffer::~FIFOSampleBuffer()
|
||||||
|
{
|
||||||
|
delete[] bufferUnaligned;
|
||||||
|
bufferUnaligned = NULL;
|
||||||
|
buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets number of channels, 1 = mono, 2 = stereo
|
||||||
|
void FIFOSampleBuffer::setChannels(int numChannels)
|
||||||
|
{
|
||||||
|
uint usedBytes;
|
||||||
|
|
||||||
|
assert(numChannels > 0);
|
||||||
|
usedBytes = channels * samplesInBuffer;
|
||||||
|
channels = (uint)numChannels;
|
||||||
|
samplesInBuffer = usedBytes / channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
|
||||||
|
// zeroes this pointer by copying samples from the 'bufferPos' pointer
|
||||||
|
// location on to the beginning of the buffer.
|
||||||
|
void FIFOSampleBuffer::rewind()
|
||||||
|
{
|
||||||
|
if (buffer && bufferPos)
|
||||||
|
{
|
||||||
|
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
||||||
|
// the sample buffer.
|
||||||
|
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
||||||
|
{
|
||||||
|
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
|
||||||
|
samplesInBuffer += nSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Increases the number of samples in the buffer without copying any actual
|
||||||
|
// samples.
|
||||||
|
//
|
||||||
|
// This function is used to update the number of samples in the sample buffer
|
||||||
|
// when accessing the buffer directly with 'ptrEnd' function. Please be
|
||||||
|
// careful though!
|
||||||
|
void FIFOSampleBuffer::putSamples(uint nSamples)
|
||||||
|
{
|
||||||
|
uint req;
|
||||||
|
|
||||||
|
req = samplesInBuffer + nSamples;
|
||||||
|
ensureCapacity(req);
|
||||||
|
samplesInBuffer += nSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns a pointer to the end of the used part of the sample buffer (i.e.
|
||||||
|
// where the new samples are to be inserted). This function may be used for
|
||||||
|
// inserting new samples into the sample buffer directly. Please be careful!
|
||||||
|
//
|
||||||
|
// Parameter 'slackCapacity' tells the function how much free capacity (in
|
||||||
|
// terms of samples) there _at least_ should be, in order to the caller to
|
||||||
|
// succesfully insert all the required samples to the buffer. When necessary,
|
||||||
|
// the function grows the buffer size to comply with this requirement.
|
||||||
|
//
|
||||||
|
// When using this function as means for inserting new samples, also remember
|
||||||
|
// to increase the sample count afterwards, by calling the
|
||||||
|
// 'putSamples(numSamples)' function.
|
||||||
|
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
|
||||||
|
{
|
||||||
|
ensureCapacity(samplesInBuffer + slackCapacity);
|
||||||
|
return buffer + samplesInBuffer * channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns a pointer to the beginning of the currently non-outputted samples.
|
||||||
|
// This function is provided for accessing the output samples directly.
|
||||||
|
// Please be careful!
|
||||||
|
//
|
||||||
|
// When using this function to output samples, also remember to 'remove' the
|
||||||
|
// outputted samples from the buffer by calling the
|
||||||
|
// 'receiveSamples(numSamples)' function
|
||||||
|
SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
|
||||||
|
{
|
||||||
|
assert(buffer);
|
||||||
|
return buffer + bufferPos * channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ensures that the buffer has enought capacity, i.e. space for _at least_
|
||||||
|
// 'capacityRequirement' number of samples. The buffer is grown in steps of
|
||||||
|
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
|
||||||
|
// as well as to round the buffer size up to the virtual memory page size.
|
||||||
|
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
|
||||||
|
{
|
||||||
|
SAMPLETYPE *tempUnaligned, *temp;
|
||||||
|
|
||||||
|
if (capacityRequirement > getCapacity())
|
||||||
|
{
|
||||||
|
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
|
||||||
|
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
|
||||||
|
assert(sizeInBytes % 2 == 0);
|
||||||
|
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
|
||||||
|
if (tempUnaligned == NULL)
|
||||||
|
{
|
||||||
|
ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
|
||||||
|
}
|
||||||
|
// Align the buffer to begin at 16byte cache line boundary for optimal performance
|
||||||
|
temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned);
|
||||||
|
if (samplesInBuffer)
|
||||||
|
{
|
||||||
|
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
|
||||||
|
}
|
||||||
|
delete[] bufferUnaligned;
|
||||||
|
buffer = temp;
|
||||||
|
bufferUnaligned = tempUnaligned;
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// simply rewind the buffer (if necessary)
|
||||||
|
rewind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the current buffer capacity in terms of samples
|
||||||
|
uint FIFOSampleBuffer::getCapacity() const
|
||||||
|
{
|
||||||
|
return sizeInBytes / (channels * sizeof(SAMPLETYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the number of samples currently in the buffer
|
||||||
|
uint FIFOSampleBuffer::numSamples() const
|
||||||
|
{
|
||||||
|
return samplesInBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Output samples from beginning of the sample buffer. Copies demanded number
|
||||||
|
// of samples to output and removes them from the sample buffer. If there
|
||||||
|
// are less than 'numsample' samples in the buffer, returns all available.
|
||||||
|
//
|
||||||
|
// Returns number of samples copied.
|
||||||
|
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
|
||||||
|
{
|
||||||
|
uint num;
|
||||||
|
|
||||||
|
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
|
||||||
|
|
||||||
|
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
|
||||||
|
return receiveSamples(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Removes samples from the beginning of the sample buffer without copying them
|
||||||
|
// anywhere. Used to reduce the number of samples in the buffer, when accessing
|
||||||
|
// the sample buffer with the 'ptrBegin' function.
|
||||||
|
uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
|
||||||
|
{
|
||||||
|
if (maxSamples >= samplesInBuffer)
|
||||||
|
{
|
||||||
|
uint temp;
|
||||||
|
|
||||||
|
temp = samplesInBuffer;
|
||||||
|
samplesInBuffer = 0;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
samplesInBuffer -= maxSamples;
|
||||||
|
bufferPos += maxSamples;
|
||||||
|
|
||||||
|
return maxSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns nonzero if the sample buffer is empty
|
||||||
|
int FIFOSampleBuffer::isEmpty() const
|
||||||
|
{
|
||||||
|
return (samplesInBuffer == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clears the sample buffer
|
||||||
|
void FIFOSampleBuffer::clear()
|
||||||
|
{
|
||||||
|
samplesInBuffer = 0;
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
|
/// Returns adjusted amount of samples
|
||||||
|
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
|
||||||
|
{
|
||||||
|
if (numSamples < samplesInBuffer)
|
||||||
|
{
|
||||||
|
samplesInBuffer = numSamples;
|
||||||
|
}
|
||||||
|
return samplesInBuffer;
|
||||||
|
}
|
||||||
|
|
328
src/FIRFilter.cpp
Normal file
328
src/FIRFilter.cpp
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// General FIR digital filter routines with MMX optimization.
|
||||||
|
///
|
||||||
|
/// Note : MMX optimized functions reside in a separate, platform-specific file,
|
||||||
|
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: FIRFilter.cpp 202 2015-02-21 21:24:29Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "FIRFilter.h"
|
||||||
|
#include "cpu_detect.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Implementation of the class 'FIRFilter'
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
FIRFilter::FIRFilter()
|
||||||
|
{
|
||||||
|
resultDivFactor = 0;
|
||||||
|
resultDivider = 0;
|
||||||
|
length = 0;
|
||||||
|
lengthDiv8 = 0;
|
||||||
|
filterCoeffs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FIRFilter::~FIRFilter()
|
||||||
|
{
|
||||||
|
delete[] filterCoeffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usual C-version of the filter routine for stereo sound
|
||||||
|
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
||||||
|
{
|
||||||
|
int j, end;
|
||||||
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
// when using floating point samples, use a scaler instead of a divider
|
||||||
|
// because division is much slower operation than multiplying.
|
||||||
|
double dScaler = 1.0 / (double)resultDivider;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(length != 0);
|
||||||
|
assert(src != NULL);
|
||||||
|
assert(dest != NULL);
|
||||||
|
assert(filterCoeffs != NULL);
|
||||||
|
|
||||||
|
end = 2 * (numSamples - length);
|
||||||
|
|
||||||
|
#pragma omp parallel for
|
||||||
|
for (j = 0; j < end; j += 2)
|
||||||
|
{
|
||||||
|
const SAMPLETYPE *ptr;
|
||||||
|
LONG_SAMPLETYPE suml, sumr;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
suml = sumr = 0;
|
||||||
|
ptr = src + j;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i += 4)
|
||||||
|
{
|
||||||
|
// loop is unrolled by factor of 4 here for efficiency
|
||||||
|
suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
|
||||||
|
ptr[2 * i + 2] * filterCoeffs[i + 1] +
|
||||||
|
ptr[2 * i + 4] * filterCoeffs[i + 2] +
|
||||||
|
ptr[2 * i + 6] * filterCoeffs[i + 3];
|
||||||
|
sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
|
||||||
|
ptr[2 * i + 3] * filterCoeffs[i + 1] +
|
||||||
|
ptr[2 * i + 5] * filterCoeffs[i + 2] +
|
||||||
|
ptr[2 * i + 7] * filterCoeffs[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
suml >>= resultDivFactor;
|
||||||
|
sumr >>= resultDivFactor;
|
||||||
|
// saturate to 16 bit integer limits
|
||||||
|
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
|
||||||
|
// saturate to 16 bit integer limits
|
||||||
|
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
|
||||||
|
#else
|
||||||
|
suml *= dScaler;
|
||||||
|
sumr *= dScaler;
|
||||||
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
dest[j] = (SAMPLETYPE)suml;
|
||||||
|
dest[j + 1] = (SAMPLETYPE)sumr;
|
||||||
|
}
|
||||||
|
return numSamples - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Usual C-version of the filter routine for mono sound
|
||||||
|
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
||||||
|
{
|
||||||
|
int j, end;
|
||||||
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
// when using floating point samples, use a scaler instead of a divider
|
||||||
|
// because division is much slower operation than multiplying.
|
||||||
|
double dScaler = 1.0 / (double)resultDivider;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(length != 0);
|
||||||
|
|
||||||
|
end = numSamples - length;
|
||||||
|
#pragma omp parallel for
|
||||||
|
for (j = 0; j < end; j ++)
|
||||||
|
{
|
||||||
|
const SAMPLETYPE *pSrc = src + j;
|
||||||
|
LONG_SAMPLETYPE sum;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for (i = 0; i < length; i += 4)
|
||||||
|
{
|
||||||
|
// loop is unrolled by factor of 4 here for efficiency
|
||||||
|
sum += pSrc[i + 0] * filterCoeffs[i + 0] +
|
||||||
|
pSrc[i + 1] * filterCoeffs[i + 1] +
|
||||||
|
pSrc[i + 2] * filterCoeffs[i + 2] +
|
||||||
|
pSrc[i + 3] * filterCoeffs[i + 3];
|
||||||
|
}
|
||||||
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
sum >>= resultDivFactor;
|
||||||
|
// saturate to 16 bit integer limits
|
||||||
|
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
|
||||||
|
#else
|
||||||
|
sum *= dScaler;
|
||||||
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
dest[j] = (SAMPLETYPE)sum;
|
||||||
|
}
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
|
||||||
|
{
|
||||||
|
int j, end;
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
// when using floating point samples, use a scaler instead of a divider
|
||||||
|
// because division is much slower operation than multiplying.
|
||||||
|
double dScaler = 1.0 / (double)resultDivider;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(length != 0);
|
||||||
|
assert(src != NULL);
|
||||||
|
assert(dest != NULL);
|
||||||
|
assert(filterCoeffs != NULL);
|
||||||
|
assert(numChannels < 16);
|
||||||
|
|
||||||
|
end = numChannels * (numSamples - length);
|
||||||
|
|
||||||
|
#pragma omp parallel for
|
||||||
|
for (j = 0; j < end; j += numChannels)
|
||||||
|
{
|
||||||
|
const SAMPLETYPE *ptr;
|
||||||
|
LONG_SAMPLETYPE sums[16];
|
||||||
|
uint c, i;
|
||||||
|
|
||||||
|
for (c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
sums[c] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = src + j;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i ++)
|
||||||
|
{
|
||||||
|
SAMPLETYPE coef=filterCoeffs[i];
|
||||||
|
for (c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
sums[c] += ptr[0] * coef;
|
||||||
|
ptr ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
sums[c] >>= resultDivFactor;
|
||||||
|
#else
|
||||||
|
sums[c] *= dScaler;
|
||||||
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
dest[j+c] = (SAMPLETYPE)sums[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numSamples - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set filter coeffiecients and length.
|
||||||
|
//
|
||||||
|
// Throws an exception if filter length isn't divisible by 8
|
||||||
|
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
|
||||||
|
{
|
||||||
|
assert(newLength > 0);
|
||||||
|
if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");
|
||||||
|
|
||||||
|
lengthDiv8 = newLength / 8;
|
||||||
|
length = lengthDiv8 * 8;
|
||||||
|
assert(length == newLength);
|
||||||
|
|
||||||
|
resultDivFactor = uResultDivFactor;
|
||||||
|
resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
|
||||||
|
|
||||||
|
delete[] filterCoeffs;
|
||||||
|
filterCoeffs = new SAMPLETYPE[length];
|
||||||
|
memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint FIRFilter::getLength() const
|
||||||
|
{
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Applies the filter to the given sequence of samples.
|
||||||
|
//
|
||||||
|
// Note : The amount of outputted samples is by value of 'filter_length'
|
||||||
|
// smaller than the amount of input samples.
|
||||||
|
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
|
||||||
|
{
|
||||||
|
assert(length > 0);
|
||||||
|
assert(lengthDiv8 * 8 == length);
|
||||||
|
|
||||||
|
if (numSamples < length) return 0;
|
||||||
|
|
||||||
|
#ifndef USE_MULTICH_ALWAYS
|
||||||
|
if (numChannels == 1)
|
||||||
|
{
|
||||||
|
return evaluateFilterMono(dest, src, numSamples);
|
||||||
|
}
|
||||||
|
else if (numChannels == 2)
|
||||||
|
{
|
||||||
|
return evaluateFilterStereo(dest, src, numSamples);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // USE_MULTICH_ALWAYS
|
||||||
|
{
|
||||||
|
assert(numChannels > 0);
|
||||||
|
return evaluateFilterMulti(dest, src, numSamples, numChannels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
|
// depending on if we've a MMX-capable CPU available or not.
|
||||||
|
void * FIRFilter::operator new(size_t s)
|
||||||
|
{
|
||||||
|
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
|
||||||
|
ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
|
||||||
|
return newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FIRFilter * FIRFilter::newInstance()
|
||||||
|
{
|
||||||
|
uint uExtensions;
|
||||||
|
|
||||||
|
uExtensions = detectCPUextensions();
|
||||||
|
|
||||||
|
// Check if MMX/SSE instruction set extensions supported by CPU
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
|
// MMX routines available only with integer sample types
|
||||||
|
if (uExtensions & SUPPORT_MMX)
|
||||||
|
{
|
||||||
|
return ::new FIRFilterMMX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
|
if (uExtensions & SUPPORT_SSE)
|
||||||
|
{
|
||||||
|
// SSE support
|
||||||
|
return ::new FIRFilterSSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|
||||||
|
{
|
||||||
|
// ISA optimizations not supported, use plain C version
|
||||||
|
return ::new FIRFilter;
|
||||||
|
}
|
||||||
|
}
|
146
src/FIRFilter.h
Normal file
146
src/FIRFilter.h
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// General FIR digital filter routines with MMX optimization.
|
||||||
|
///
|
||||||
|
/// Note : MMX optimized functions reside in a separate, platform-specific file,
|
||||||
|
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: FIRFilter.h 202 2015-02-21 21:24:29Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef FIRFilter_H
|
||||||
|
#define FIRFilter_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
class FIRFilter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// Number of FIR filter taps
|
||||||
|
uint length;
|
||||||
|
// Number of FIR filter taps divided by 8
|
||||||
|
uint lengthDiv8;
|
||||||
|
|
||||||
|
// Result divider factor in 2^k format
|
||||||
|
uint resultDivFactor;
|
||||||
|
|
||||||
|
// Result divider value.
|
||||||
|
SAMPLETYPE resultDivider;
|
||||||
|
|
||||||
|
// Memory for filter coefficients
|
||||||
|
SAMPLETYPE *filterCoeffs;
|
||||||
|
|
||||||
|
virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples) const;
|
||||||
|
virtual uint evaluateFilterMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples) const;
|
||||||
|
virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels);
|
||||||
|
|
||||||
|
public:
|
||||||
|
FIRFilter();
|
||||||
|
virtual ~FIRFilter();
|
||||||
|
|
||||||
|
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
|
/// depending on if we've a MMX-capable CPU available or not.
|
||||||
|
static void * operator new(size_t s);
|
||||||
|
|
||||||
|
static FIRFilter *newInstance();
|
||||||
|
|
||||||
|
/// Applies the filter to the given sequence of samples.
|
||||||
|
/// Note : The amount of outputted samples is by value of 'filter_length'
|
||||||
|
/// smaller than the amount of input samples.
|
||||||
|
///
|
||||||
|
/// \return Number of samples copied to 'dest'.
|
||||||
|
uint evaluate(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples,
|
||||||
|
uint numChannels);
|
||||||
|
|
||||||
|
uint getLength() const;
|
||||||
|
|
||||||
|
virtual void setCoefficients(const SAMPLETYPE *coeffs,
|
||||||
|
uint newLength,
|
||||||
|
uint uResultDivFactor);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Optional subclasses that implement CPU-specific optimizations:
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
||||||
|
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
|
||||||
|
class FIRFilterMMX : public FIRFilter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
short *filterCoeffsUnalign;
|
||||||
|
short *filterCoeffsAlign;
|
||||||
|
|
||||||
|
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;
|
||||||
|
public:
|
||||||
|
FIRFilterMMX();
|
||||||
|
~FIRFilterMMX();
|
||||||
|
|
||||||
|
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
|
/// Class that implements SSE optimized functions exclusive for floating point samples type.
|
||||||
|
class FIRFilterSSE : public FIRFilter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
float *filterCoeffsUnalign;
|
||||||
|
float *filterCoeffsAlign;
|
||||||
|
|
||||||
|
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
|
||||||
|
public:
|
||||||
|
FIRFilterSSE();
|
||||||
|
~FIRFilterSSE();
|
||||||
|
|
||||||
|
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FIRFilter_H
|
300
src/InterpolateLinear.cpp
Normal file
300
src/InterpolateLinear.cpp
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Linear interpolation algorithm.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// $Id: InterpolateLinear.cpp 225 2015-07-26 14:45:48Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "InterpolateLinear.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// InterpolateLinearInteger - integer arithmetic implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
/// fixed-point interpolation routine precision
|
||||||
|
#define SCALE 65536
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase()
|
||||||
|
{
|
||||||
|
// Notice: use local function calling syntax for sake of clarity,
|
||||||
|
// to indicate the fact that C++ constructor can't call virtual functions.
|
||||||
|
resetRegisters();
|
||||||
|
setRate(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpolateLinearInteger::resetRegisters()
|
||||||
|
{
|
||||||
|
iFract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Mono' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
LONG_SAMPLETYPE temp;
|
||||||
|
|
||||||
|
assert(iFract < SCALE);
|
||||||
|
|
||||||
|
temp = (SCALE - iFract) * src[0] + iFract * src[1];
|
||||||
|
dest[i] = (SAMPLETYPE)(temp / SCALE);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
iFract += iRate;
|
||||||
|
|
||||||
|
int iWhole = iFract / SCALE;
|
||||||
|
iFract -= iWhole * SCALE;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += iWhole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Stereo' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
LONG_SAMPLETYPE temp0;
|
||||||
|
LONG_SAMPLETYPE temp1;
|
||||||
|
|
||||||
|
assert(iFract < SCALE);
|
||||||
|
|
||||||
|
temp0 = (SCALE - iFract) * src[0] + iFract * src[2];
|
||||||
|
temp1 = (SCALE - iFract) * src[1] + iFract * src[3];
|
||||||
|
dest[0] = (SAMPLETYPE)(temp0 / SCALE);
|
||||||
|
dest[1] = (SAMPLETYPE)(temp1 / SCALE);
|
||||||
|
dest += 2;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
iFract += iRate;
|
||||||
|
|
||||||
|
int iWhole = iFract / SCALE;
|
||||||
|
iFract -= iWhole * SCALE;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += 2*iWhole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
LONG_SAMPLETYPE temp, vol1;
|
||||||
|
|
||||||
|
assert(iFract < SCALE);
|
||||||
|
vol1 = (SCALE - iFract);
|
||||||
|
for (int c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
temp = vol1 * src[c] + iFract * src[c + numChannels];
|
||||||
|
dest[0] = (SAMPLETYPE)(temp / SCALE);
|
||||||
|
dest ++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
iFract += iRate;
|
||||||
|
|
||||||
|
int iWhole = iFract / SCALE;
|
||||||
|
iFract -= iWhole * SCALE;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += iWhole * numChannels;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
||||||
|
// iRate, larger faster iRates.
|
||||||
|
void InterpolateLinearInteger::setRate(double newRate)
|
||||||
|
{
|
||||||
|
iRate = (int)(newRate * SCALE + 0.5);
|
||||||
|
TransposerBase::setRate(newRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// InterpolateLinearFloat - floating point arithmetic implementation
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase()
|
||||||
|
{
|
||||||
|
// Notice: use local function calling syntax for sake of clarity,
|
||||||
|
// to indicate the fact that C++ constructor can't call virtual functions.
|
||||||
|
resetRegisters();
|
||||||
|
setRate(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpolateLinearFloat::resetRegisters()
|
||||||
|
{
|
||||||
|
fract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Mono' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
double out;
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
out = (1.0 - fract) * src[0] + fract * src[1];
|
||||||
|
dest[i] = (SAMPLETYPE)out;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
src += whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Mono' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
double out0, out1;
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
out0 = (1.0 - fract) * src[0] + fract * src[2];
|
||||||
|
out1 = (1.0 - fract) * src[1] + fract * src[3];
|
||||||
|
dest[2*i] = (SAMPLETYPE)out0;
|
||||||
|
dest[2*i+1] = (SAMPLETYPE)out1;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
src += 2*whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
float temp, vol1, fract_float;
|
||||||
|
|
||||||
|
vol1 = (float)(1.0 - fract);
|
||||||
|
fract_float = (float)fract;
|
||||||
|
for (int c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
temp = vol1 * src[c] + fract_float * src[c + numChannels];
|
||||||
|
*dest = (SAMPLETYPE)temp;
|
||||||
|
dest ++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
fract += rate;
|
||||||
|
|
||||||
|
int iWhole = (int)fract;
|
||||||
|
fract -= iWhole;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += iWhole * numChannels;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
92
src/InterpolateLinear.h
Normal file
92
src/InterpolateLinear.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Linear interpolation routine.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// $Id: InterpolateLinear.h 225 2015-07-26 14:45:48Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _InterpolateLinear_H_
|
||||||
|
#define _InterpolateLinear_H_
|
||||||
|
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Linear transposer class that uses integer arithmetics
|
||||||
|
class InterpolateLinearInteger : public TransposerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int iFract;
|
||||||
|
int iRate;
|
||||||
|
|
||||||
|
virtual void resetRegisters();
|
||||||
|
|
||||||
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples);
|
||||||
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples);
|
||||||
|
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
|
||||||
|
public:
|
||||||
|
InterpolateLinearInteger();
|
||||||
|
|
||||||
|
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
|
||||||
|
/// rate, larger faster rates.
|
||||||
|
virtual void setRate(double newRate);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Linear transposer class that uses floating point arithmetics
|
||||||
|
class InterpolateLinearFloat : public TransposerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
double fract;
|
||||||
|
|
||||||
|
virtual void resetRegisters();
|
||||||
|
|
||||||
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples);
|
||||||
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples);
|
||||||
|
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
|
||||||
|
|
||||||
|
public:
|
||||||
|
InterpolateLinearFloat();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
300
src/RateTransposer.cpp
Normal file
300
src/RateTransposer.cpp
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
||||||
|
/// together with anti-alias filtering (first order interpolation with anti-
|
||||||
|
/// alias filtering should be quite adequate for this application)
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: RateTransposer.cpp 225 2015-07-26 14:45:48Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "InterpolateLinear.h"
|
||||||
|
#include "AAFilter.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
// Define default interpolation algorithm here
|
||||||
|
TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
|
||||||
|
{
|
||||||
|
bUseAAFilter = true;
|
||||||
|
|
||||||
|
// Instantiates the anti-alias filter
|
||||||
|
pAAFilter = new AAFilter(64);
|
||||||
|
pTransposer = TransposerBase::newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RateTransposer::~RateTransposer()
|
||||||
|
{
|
||||||
|
delete pAAFilter;
|
||||||
|
delete pTransposer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
||||||
|
void RateTransposer::enableAAFilter(bool newMode)
|
||||||
|
{
|
||||||
|
bUseAAFilter = newMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns nonzero if anti-alias filter is enabled.
|
||||||
|
bool RateTransposer::isAAFilterEnabled() const
|
||||||
|
{
|
||||||
|
return bUseAAFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AAFilter *RateTransposer::getAAFilter()
|
||||||
|
{
|
||||||
|
return pAAFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
||||||
|
// iRate, larger faster iRates.
|
||||||
|
void RateTransposer::setRate(double newRate)
|
||||||
|
{
|
||||||
|
double fCutoff;
|
||||||
|
|
||||||
|
pTransposer->setRate(newRate);
|
||||||
|
|
||||||
|
// design a new anti-alias filter
|
||||||
|
if (newRate > 1.0)
|
||||||
|
{
|
||||||
|
fCutoff = 0.5 / newRate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fCutoff = 0.5 * newRate;
|
||||||
|
}
|
||||||
|
pAAFilter->setCutoffFreq(fCutoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
|
||||||
|
// the input of the object.
|
||||||
|
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
||||||
|
{
|
||||||
|
processSamples(samples, nSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes sample rate by applying anti-alias filter to prevent folding.
|
||||||
|
// Returns amount of samples returned in the "dest" buffer.
|
||||||
|
// The maximum amount of samples that can be returned at a time is set by
|
||||||
|
// the 'set_returnBuffer_size' function.
|
||||||
|
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
|
||||||
|
{
|
||||||
|
uint count;
|
||||||
|
|
||||||
|
if (nSamples == 0) return;
|
||||||
|
|
||||||
|
// Store samples to input buffer
|
||||||
|
inputBuffer.putSamples(src, nSamples);
|
||||||
|
|
||||||
|
// If anti-alias filter is turned off, simply transpose without applying
|
||||||
|
// the filter
|
||||||
|
if (bUseAAFilter == false)
|
||||||
|
{
|
||||||
|
count = pTransposer->transpose(outputBuffer, inputBuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pAAFilter);
|
||||||
|
|
||||||
|
// Transpose with anti-alias filter
|
||||||
|
if (pTransposer->rate < 1.0f)
|
||||||
|
{
|
||||||
|
// If the parameter 'Rate' value is smaller than 1, first transpose
|
||||||
|
// the samples and then apply the anti-alias filter to remove aliasing.
|
||||||
|
|
||||||
|
// Transpose the samples, store the result to end of "midBuffer"
|
||||||
|
pTransposer->transpose(midBuffer, inputBuffer);
|
||||||
|
|
||||||
|
// Apply the anti-alias filter for transposed samples in midBuffer
|
||||||
|
pAAFilter->evaluate(outputBuffer, midBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the parameter 'Rate' value is larger than 1, first apply the
|
||||||
|
// anti-alias filter to remove high frequencies (prevent them from folding
|
||||||
|
// over the lover frequencies), then transpose.
|
||||||
|
|
||||||
|
// Apply the anti-alias filter for samples in inputBuffer
|
||||||
|
pAAFilter->evaluate(midBuffer, inputBuffer);
|
||||||
|
|
||||||
|
// Transpose the AA-filtered samples in "midBuffer"
|
||||||
|
pTransposer->transpose(outputBuffer, midBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
|
void RateTransposer::setChannels(int nChannels)
|
||||||
|
{
|
||||||
|
assert(nChannels > 0);
|
||||||
|
|
||||||
|
if (pTransposer->numChannels == nChannels) return;
|
||||||
|
pTransposer->setChannels(nChannels);
|
||||||
|
|
||||||
|
inputBuffer.setChannels(nChannels);
|
||||||
|
midBuffer.setChannels(nChannels);
|
||||||
|
outputBuffer.setChannels(nChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clears all the samples in the object
|
||||||
|
void RateTransposer::clear()
|
||||||
|
{
|
||||||
|
outputBuffer.clear();
|
||||||
|
midBuffer.clear();
|
||||||
|
inputBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
int RateTransposer::isEmpty() const
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = FIFOProcessor::isEmpty();
|
||||||
|
if (res == 0) return 0;
|
||||||
|
return inputBuffer.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// TransposerBase - Base class for interpolation
|
||||||
|
//
|
||||||
|
|
||||||
|
// static function to set interpolation algorithm
|
||||||
|
void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
|
||||||
|
{
|
||||||
|
TransposerBase::algorithm = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// Returns the number of samples returned in the "dest" buffer
|
||||||
|
int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
|
||||||
|
{
|
||||||
|
int numSrcSamples = src.numSamples();
|
||||||
|
int sizeDemand = (int)((double)numSrcSamples / rate) + 8;
|
||||||
|
int numOutput;
|
||||||
|
SAMPLETYPE *psrc = src.ptrBegin();
|
||||||
|
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
|
||||||
|
|
||||||
|
#ifndef USE_MULTICH_ALWAYS
|
||||||
|
if (numChannels == 1)
|
||||||
|
{
|
||||||
|
numOutput = transposeMono(pdest, psrc, numSrcSamples);
|
||||||
|
}
|
||||||
|
else if (numChannels == 2)
|
||||||
|
{
|
||||||
|
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // USE_MULTICH_ALWAYS
|
||||||
|
{
|
||||||
|
assert(numChannels > 0);
|
||||||
|
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
|
||||||
|
}
|
||||||
|
dest.putSamples(numOutput);
|
||||||
|
src.receiveSamples(numSrcSamples);
|
||||||
|
return numOutput;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TransposerBase::TransposerBase()
|
||||||
|
{
|
||||||
|
numChannels = 0;
|
||||||
|
rate = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TransposerBase::~TransposerBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TransposerBase::setChannels(int channels)
|
||||||
|
{
|
||||||
|
numChannels = channels;
|
||||||
|
resetRegisters();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TransposerBase::setRate(double newRate)
|
||||||
|
{
|
||||||
|
rate = newRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static factory function
|
||||||
|
TransposerBase *TransposerBase::newInstance()
|
||||||
|
{
|
||||||
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
// Notice: For integer arithmetics support only linear algorithm (due to simplest calculus)
|
||||||
|
return ::new InterpolateLinearInteger;
|
||||||
|
#else
|
||||||
|
switch (algorithm)
|
||||||
|
{
|
||||||
|
case LINEAR:
|
||||||
|
return new InterpolateLinearFloat;
|
||||||
|
|
||||||
|
case CUBIC:
|
||||||
|
return new InterpolateCubic;
|
||||||
|
|
||||||
|
case SHANNON:
|
||||||
|
return new InterpolateShannon;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
179
src/RateTransposer.h
Normal file
179
src/RateTransposer.h
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
||||||
|
/// together with anti-alias filtering (first order interpolation with anti-
|
||||||
|
/// alias filtering should be quite adequate for this application).
|
||||||
|
///
|
||||||
|
/// Use either of the derived classes of 'RateTransposerInteger' or
|
||||||
|
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
|
||||||
|
/// algorithm implementation.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: RateTransposer.h 225 2015-07-26 14:45:48Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef RateTransposer_H
|
||||||
|
#define RateTransposer_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "AAFilter.h"
|
||||||
|
#include "FIFOSamplePipe.h"
|
||||||
|
#include "FIFOSampleBuffer.h"
|
||||||
|
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc)
|
||||||
|
class TransposerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ALGORITHM {
|
||||||
|
LINEAR = 0,
|
||||||
|
CUBIC,
|
||||||
|
SHANNON
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void resetRegisters() = 0;
|
||||||
|
|
||||||
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) = 0;
|
||||||
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) = 0;
|
||||||
|
virtual int transposeMulti(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) = 0;
|
||||||
|
|
||||||
|
static ALGORITHM algorithm;
|
||||||
|
|
||||||
|
public:
|
||||||
|
double rate;
|
||||||
|
int numChannels;
|
||||||
|
|
||||||
|
TransposerBase();
|
||||||
|
virtual ~TransposerBase();
|
||||||
|
|
||||||
|
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
|
||||||
|
virtual void setRate(double newRate);
|
||||||
|
virtual void setChannels(int channels);
|
||||||
|
|
||||||
|
// static factory function
|
||||||
|
static TransposerBase *newInstance();
|
||||||
|
|
||||||
|
// static function to set interpolation algorithm
|
||||||
|
static void setAlgorithm(ALGORITHM a);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// A common linear samplerate transposer class.
|
||||||
|
///
|
||||||
|
class RateTransposer : public FIFOProcessor
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/// Anti-alias filter object
|
||||||
|
AAFilter *pAAFilter;
|
||||||
|
TransposerBase *pTransposer;
|
||||||
|
|
||||||
|
/// Buffer for collecting samples to feed the anti-alias filter between
|
||||||
|
/// two batches
|
||||||
|
FIFOSampleBuffer inputBuffer;
|
||||||
|
|
||||||
|
/// Buffer for keeping samples between transposing & anti-alias filter
|
||||||
|
FIFOSampleBuffer midBuffer;
|
||||||
|
|
||||||
|
/// Output sample buffer
|
||||||
|
FIFOSampleBuffer outputBuffer;
|
||||||
|
|
||||||
|
bool bUseAAFilter;
|
||||||
|
|
||||||
|
|
||||||
|
/// Transposes sample rate by applying anti-alias filter to prevent folding.
|
||||||
|
/// Returns amount of samples returned in the "dest" buffer.
|
||||||
|
/// The maximum amount of samples that can be returned at a time is set by
|
||||||
|
/// the 'set_returnBuffer_size' function.
|
||||||
|
void processSamples(const SAMPLETYPE *src,
|
||||||
|
uint numSamples);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RateTransposer();
|
||||||
|
virtual ~RateTransposer();
|
||||||
|
|
||||||
|
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
|
/// depending on if we're to use integer or floating point arithmetics.
|
||||||
|
// static void *operator new(size_t s);
|
||||||
|
|
||||||
|
/// Use this function instead of "new" operator to create a new instance of this class.
|
||||||
|
/// This function automatically chooses a correct implementation, depending on if
|
||||||
|
/// integer ot floating point arithmetics are to be used.
|
||||||
|
// static RateTransposer *newInstance();
|
||||||
|
|
||||||
|
/// Returns the output buffer object
|
||||||
|
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
||||||
|
|
||||||
|
/// Returns the store buffer object
|
||||||
|
// FIFOSamplePipe *getStore() { return &storeBuffer; };
|
||||||
|
|
||||||
|
/// Return anti-alias filter object
|
||||||
|
AAFilter *getAAFilter();
|
||||||
|
|
||||||
|
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
||||||
|
void enableAAFilter(bool newMode);
|
||||||
|
|
||||||
|
/// Returns nonzero if anti-alias filter is enabled.
|
||||||
|
bool isAAFilterEnabled() const;
|
||||||
|
|
||||||
|
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
|
||||||
|
/// rate, larger faster rates.
|
||||||
|
virtual void setRate(double newRate);
|
||||||
|
|
||||||
|
/// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
|
void setChannels(int channels);
|
||||||
|
|
||||||
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
||||||
|
/// the input of the object.
|
||||||
|
void putSamples(const SAMPLETYPE *samples, uint numSamples);
|
||||||
|
|
||||||
|
/// Clears all the samples in the object
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
int isEmpty() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
526
src/SoundTouch.cpp
Normal file
526
src/SoundTouch.cpp
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
|
||||||
|
///
|
||||||
|
/// Notes:
|
||||||
|
/// - Initialize the SoundTouch object instance by setting up the sound stream
|
||||||
|
/// parameters with functions 'setSampleRate' and 'setChannels', then set
|
||||||
|
/// desired tempo/pitch/rate settings with the corresponding functions.
|
||||||
|
///
|
||||||
|
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
|
||||||
|
/// samples that are to be processed are fed into one of the pipe by calling
|
||||||
|
/// function 'putSamples', while the ready processed samples can be read
|
||||||
|
/// from the other end of the pipeline with function 'receiveSamples'.
|
||||||
|
///
|
||||||
|
/// - The SoundTouch processing classes require certain sized 'batches' of
|
||||||
|
/// samples in order to process the sound. For this reason the classes buffer
|
||||||
|
/// incoming samples until there are enough of samples available for
|
||||||
|
/// processing, then they carry out the processing step and consequently
|
||||||
|
/// make the processed samples available for outputting.
|
||||||
|
///
|
||||||
|
/// - For the above reason, the processing routines introduce a certain
|
||||||
|
/// 'latency' between the input and output, so that the samples input to
|
||||||
|
/// SoundTouch may not be immediately available in the output, and neither
|
||||||
|
/// the amount of outputtable samples may not immediately be in direct
|
||||||
|
/// relationship with the amount of previously input samples.
|
||||||
|
///
|
||||||
|
/// - The tempo/pitch/rate control parameters can be altered during processing.
|
||||||
|
/// Please notice though that they aren't currently protected by semaphores,
|
||||||
|
/// so in multi-thread application external semaphore protection may be
|
||||||
|
/// required.
|
||||||
|
///
|
||||||
|
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
|
||||||
|
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
|
||||||
|
/// tempo and pitch in the same ratio) of the sound. The third available control
|
||||||
|
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
|
||||||
|
/// combining the two other controls.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: SoundTouch.cpp 225 2015-07-26 14:45:48Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "SoundTouch.h"
|
||||||
|
#include "TDStretch.h"
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "cpu_detect.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
/// test if two floating point numbers are equal
|
||||||
|
#define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10)
|
||||||
|
|
||||||
|
|
||||||
|
/// Print library version string for autoconf
|
||||||
|
extern "C" void soundtouch_ac_test()
|
||||||
|
{
|
||||||
|
printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SoundTouch::SoundTouch()
|
||||||
|
{
|
||||||
|
// Initialize rate transposer and tempo changer instances
|
||||||
|
|
||||||
|
pRateTransposer = new RateTransposer();
|
||||||
|
pTDStretch = TDStretch::newInstance();
|
||||||
|
|
||||||
|
setOutPipe(pTDStretch);
|
||||||
|
|
||||||
|
rate = tempo = 0;
|
||||||
|
|
||||||
|
virtualPitch =
|
||||||
|
virtualRate =
|
||||||
|
virtualTempo = 1.0;
|
||||||
|
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
|
||||||
|
samplesExpectedOut = 0;
|
||||||
|
samplesOutput = 0;
|
||||||
|
|
||||||
|
channels = 0;
|
||||||
|
bSrateSet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SoundTouch::~SoundTouch()
|
||||||
|
{
|
||||||
|
delete pRateTransposer;
|
||||||
|
delete pTDStretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Get SoundTouch library version string
|
||||||
|
const char *SoundTouch::getVersionString()
|
||||||
|
{
|
||||||
|
static const char *_version = SOUNDTOUCH_VERSION;
|
||||||
|
|
||||||
|
return _version;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get SoundTouch library version Id
|
||||||
|
uint SoundTouch::getVersionId()
|
||||||
|
{
|
||||||
|
return SOUNDTOUCH_VERSION_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
|
void SoundTouch::setChannels(uint numChannels)
|
||||||
|
{
|
||||||
|
/*if (numChannels != 1 && numChannels != 2)
|
||||||
|
{
|
||||||
|
//ST_THROW_RT_ERROR("Illegal number of channels");
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
channels = numChannels;
|
||||||
|
pRateTransposer->setChannels((int)numChannels);
|
||||||
|
pTDStretch->setChannels((int)numChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new rate control value. Normal rate = 1.0, smaller values
|
||||||
|
// represent slower rate, larger faster rates.
|
||||||
|
void SoundTouch::setRate(double newRate)
|
||||||
|
{
|
||||||
|
virtualRate = newRate;
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new rate control value as a difference in percents compared
|
||||||
|
// to the original rate (-50 .. +100 %)
|
||||||
|
void SoundTouch::setRateChange(double newRate)
|
||||||
|
{
|
||||||
|
virtualRate = 1.0 + 0.01 * newRate;
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
||||||
|
// represent slower tempo, larger faster tempo.
|
||||||
|
void SoundTouch::setTempo(double newTempo)
|
||||||
|
{
|
||||||
|
virtualTempo = newTempo;
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new tempo control value as a difference in percents compared
|
||||||
|
// to the original tempo (-50 .. +100 %)
|
||||||
|
void SoundTouch::setTempoChange(double newTempo)
|
||||||
|
{
|
||||||
|
virtualTempo = 1.0 + 0.01 * newTempo;
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new pitch control value. Original pitch = 1.0, smaller values
|
||||||
|
// represent lower pitches, larger values higher pitch.
|
||||||
|
void SoundTouch::setPitch(double newPitch)
|
||||||
|
{
|
||||||
|
virtualPitch = newPitch;
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets pitch change in octaves compared to the original pitch
|
||||||
|
// (-1.00 .. +1.00)
|
||||||
|
void SoundTouch::setPitchOctaves(double newPitch)
|
||||||
|
{
|
||||||
|
virtualPitch = exp(0.69314718056 * newPitch);
|
||||||
|
calcEffectiveRateAndTempo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Sets pitch change in semi-tones compared to the original pitch
|
||||||
|
// (-12 .. +12)
|
||||||
|
void SoundTouch::setPitchSemiTones(int newPitch)
|
||||||
|
{
|
||||||
|
setPitchOctaves((double)newPitch / 12.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SoundTouch::setPitchSemiTones(double newPitch)
|
||||||
|
{
|
||||||
|
setPitchOctaves(newPitch / 12.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculates 'effective' rate and tempo values from the
|
||||||
|
// nominal control values.
|
||||||
|
void SoundTouch::calcEffectiveRateAndTempo()
|
||||||
|
{
|
||||||
|
double oldTempo = tempo;
|
||||||
|
double oldRate = rate;
|
||||||
|
|
||||||
|
tempo = virtualTempo / virtualPitch;
|
||||||
|
rate = virtualPitch * virtualRate;
|
||||||
|
|
||||||
|
if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);
|
||||||
|
if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);
|
||||||
|
|
||||||
|
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
|
||||||
|
if (rate <= 1.0f)
|
||||||
|
{
|
||||||
|
if (output != pTDStretch)
|
||||||
|
{
|
||||||
|
FIFOSamplePipe *tempoOut;
|
||||||
|
|
||||||
|
assert(output == pRateTransposer);
|
||||||
|
// move samples in the current output buffer to the output of pTDStretch
|
||||||
|
tempoOut = pTDStretch->getOutput();
|
||||||
|
tempoOut->moveSamples(*output);
|
||||||
|
// move samples in pitch transposer's store buffer to tempo changer's input
|
||||||
|
// deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore());
|
||||||
|
|
||||||
|
output = pTDStretch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (output != pRateTransposer)
|
||||||
|
{
|
||||||
|
FIFOSamplePipe *transOut;
|
||||||
|
|
||||||
|
assert(output == pTDStretch);
|
||||||
|
// move samples in the current output buffer to the output of pRateTransposer
|
||||||
|
transOut = pRateTransposer->getOutput();
|
||||||
|
transOut->moveSamples(*output);
|
||||||
|
// move samples in tempo changer's input to pitch transposer's input
|
||||||
|
pRateTransposer->moveSamples(*pTDStretch->getInput());
|
||||||
|
|
||||||
|
output = pRateTransposer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets sample rate.
|
||||||
|
void SoundTouch::setSampleRate(uint srate)
|
||||||
|
{
|
||||||
|
bSrateSet = true;
|
||||||
|
// set sample rate, leave other tempo changer parameters as they are.
|
||||||
|
pTDStretch->setParameters((int)srate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
||||||
|
// the input of the object.
|
||||||
|
void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
||||||
|
{
|
||||||
|
if (bSrateSet == false)
|
||||||
|
{
|
||||||
|
ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined");
|
||||||
|
}
|
||||||
|
else if (channels == 0)
|
||||||
|
{
|
||||||
|
ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transpose the rate of the new samples if necessary
|
||||||
|
/* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
|
||||||
|
if (rate == 1.0f)
|
||||||
|
{
|
||||||
|
// The rate value is same as the original, simply evaluate the tempo changer.
|
||||||
|
assert(output == pTDStretch);
|
||||||
|
if (pRateTransposer->isEmpty() == 0)
|
||||||
|
{
|
||||||
|
// yet flush the last samples in the pitch transposer buffer
|
||||||
|
// (may happen if 'rate' changes from a non-zero value to zero)
|
||||||
|
pTDStretch->moveSamples(*pRateTransposer);
|
||||||
|
}
|
||||||
|
pTDStretch->putSamples(samples, nSamples);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// accumulate how many samples are expected out from processing, given the current
|
||||||
|
// processing setting
|
||||||
|
samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo);
|
||||||
|
|
||||||
|
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
|
||||||
|
if (rate <= 1.0f)
|
||||||
|
{
|
||||||
|
// transpose the rate down, output the transposed sound to tempo changer buffer
|
||||||
|
assert(output == pTDStretch);
|
||||||
|
pRateTransposer->putSamples(samples, nSamples);
|
||||||
|
pTDStretch->moveSamples(*pRateTransposer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// evaluate the tempo changer, then transpose the rate up,
|
||||||
|
assert(output == pRateTransposer);
|
||||||
|
pTDStretch->putSamples(samples, nSamples);
|
||||||
|
pRateTransposer->moveSamples(*pTDStretch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Flushes the last samples from the processing pipeline to the output.
|
||||||
|
// Clears also the internal processing buffers.
|
||||||
|
//
|
||||||
|
// Note: This function is meant for extracting the last samples of a sound
|
||||||
|
// stream. This function may introduce additional blank samples in the end
|
||||||
|
// of the sound stream, and thus it's not recommended to call this function
|
||||||
|
// in the middle of a sound stream.
|
||||||
|
void SoundTouch::flush()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int numStillExpected;
|
||||||
|
SAMPLETYPE *buff = new SAMPLETYPE[128 * channels];
|
||||||
|
|
||||||
|
// how many samples are still expected to output
|
||||||
|
numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput);
|
||||||
|
|
||||||
|
memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE));
|
||||||
|
// "Push" the last active samples out from the processing pipeline by
|
||||||
|
// feeding blank samples into the processing pipeline until new,
|
||||||
|
// processed samples appear in the output (not however, more than
|
||||||
|
// 24ksamples in any case)
|
||||||
|
for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++)
|
||||||
|
{
|
||||||
|
putSamples(buff, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
adjustAmountOfSamples(numStillExpected);
|
||||||
|
|
||||||
|
delete[] buff;
|
||||||
|
|
||||||
|
// Clear input buffers
|
||||||
|
// pRateTransposer->clearInput();
|
||||||
|
pTDStretch->clearInput();
|
||||||
|
// yet leave the output intouched as that's where the
|
||||||
|
// flushed samples are!
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Changes a setting controlling the processing system behaviour. See the
|
||||||
|
// 'SETTING_...' defines for available setting ID's.
|
||||||
|
bool SoundTouch::setSetting(int settingId, int value)
|
||||||
|
{
|
||||||
|
int sampleRate, sequenceMs, seekWindowMs, overlapMs;
|
||||||
|
|
||||||
|
// read current tdstretch routine parameters
|
||||||
|
pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
|
||||||
|
|
||||||
|
switch (settingId)
|
||||||
|
{
|
||||||
|
case SETTING_USE_AA_FILTER :
|
||||||
|
// enables / disabless anti-alias filter
|
||||||
|
pRateTransposer->enableAAFilter((value != 0) ? true : false);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SETTING_AA_FILTER_LENGTH :
|
||||||
|
// sets anti-alias filter length
|
||||||
|
pRateTransposer->getAAFilter()->setLength(value);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SETTING_USE_QUICKSEEK :
|
||||||
|
// enables / disables tempo routine quick seeking algorithm
|
||||||
|
pTDStretch->enableQuickSeek((value != 0) ? true : false);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SETTING_SEQUENCE_MS:
|
||||||
|
// change time-stretch sequence duration parameter
|
||||||
|
pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SETTING_SEEKWINDOW_MS:
|
||||||
|
// change time-stretch seek window length parameter
|
||||||
|
pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SETTING_OVERLAP_MS:
|
||||||
|
// change time-stretch overlap length parameter
|
||||||
|
pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default :
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reads a setting controlling the processing system behaviour. See the
|
||||||
|
// 'SETTING_...' defines for available setting ID's.
|
||||||
|
//
|
||||||
|
// Returns the setting value.
|
||||||
|
int SoundTouch::getSetting(int settingId) const
|
||||||
|
{
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
switch (settingId)
|
||||||
|
{
|
||||||
|
case SETTING_USE_AA_FILTER :
|
||||||
|
return (uint)pRateTransposer->isAAFilterEnabled();
|
||||||
|
|
||||||
|
case SETTING_AA_FILTER_LENGTH :
|
||||||
|
return pRateTransposer->getAAFilter()->getLength();
|
||||||
|
|
||||||
|
case SETTING_USE_QUICKSEEK :
|
||||||
|
return (uint) pTDStretch->isQuickSeekEnabled();
|
||||||
|
|
||||||
|
case SETTING_SEQUENCE_MS:
|
||||||
|
pTDStretch->getParameters(NULL, &temp, NULL, NULL);
|
||||||
|
return temp;
|
||||||
|
|
||||||
|
case SETTING_SEEKWINDOW_MS:
|
||||||
|
pTDStretch->getParameters(NULL, NULL, &temp, NULL);
|
||||||
|
return temp;
|
||||||
|
|
||||||
|
case SETTING_OVERLAP_MS:
|
||||||
|
pTDStretch->getParameters(NULL, NULL, NULL, &temp);
|
||||||
|
return temp;
|
||||||
|
|
||||||
|
case SETTING_NOMINAL_INPUT_SEQUENCE :
|
||||||
|
return pTDStretch->getInputSampleReq();
|
||||||
|
|
||||||
|
case SETTING_NOMINAL_OUTPUT_SEQUENCE :
|
||||||
|
return pTDStretch->getOutputBatchSize();
|
||||||
|
|
||||||
|
default :
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clears all the samples in the object's output and internal processing
|
||||||
|
// buffers.
|
||||||
|
void SoundTouch::clear()
|
||||||
|
{
|
||||||
|
samplesExpectedOut = 0;
|
||||||
|
pRateTransposer->clear();
|
||||||
|
pTDStretch->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns number of samples currently unprocessed.
|
||||||
|
uint SoundTouch::numUnprocessedSamples() const
|
||||||
|
{
|
||||||
|
FIFOSamplePipe * psp;
|
||||||
|
if (pTDStretch)
|
||||||
|
{
|
||||||
|
psp = pTDStretch->getInput();
|
||||||
|
if (psp)
|
||||||
|
{
|
||||||
|
return psp->numSamples();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
|
/// \return Number of samples returned.
|
||||||
|
uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples)
|
||||||
|
{
|
||||||
|
uint ret = FIFOProcessor::receiveSamples(output, maxSamples);
|
||||||
|
samplesOutput += (long)ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
|
/// with 'ptrBegin' function.
|
||||||
|
uint SoundTouch::receiveSamples(uint maxSamples)
|
||||||
|
{
|
||||||
|
uint ret = FIFOProcessor::receiveSamples(maxSamples);
|
||||||
|
samplesOutput += (long)ret;
|
||||||
|
return ret;
|
||||||
|
}
|
1078
src/TDStretch.cpp
Normal file
1078
src/TDStretch.cpp
Normal file
File diff suppressed because it is too large
Load Diff
281
src/TDStretch.h
Normal file
281
src/TDStretch.h
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
|
||||||
|
/// while maintaining the original pitch by using a time domain WSOLA-like method
|
||||||
|
/// with several performance-increasing tweaks.
|
||||||
|
///
|
||||||
|
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files
|
||||||
|
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: TDStretch.h 226 2015-08-08 21:00:15Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef TDStretch_H
|
||||||
|
#define TDStretch_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "STTypes.h"
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "FIFOSamplePipe.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Default values for sound processing parameters:
|
||||||
|
/// Notice that the default parameters are tuned for contemporary popular music
|
||||||
|
/// processing. For speech processing applications these parameters suit better:
|
||||||
|
/// #define DEFAULT_SEQUENCE_MS 40
|
||||||
|
/// #define DEFAULT_SEEKWINDOW_MS 15
|
||||||
|
/// #define DEFAULT_OVERLAP_MS 8
|
||||||
|
///
|
||||||
|
|
||||||
|
/// Default length of a single processing sequence, in milliseconds. This determines to how
|
||||||
|
/// long sequences the original sound is chopped in the time-stretch algorithm.
|
||||||
|
///
|
||||||
|
/// The larger this value is, the lesser sequences are used in processing. In principle
|
||||||
|
/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
|
||||||
|
/// and vice versa.
|
||||||
|
///
|
||||||
|
/// Increasing this value reduces computational burden & vice versa.
|
||||||
|
//#define DEFAULT_SEQUENCE_MS 40
|
||||||
|
#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
|
||||||
|
|
||||||
|
/// Giving this value for the sequence length sets automatic parameter value
|
||||||
|
/// according to tempo setting (recommended)
|
||||||
|
#define USE_AUTO_SEQUENCE_LEN 0
|
||||||
|
|
||||||
|
/// Seeking window default length in milliseconds for algorithm that finds the best possible
|
||||||
|
/// overlapping location. This determines from how wide window the algorithm may look for an
|
||||||
|
/// optimal joining location when mixing the sound sequences back together.
|
||||||
|
///
|
||||||
|
/// The bigger this window setting is, the higher the possibility to find a better mixing
|
||||||
|
/// position will become, but at the same time large values may cause a "drifting" artifact
|
||||||
|
/// because consequent sequences will be taken at more uneven intervals.
|
||||||
|
///
|
||||||
|
/// If there's a disturbing artifact that sounds as if a constant frequency was drifting
|
||||||
|
/// around, try reducing this setting.
|
||||||
|
///
|
||||||
|
/// Increasing this value increases computational burden & vice versa.
|
||||||
|
//#define DEFAULT_SEEKWINDOW_MS 15
|
||||||
|
#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
|
||||||
|
|
||||||
|
/// Giving this value for the seek window length sets automatic parameter value
|
||||||
|
/// according to tempo setting (recommended)
|
||||||
|
#define USE_AUTO_SEEKWINDOW_LEN 0
|
||||||
|
|
||||||
|
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
|
||||||
|
/// to form a continuous sound stream, this parameter defines over how long period the two
|
||||||
|
/// consecutive sequences are let to overlap each other.
|
||||||
|
///
|
||||||
|
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
|
||||||
|
/// by a large amount, you might wish to try a smaller value on this.
|
||||||
|
///
|
||||||
|
/// Increasing this value increases computational burden & vice versa.
|
||||||
|
#define DEFAULT_OVERLAP_MS 8
|
||||||
|
|
||||||
|
|
||||||
|
/// Class that does the time-stretch (tempo change) effect for the processed
|
||||||
|
/// sound.
|
||||||
|
class TDStretch : public FIFOProcessor
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int channels;
|
||||||
|
int sampleReq;
|
||||||
|
|
||||||
|
int overlapLength;
|
||||||
|
int seekLength;
|
||||||
|
int seekWindowLength;
|
||||||
|
int overlapDividerBitsNorm;
|
||||||
|
int overlapDividerBitsPure;
|
||||||
|
int slopingDivider;
|
||||||
|
int sampleRate;
|
||||||
|
int sequenceMs;
|
||||||
|
int seekWindowMs;
|
||||||
|
int overlapMs;
|
||||||
|
|
||||||
|
unsigned long maxnorm;
|
||||||
|
float maxnormf;
|
||||||
|
|
||||||
|
double tempo;
|
||||||
|
double nominalSkip;
|
||||||
|
double skipFract;
|
||||||
|
|
||||||
|
bool bQuickSeek;
|
||||||
|
bool bAutoSeqSetting;
|
||||||
|
bool bAutoSeekSetting;
|
||||||
|
|
||||||
|
SAMPLETYPE *pMidBuffer;
|
||||||
|
SAMPLETYPE *pMidBufferUnaligned;
|
||||||
|
|
||||||
|
FIFOSampleBuffer outputBuffer;
|
||||||
|
FIFOSampleBuffer inputBuffer;
|
||||||
|
|
||||||
|
void acceptNewOverlapLength(int newOverlapLength);
|
||||||
|
|
||||||
|
virtual void clearCrossCorrState();
|
||||||
|
void calculateOverlapLength(int overlapMs);
|
||||||
|
|
||||||
|
virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
|
||||||
|
virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
|
||||||
|
|
||||||
|
virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos);
|
||||||
|
virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);
|
||||||
|
virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos);
|
||||||
|
|
||||||
|
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
||||||
|
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
||||||
|
virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
||||||
|
|
||||||
|
void clearMidBuffer();
|
||||||
|
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
|
||||||
|
|
||||||
|
void calcSeqParameters();
|
||||||
|
void adaptNormalizer();
|
||||||
|
|
||||||
|
|
||||||
|
/// Changes the tempo of the given sound samples.
|
||||||
|
/// Returns amount of samples returned in the "output" buffer.
|
||||||
|
/// The maximum amount of samples that can be returned at a time is set by
|
||||||
|
/// the 'set_returnBuffer_size' function.
|
||||||
|
void processSamples();
|
||||||
|
|
||||||
|
public:
|
||||||
|
TDStretch();
|
||||||
|
virtual ~TDStretch();
|
||||||
|
|
||||||
|
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
|
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
|
||||||
|
static void *operator new(size_t s);
|
||||||
|
|
||||||
|
/// Use this function instead of "new" operator to create a new instance of this class.
|
||||||
|
/// This function automatically chooses a correct feature set depending on if the CPU
|
||||||
|
/// supports MMX/SSE/etc extensions.
|
||||||
|
static TDStretch *newInstance();
|
||||||
|
|
||||||
|
/// Returns the output buffer object
|
||||||
|
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
||||||
|
|
||||||
|
/// Returns the input buffer object
|
||||||
|
FIFOSamplePipe *getInput() { return &inputBuffer; };
|
||||||
|
|
||||||
|
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
|
||||||
|
/// tempo, larger faster tempo.
|
||||||
|
void setTempo(double newTempo);
|
||||||
|
|
||||||
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
|
/// Clears the input buffer
|
||||||
|
void clearInput();
|
||||||
|
|
||||||
|
/// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
|
void setChannels(int numChannels);
|
||||||
|
|
||||||
|
/// Enables/disables the quick position seeking algorithm. Zero to disable,
|
||||||
|
/// nonzero to enable
|
||||||
|
void enableQuickSeek(bool enable);
|
||||||
|
|
||||||
|
/// Returns nonzero if the quick seeking algorithm is enabled.
|
||||||
|
bool isQuickSeekEnabled() const;
|
||||||
|
|
||||||
|
/// Sets routine control parameters. These control are certain time constants
|
||||||
|
/// defining how the sound is stretched to the desired duration.
|
||||||
|
//
|
||||||
|
/// 'sampleRate' = sample rate of the sound
|
||||||
|
/// 'sequenceMS' = one processing sequence length in milliseconds
|
||||||
|
/// 'seekwindowMS' = seeking window length for scanning the best overlapping
|
||||||
|
/// position
|
||||||
|
/// 'overlapMS' = overlapping length
|
||||||
|
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
|
||||||
|
int sequenceMS = -1, ///< Single processing sequence length (ms)
|
||||||
|
int seekwindowMS = -1, ///< Offset seeking window length (ms)
|
||||||
|
int overlapMS = -1 ///< Sequence overlapping length (ms)
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Get routine control parameters, see setParameters() function.
|
||||||
|
/// Any of the parameters to this function can be NULL, in such case corresponding parameter
|
||||||
|
/// value isn't returned.
|
||||||
|
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
|
||||||
|
|
||||||
|
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into
|
||||||
|
/// the input of the object.
|
||||||
|
virtual void putSamples(
|
||||||
|
const SAMPLETYPE *samples, ///< Input sample data
|
||||||
|
uint numSamples ///< Number of samples in 'samples' so that one sample
|
||||||
|
///< contains both channels if stereo
|
||||||
|
);
|
||||||
|
|
||||||
|
/// return nominal input sample requirement for triggering a processing batch
|
||||||
|
int getInputSampleReq() const
|
||||||
|
{
|
||||||
|
return (int)(nominalSkip + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// return nominal output sample amount when running a processing batch
|
||||||
|
int getOutputBatchSize() const
|
||||||
|
{
|
||||||
|
return seekWindowLength - overlapLength;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Implementation-specific class declarations:
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
|
/// Class that implements MMX optimized routines for 16bit integer samples type.
|
||||||
|
class TDStretchMMX : public TDStretch
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm);
|
||||||
|
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm);
|
||||||
|
virtual void overlapStereo(short *output, const short *input) const;
|
||||||
|
virtual void clearCrossCorrState();
|
||||||
|
};
|
||||||
|
#endif /// SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
|
/// Class that implements SSE optimized routines for floating point samples type.
|
||||||
|
class TDStretchSSE : public TDStretch
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm);
|
||||||
|
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /// SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /// TDStretch_H
|
62
src/cpu_detect.h
Normal file
62
src/cpu_detect.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// A header file for detecting the Intel MMX instructions set extension.
|
||||||
|
///
|
||||||
|
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
|
||||||
|
/// routine implementations for x86 Windows, x86 gnu version and non-x86
|
||||||
|
/// platforms, respectively.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _CPU_DETECT_H_
|
||||||
|
#define _CPU_DETECT_H_
|
||||||
|
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
#define SUPPORT_MMX 0x0001
|
||||||
|
#define SUPPORT_3DNOW 0x0002
|
||||||
|
#define SUPPORT_ALTIVEC 0x0004
|
||||||
|
#define SUPPORT_SSE 0x0008
|
||||||
|
#define SUPPORT_SSE2 0x0010
|
||||||
|
|
||||||
|
/// Checks which instruction set extensions are supported by the CPU.
|
||||||
|
///
|
||||||
|
/// \return A bitmask of supported extensions, see SUPPORT_... defines.
|
||||||
|
uint detectCPUextensions(void);
|
||||||
|
|
||||||
|
/// Disables given set of instruction extensions. See SUPPORT_... defines.
|
||||||
|
void disableExtensions(uint wDisableMask);
|
||||||
|
|
||||||
|
#endif // _CPU_DETECT_H_
|
138
src/cpu_detect_x86.cpp
Normal file
138
src/cpu_detect_x86.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Generic version of the x86 CPU extension detection routine.
|
||||||
|
///
|
||||||
|
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
|
||||||
|
/// for the Microsoft compiler version.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Last changed : $Date: 2014-01-07 20:24:28 +0200 (Tue, 07 Jan 2014) $
|
||||||
|
// File revision : $Revision: 4 $
|
||||||
|
//
|
||||||
|
// $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "cpu_detect.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && defined(__i386__)
|
||||||
|
// gcc
|
||||||
|
#include "cpuid.h"
|
||||||
|
#elif defined(_M_IX86)
|
||||||
|
// windows non-gcc
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define bit_MMX (1 << 23)
|
||||||
|
#define bit_SSE (1 << 25)
|
||||||
|
#define bit_SSE2 (1 << 26)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// processor instructions extension detection routines
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Flag variable indicating whick ISA extensions are disabled (for debugging)
|
||||||
|
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
|
||||||
|
|
||||||
|
// Disables given set of instruction extensions. See SUPPORT_... defines.
|
||||||
|
void disableExtensions(uint dwDisableMask)
|
||||||
|
{
|
||||||
|
_dwDisabledISA = dwDisableMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Checks which instruction set extensions are supported by the CPU.
|
||||||
|
uint detectCPUextensions(void)
|
||||||
|
{
|
||||||
|
/// If building for a 64bit system (no Itanium) and the user wants optimizations.
|
||||||
|
/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.
|
||||||
|
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
|
||||||
|
#if ((defined(__GNUC__) && defined(__x86_64__)) \
|
||||||
|
|| defined(_M_X64)) \
|
||||||
|
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
||||||
|
return 0x19 & ~_dwDisabledISA;
|
||||||
|
|
||||||
|
/// If building for a 32bit system and the user wants optimizations.
|
||||||
|
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
|
||||||
|
#elif ((defined(__GNUC__) && defined(__i386__)) \
|
||||||
|
|| defined(_M_IX86)) \
|
||||||
|
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
||||||
|
|
||||||
|
if (_dwDisabledISA == 0xffffffff) return 0;
|
||||||
|
|
||||||
|
uint res = 0;
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.
|
||||||
|
uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.
|
||||||
|
|
||||||
|
// Check if no cpuid support.
|
||||||
|
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.
|
||||||
|
|
||||||
|
if (edx & bit_MMX) res = res | SUPPORT_MMX;
|
||||||
|
if (edx & bit_SSE) res = res | SUPPORT_SSE;
|
||||||
|
if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
|
||||||
|
// for __cpuid intrinsic support.
|
||||||
|
int reg[4] = {-1};
|
||||||
|
|
||||||
|
// Check if no cpuid support.
|
||||||
|
__cpuid(reg,0);
|
||||||
|
if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.
|
||||||
|
|
||||||
|
__cpuid(reg,1);
|
||||||
|
if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX;
|
||||||
|
if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE;
|
||||||
|
if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return res & ~_dwDisabledISA;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/// One of these is true:
|
||||||
|
/// 1) We don't want optimizations.
|
||||||
|
/// 2) Using an unsupported compiler.
|
||||||
|
/// 3) Running on a non-x86 platform.
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user