migrating to the latest JUCE version
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -1,310 +1,310 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/**
|
||||
Used by the Convolution to dispatch engine-update messages on a background
|
||||
thread.
|
||||
|
||||
May be shared between multiple Convolution instances.
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
class JUCE_API ConvolutionMessageQueue
|
||||
{
|
||||
public:
|
||||
/** Initialises the queue to a default size.
|
||||
|
||||
If your Convolution is updated very frequently, or you are sharing
|
||||
this queue between multiple Convolutions, consider using the alternative
|
||||
constructor taking an explicit size argument.
|
||||
*/
|
||||
ConvolutionMessageQueue();
|
||||
~ConvolutionMessageQueue() noexcept;
|
||||
|
||||
/** Initialises the queue with the specified number of entries.
|
||||
|
||||
In general, the number of required entries scales with the number
|
||||
of Convolutions sharing the same Queue, and the frequency of updates
|
||||
to those Convolutions.
|
||||
*/
|
||||
explicit ConvolutionMessageQueue (int numEntries);
|
||||
|
||||
ConvolutionMessageQueue (ConvolutionMessageQueue&&) noexcept;
|
||||
ConvolutionMessageQueue& operator= (ConvolutionMessageQueue&&) noexcept;
|
||||
|
||||
ConvolutionMessageQueue (const ConvolutionMessageQueue&) = delete;
|
||||
ConvolutionMessageQueue& operator= (const ConvolutionMessageQueue&) = delete;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
friend class Convolution;
|
||||
};
|
||||
|
||||
/**
|
||||
Performs stereo partitioned convolution of an input signal with an
|
||||
impulse response in the frequency domain, using the JUCE FFT class.
|
||||
|
||||
This class provides some thread-safe functions to load impulse responses
|
||||
from audio files or memory on-the-fly without noticeable artefacts,
|
||||
performing resampling and trimming if necessary.
|
||||
|
||||
The processing performed by this class is equivalent to the time domain
|
||||
convolution done in the FIRFilter class, with a FIRFilter::Coefficients
|
||||
object having the samples of the impulse response as its coefficients.
|
||||
However, in general it is more efficient to do frequency domain
|
||||
convolution when the size of the impulse response is 64 samples or
|
||||
greater.
|
||||
|
||||
Note: The default operation of this class uses zero latency and a uniform
|
||||
partitioned algorithm. If the impulse response size is large, or if the
|
||||
algorithm is too CPU intensive, it is possible to use either a fixed
|
||||
latency version of the algorithm, or a simple non-uniform partitioned
|
||||
convolution algorithm.
|
||||
|
||||
Threading: It is not safe to interleave calls to the methods of this
|
||||
class. If you need to load new impulse responses during processing the
|
||||
load() calls must be synchronised with process() calls, which in practice
|
||||
means making the load() call from the audio thread. The
|
||||
loadImpulseResponse() functions *are* wait-free and are therefore
|
||||
suitable for use in a realtime context.
|
||||
|
||||
@see FIRFilter, FIRFilter::Coefficients, FFT
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
class JUCE_API Convolution
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Initialises an object for performing convolution in the frequency domain. */
|
||||
Convolution();
|
||||
|
||||
/** Initialises a convolution engine using a shared background message queue.
|
||||
|
||||
IMPORTANT: the queue *must* remain alive throughout the lifetime of the
|
||||
Convolution.
|
||||
*/
|
||||
explicit Convolution (ConvolutionMessageQueue& queue);
|
||||
|
||||
/** Contains configuration information for a convolution with a fixed latency. */
|
||||
struct Latency { int latencyInSamples; };
|
||||
|
||||
/** Initialises an object for performing convolution with a fixed latency.
|
||||
|
||||
If the requested latency is zero, the actual latency will also be zero.
|
||||
For requested latencies greater than zero, the actual latency will
|
||||
always at least as large as the requested latency. Using a fixed
|
||||
non-zero latency can reduce the CPU consumption of the convolution
|
||||
algorithm.
|
||||
|
||||
@param requiredLatency the minimum latency
|
||||
*/
|
||||
explicit Convolution (const Latency& requiredLatency);
|
||||
|
||||
/** Contains configuration information for a non-uniform convolution. */
|
||||
struct NonUniform { int headSizeInSamples; };
|
||||
|
||||
/** Initialises an object for performing convolution in the frequency domain
|
||||
using a non-uniform partitioned algorithm.
|
||||
|
||||
A requiredHeadSize of 256 samples or greater will improve the
|
||||
efficiency of the processing for IR sizes of 4096 samples or greater
|
||||
(recommended for reverberation IRs).
|
||||
|
||||
@param requiredHeadSize the head IR size for two stage non-uniform
|
||||
partitioned convolution
|
||||
*/
|
||||
explicit Convolution (const NonUniform& requiredHeadSize);
|
||||
|
||||
/** Behaves the same as the constructor taking a single Latency argument,
|
||||
but with a shared background message queue.
|
||||
|
||||
IMPORTANT: the queue *must* remain alive throughout the lifetime of the
|
||||
Convolution.
|
||||
*/
|
||||
Convolution (const Latency&, ConvolutionMessageQueue&);
|
||||
|
||||
/** Behaves the same as the constructor taking a single NonUniform argument,
|
||||
but with a shared background message queue.
|
||||
|
||||
IMPORTANT: the queue *must* remain alive throughout the lifetime of the
|
||||
Convolution.
|
||||
*/
|
||||
Convolution (const NonUniform&, ConvolutionMessageQueue&);
|
||||
|
||||
~Convolution() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Must be called before first calling process.
|
||||
|
||||
In general, calls to loadImpulseResponse() load the impulse response (IR)
|
||||
asynchronously. The IR will become active once it has been completely loaded
|
||||
and processed, which may take some time.
|
||||
|
||||
Calling prepare() will ensure that the IR supplied to the most recent call to
|
||||
loadImpulseResponse() is fully initialised. This IR will then be active during
|
||||
the next call to process(). It is recommended to call loadImpulseResponse() *before*
|
||||
prepare() if a specific IR must be active during the first process() call.
|
||||
*/
|
||||
void prepare (const ProcessSpec&);
|
||||
|
||||
/** Resets the processing pipeline ready to start a new stream of data. */
|
||||
void reset() noexcept;
|
||||
|
||||
/** Performs the filter operation on the given set of samples with optional
|
||||
stereo processing.
|
||||
*/
|
||||
template <typename ProcessContext,
|
||||
std::enable_if_t<std::is_same<typename ProcessContext::SampleType, float>::value, int> = 0>
|
||||
void process (const ProcessContext& context) noexcept
|
||||
{
|
||||
processSamples (context.getInputBlock(), context.getOutputBlock(), context.isBypassed);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
enum class Stereo { no, yes };
|
||||
enum class Trim { no, yes };
|
||||
enum class Normalise { no, yes };
|
||||
|
||||
//==============================================================================
|
||||
/** This function loads an impulse response audio file from memory, added in a
|
||||
JUCE project with the Projucer as binary data. It can load any of the audio
|
||||
formats registered in JUCE, and performs some resampling and pre-processing
|
||||
as well if needed.
|
||||
|
||||
Note: Don't try to use this function on float samples, since the data is
|
||||
expected to be an audio file in its binary format. Be sure that the original
|
||||
data remains constant throughout the lifetime of the Convolution object, as
|
||||
the loading process will happen on a background thread once this function has
|
||||
returned.
|
||||
|
||||
@param sourceData the block of data to use as the stream's source
|
||||
@param sourceDataSize the number of bytes in the source data block
|
||||
@param isStereo selects either stereo or mono
|
||||
@param requiresTrimming optionally trim the start and the end of the impulse response
|
||||
@param size the expected size for the impulse response after loading, can be
|
||||
set to 0 to requesting the original impulse response size
|
||||
@param requiresNormalisation optionally normalise the impulse response amplitude
|
||||
*/
|
||||
void loadImpulseResponse (const void* sourceData, size_t sourceDataSize,
|
||||
Stereo isStereo, Trim requiresTrimming, size_t size,
|
||||
Normalise requiresNormalisation = Normalise::yes);
|
||||
|
||||
/** This function loads an impulse response from an audio file. It can load any
|
||||
of the audio formats registered in JUCE, and performs some resampling and
|
||||
pre-processing as well if needed.
|
||||
|
||||
@param fileImpulseResponse the location of the audio file
|
||||
@param isStereo selects either stereo or mono
|
||||
@param requiresTrimming optionally trim the start and the end of the impulse response
|
||||
@param size the expected size for the impulse response after loading, can be
|
||||
set to 0 to requesting the original impulse response size
|
||||
@param requiresNormalisation optionally normalise the impulse response amplitude
|
||||
*/
|
||||
void loadImpulseResponse (const File& fileImpulseResponse,
|
||||
Stereo isStereo, Trim requiresTrimming, size_t size,
|
||||
Normalise requiresNormalisation = Normalise::yes);
|
||||
|
||||
/** This function loads an impulse response from an audio buffer.
|
||||
To avoid memory allocation on the audio thread, this function takes
|
||||
ownership of the buffer passed in.
|
||||
|
||||
If calling this function during processing, make sure that the buffer is
|
||||
not allocated on the audio thread (be careful of accidental copies!).
|
||||
If you need to pass arbitrary/generated buffers it's recommended to
|
||||
create these buffers on a separate thread and to use some wait-free
|
||||
construct (a lock-free queue or a SpinLock/GenericScopedTryLock combination)
|
||||
to transfer ownership to the audio thread without allocating.
|
||||
|
||||
@param buffer the AudioBuffer to use
|
||||
@param bufferSampleRate the sampleRate of the data in the AudioBuffer
|
||||
@param isStereo selects either stereo or mono
|
||||
@param requiresTrimming optionally trim the start and the end of the impulse response
|
||||
@param requiresNormalisation optionally normalise the impulse response amplitude
|
||||
*/
|
||||
void loadImpulseResponse (AudioBuffer<float>&& buffer, double bufferSampleRate,
|
||||
Stereo isStereo, Trim requiresTrimming, Normalise requiresNormalisation);
|
||||
|
||||
/** This function returns the size of the current IR in samples. */
|
||||
int getCurrentIRSize() const;
|
||||
|
||||
/** This function returns the current latency of the process in samples.
|
||||
|
||||
Note: This is the latency of the convolution engine, not the latency
|
||||
associated with the current impulse response choice that has to be
|
||||
considered separately (linear phase filters, for example).
|
||||
*/
|
||||
int getLatency() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Convolution (const Latency&,
|
||||
const NonUniform&,
|
||||
OptionalScopedPointer<ConvolutionMessageQueue>&&);
|
||||
|
||||
void processSamples (const AudioBlock<const float>&, AudioBlock<float>&, bool isBypassed) noexcept;
|
||||
|
||||
class Mixer
|
||||
{
|
||||
public:
|
||||
void prepare (const ProcessSpec&);
|
||||
|
||||
template <typename ProcessWet>
|
||||
void processSamples (const AudioBlock<const float>&,
|
||||
AudioBlock<float>&,
|
||||
bool isBypassed,
|
||||
ProcessWet&&) noexcept;
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
std::array<SmoothedValue<float>, 2> volumeDry, volumeWet;
|
||||
AudioBlock<float> dryBlock;
|
||||
HeapBlock<char> dryBlockStorage;
|
||||
double sampleRate = 0;
|
||||
bool currentIsBypassed = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
//==============================================================================
|
||||
Mixer mixer;
|
||||
bool isActive = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Convolution)
|
||||
};
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/**
|
||||
Used by the Convolution to dispatch engine-update messages on a background
|
||||
thread.
|
||||
|
||||
May be shared between multiple Convolution instances.
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
class JUCE_API ConvolutionMessageQueue
|
||||
{
|
||||
public:
|
||||
/** Initialises the queue to a default size.
|
||||
|
||||
If your Convolution is updated very frequently, or you are sharing
|
||||
this queue between multiple Convolutions, consider using the alternative
|
||||
constructor taking an explicit size argument.
|
||||
*/
|
||||
ConvolutionMessageQueue();
|
||||
~ConvolutionMessageQueue() noexcept;
|
||||
|
||||
/** Initialises the queue with the specified number of entries.
|
||||
|
||||
In general, the number of required entries scales with the number
|
||||
of Convolutions sharing the same Queue, and the frequency of updates
|
||||
to those Convolutions.
|
||||
*/
|
||||
explicit ConvolutionMessageQueue (int numEntries);
|
||||
|
||||
ConvolutionMessageQueue (ConvolutionMessageQueue&&) noexcept;
|
||||
ConvolutionMessageQueue& operator= (ConvolutionMessageQueue&&) noexcept;
|
||||
|
||||
ConvolutionMessageQueue (const ConvolutionMessageQueue&) = delete;
|
||||
ConvolutionMessageQueue& operator= (const ConvolutionMessageQueue&) = delete;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
friend class Convolution;
|
||||
};
|
||||
|
||||
/**
|
||||
Performs stereo partitioned convolution of an input signal with an
|
||||
impulse response in the frequency domain, using the JUCE FFT class.
|
||||
|
||||
This class provides some thread-safe functions to load impulse responses
|
||||
from audio files or memory on-the-fly without noticeable artefacts,
|
||||
performing resampling and trimming if necessary.
|
||||
|
||||
The processing performed by this class is equivalent to the time domain
|
||||
convolution done in the FIRFilter class, with a FIRFilter::Coefficients
|
||||
object having the samples of the impulse response as its coefficients.
|
||||
However, in general it is more efficient to do frequency domain
|
||||
convolution when the size of the impulse response is 64 samples or
|
||||
greater.
|
||||
|
||||
Note: The default operation of this class uses zero latency and a uniform
|
||||
partitioned algorithm. If the impulse response size is large, or if the
|
||||
algorithm is too CPU intensive, it is possible to use either a fixed
|
||||
latency version of the algorithm, or a simple non-uniform partitioned
|
||||
convolution algorithm.
|
||||
|
||||
Threading: It is not safe to interleave calls to the methods of this
|
||||
class. If you need to load new impulse responses during processing the
|
||||
load() calls must be synchronised with process() calls, which in practice
|
||||
means making the load() call from the audio thread. The
|
||||
loadImpulseResponse() functions *are* wait-free and are therefore
|
||||
suitable for use in a realtime context.
|
||||
|
||||
@see FIRFilter, FIRFilter::Coefficients, FFT
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
class JUCE_API Convolution
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Initialises an object for performing convolution in the frequency domain. */
|
||||
Convolution();
|
||||
|
||||
/** Initialises a convolution engine using a shared background message queue.
|
||||
|
||||
IMPORTANT: the queue *must* remain alive throughout the lifetime of the
|
||||
Convolution.
|
||||
*/
|
||||
explicit Convolution (ConvolutionMessageQueue& queue);
|
||||
|
||||
/** Contains configuration information for a convolution with a fixed latency. */
|
||||
struct Latency { int latencyInSamples; };
|
||||
|
||||
/** Initialises an object for performing convolution with a fixed latency.
|
||||
|
||||
If the requested latency is zero, the actual latency will also be zero.
|
||||
For requested latencies greater than zero, the actual latency will
|
||||
always at least as large as the requested latency. Using a fixed
|
||||
non-zero latency can reduce the CPU consumption of the convolution
|
||||
algorithm.
|
||||
|
||||
@param requiredLatency the minimum latency
|
||||
*/
|
||||
explicit Convolution (const Latency& requiredLatency);
|
||||
|
||||
/** Contains configuration information for a non-uniform convolution. */
|
||||
struct NonUniform { int headSizeInSamples; };
|
||||
|
||||
/** Initialises an object for performing convolution in the frequency domain
|
||||
using a non-uniform partitioned algorithm.
|
||||
|
||||
A requiredHeadSize of 256 samples or greater will improve the
|
||||
efficiency of the processing for IR sizes of 4096 samples or greater
|
||||
(recommended for reverberation IRs).
|
||||
|
||||
@param requiredHeadSize the head IR size for two stage non-uniform
|
||||
partitioned convolution
|
||||
*/
|
||||
explicit Convolution (const NonUniform& requiredHeadSize);
|
||||
|
||||
/** Behaves the same as the constructor taking a single Latency argument,
|
||||
but with a shared background message queue.
|
||||
|
||||
IMPORTANT: the queue *must* remain alive throughout the lifetime of the
|
||||
Convolution.
|
||||
*/
|
||||
Convolution (const Latency&, ConvolutionMessageQueue&);
|
||||
|
||||
/** Behaves the same as the constructor taking a single NonUniform argument,
|
||||
but with a shared background message queue.
|
||||
|
||||
IMPORTANT: the queue *must* remain alive throughout the lifetime of the
|
||||
Convolution.
|
||||
*/
|
||||
Convolution (const NonUniform&, ConvolutionMessageQueue&);
|
||||
|
||||
~Convolution() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Must be called before first calling process.
|
||||
|
||||
In general, calls to loadImpulseResponse() load the impulse response (IR)
|
||||
asynchronously. The IR will become active once it has been completely loaded
|
||||
and processed, which may take some time.
|
||||
|
||||
Calling prepare() will ensure that the IR supplied to the most recent call to
|
||||
loadImpulseResponse() is fully initialised. This IR will then be active during
|
||||
the next call to process(). It is recommended to call loadImpulseResponse() *before*
|
||||
prepare() if a specific IR must be active during the first process() call.
|
||||
*/
|
||||
void prepare (const ProcessSpec&);
|
||||
|
||||
/** Resets the processing pipeline ready to start a new stream of data. */
|
||||
void reset() noexcept;
|
||||
|
||||
/** Performs the filter operation on the given set of samples with optional
|
||||
stereo processing.
|
||||
*/
|
||||
template <typename ProcessContext,
|
||||
std::enable_if_t<std::is_same<typename ProcessContext::SampleType, float>::value, int> = 0>
|
||||
void process (const ProcessContext& context) noexcept
|
||||
{
|
||||
processSamples (context.getInputBlock(), context.getOutputBlock(), context.isBypassed);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
enum class Stereo { no, yes };
|
||||
enum class Trim { no, yes };
|
||||
enum class Normalise { no, yes };
|
||||
|
||||
//==============================================================================
|
||||
/** This function loads an impulse response audio file from memory, added in a
|
||||
JUCE project with the Projucer as binary data. It can load any of the audio
|
||||
formats registered in JUCE, and performs some resampling and pre-processing
|
||||
as well if needed.
|
||||
|
||||
Note: Don't try to use this function on float samples, since the data is
|
||||
expected to be an audio file in its binary format. Be sure that the original
|
||||
data remains constant throughout the lifetime of the Convolution object, as
|
||||
the loading process will happen on a background thread once this function has
|
||||
returned.
|
||||
|
||||
@param sourceData the block of data to use as the stream's source
|
||||
@param sourceDataSize the number of bytes in the source data block
|
||||
@param isStereo selects either stereo or mono
|
||||
@param requiresTrimming optionally trim the start and the end of the impulse response
|
||||
@param size the expected size for the impulse response after loading, can be
|
||||
set to 0 to requesting the original impulse response size
|
||||
@param requiresNormalisation optionally normalise the impulse response amplitude
|
||||
*/
|
||||
void loadImpulseResponse (const void* sourceData, size_t sourceDataSize,
|
||||
Stereo isStereo, Trim requiresTrimming, size_t size,
|
||||
Normalise requiresNormalisation = Normalise::yes);
|
||||
|
||||
/** This function loads an impulse response from an audio file. It can load any
|
||||
of the audio formats registered in JUCE, and performs some resampling and
|
||||
pre-processing as well if needed.
|
||||
|
||||
@param fileImpulseResponse the location of the audio file
|
||||
@param isStereo selects either stereo or mono
|
||||
@param requiresTrimming optionally trim the start and the end of the impulse response
|
||||
@param size the expected size for the impulse response after loading, can be
|
||||
set to 0 to requesting the original impulse response size
|
||||
@param requiresNormalisation optionally normalise the impulse response amplitude
|
||||
*/
|
||||
void loadImpulseResponse (const File& fileImpulseResponse,
|
||||
Stereo isStereo, Trim requiresTrimming, size_t size,
|
||||
Normalise requiresNormalisation = Normalise::yes);
|
||||
|
||||
/** This function loads an impulse response from an audio buffer.
|
||||
To avoid memory allocation on the audio thread, this function takes
|
||||
ownership of the buffer passed in.
|
||||
|
||||
If calling this function during processing, make sure that the buffer is
|
||||
not allocated on the audio thread (be careful of accidental copies!).
|
||||
If you need to pass arbitrary/generated buffers it's recommended to
|
||||
create these buffers on a separate thread and to use some wait-free
|
||||
construct (a lock-free queue or a SpinLock/GenericScopedTryLock combination)
|
||||
to transfer ownership to the audio thread without allocating.
|
||||
|
||||
@param buffer the AudioBuffer to use
|
||||
@param bufferSampleRate the sampleRate of the data in the AudioBuffer
|
||||
@param isStereo selects either stereo or mono
|
||||
@param requiresTrimming optionally trim the start and the end of the impulse response
|
||||
@param requiresNormalisation optionally normalise the impulse response amplitude
|
||||
*/
|
||||
void loadImpulseResponse (AudioBuffer<float>&& buffer, double bufferSampleRate,
|
||||
Stereo isStereo, Trim requiresTrimming, Normalise requiresNormalisation);
|
||||
|
||||
/** This function returns the size of the current IR in samples. */
|
||||
int getCurrentIRSize() const;
|
||||
|
||||
/** This function returns the current latency of the process in samples.
|
||||
|
||||
Note: This is the latency of the convolution engine, not the latency
|
||||
associated with the current impulse response choice that has to be
|
||||
considered separately (linear phase filters, for example).
|
||||
*/
|
||||
int getLatency() const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Convolution (const Latency&,
|
||||
const NonUniform&,
|
||||
OptionalScopedPointer<ConvolutionMessageQueue>&&);
|
||||
|
||||
void processSamples (const AudioBlock<const float>&, AudioBlock<float>&, bool isBypassed) noexcept;
|
||||
|
||||
class Mixer
|
||||
{
|
||||
public:
|
||||
void prepare (const ProcessSpec&);
|
||||
|
||||
template <typename ProcessWet>
|
||||
void processSamples (const AudioBlock<const float>&,
|
||||
AudioBlock<float>&,
|
||||
bool isBypassed,
|
||||
ProcessWet&&) noexcept;
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
std::array<SmoothedValue<float>, 2> volumeDry, volumeWet;
|
||||
AudioBlock<float> dryBlock;
|
||||
HeapBlock<char> dryBlockStorage;
|
||||
double sampleRate = 0;
|
||||
bool currentIsBypassed = false;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
//==============================================================================
|
||||
Mixer mixer;
|
||||
bool isActive = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Convolution)
|
||||
};
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
|
File diff suppressed because it is too large
Load Diff
2003
deps/juce/modules/juce_dsp/frequency/juce_FFT.cpp
vendored
2003
deps/juce/modules/juce_dsp/frequency/juce_FFT.cpp
vendored
File diff suppressed because it is too large
Load Diff
259
deps/juce/modules/juce_dsp/frequency/juce_FFT.h
vendored
259
deps/juce/modules/juce_dsp/frequency/juce_FFT.h
vendored
@ -1,127 +1,132 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/**
|
||||
Performs a fast fourier transform.
|
||||
|
||||
This is only a simple low-footprint implementation and isn't tuned for speed - it may
|
||||
be useful for simple applications where one of the more complex FFT libraries would be
|
||||
overkill. (But in the future it may end up becoming optimised of course...)
|
||||
|
||||
The FFT class itself contains lookup tables, so there's some overhead in creating
|
||||
one, you should create and cache an FFT object for each size/direction of transform
|
||||
that you need, and re-use them to perform the actual operation.
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
class JUCE_API FFT
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Initialises an object for performing forward and inverse FFT with the given size.
|
||||
The number of points the FFT will operate on will be 2 ^ order.
|
||||
*/
|
||||
FFT (int order);
|
||||
|
||||
/** Move constructor. */
|
||||
FFT (FFT&&) noexcept;
|
||||
|
||||
/** Move assignment operator. */
|
||||
FFT& operator= (FFT&&) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~FFT();
|
||||
|
||||
//==============================================================================
|
||||
/** Performs an out-of-place FFT, either forward or inverse.
|
||||
The arrays must contain at least getSize() elements.
|
||||
*/
|
||||
void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept;
|
||||
|
||||
/** Performs an in-place forward transform on a block of real data.
|
||||
|
||||
As the coefficients of the negative frequencies (frequencies higher than
|
||||
N/2 or pi) are the complex conjugate of their positive counterparts,
|
||||
it may not be necessary to calculate them for your particular application.
|
||||
You can use dontCalculateNegativeFrequencies to let the FFT
|
||||
engine know that you do not plan on using them. Note that this is only a
|
||||
hint: some FFT engines (currently only the Fallback engine), will still
|
||||
calculate the negative frequencies even if dontCalculateNegativeFrequencies
|
||||
is true.
|
||||
|
||||
The size of the array passed in must be 2 * getSize(), and the first half
|
||||
should contain your raw input sample data. On return, if
|
||||
dontCalculateNegativeFrequencies is false, the array will contain size
|
||||
complex real + imaginary parts data interleaved. If
|
||||
dontCalculateNegativeFrequencies is true, the array will contain at least
|
||||
(size / 2) + 1 complex numbers. Both outputs can be passed to
|
||||
performRealOnlyInverseTransform() in order to convert it back to reals.
|
||||
*/
|
||||
void performRealOnlyForwardTransform (float* inputOutputData,
|
||||
bool dontCalculateNegativeFrequencies = false) const noexcept;
|
||||
|
||||
/** Performs a reverse operation to data created in performRealOnlyForwardTransform().
|
||||
|
||||
Although performRealOnlyInverseTransform will only use the first ((size / 2) + 1)
|
||||
complex numbers, the size of the array passed in must still be 2 * getSize(), as some
|
||||
FFT engines require the extra space for the calculation. On return, the first half of the
|
||||
array will contain the reconstituted samples.
|
||||
*/
|
||||
void performRealOnlyInverseTransform (float* inputOutputData) const noexcept;
|
||||
|
||||
/** Takes an array and simply transforms it to the magnitude frequency response
|
||||
spectrum. This may be handy for things like frequency displays or analysis.
|
||||
The size of the array passed in must be 2 * getSize().
|
||||
*/
|
||||
void performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept;
|
||||
|
||||
/** Returns the number of data points that this FFT was created to work with. */
|
||||
int getSize() const noexcept { return size; }
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
/* internal */
|
||||
struct Instance;
|
||||
template <typename> struct EngineImpl;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct Engine;
|
||||
|
||||
std::unique_ptr<Instance> engine;
|
||||
int size;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFT)
|
||||
};
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/**
|
||||
Performs a fast fourier transform.
|
||||
|
||||
This is only a simple low-footprint implementation and isn't tuned for speed - it may
|
||||
be useful for simple applications where one of the more complex FFT libraries would be
|
||||
overkill. (But in the future it may end up becoming optimised of course...)
|
||||
|
||||
The FFT class itself contains lookup tables, so there's some overhead in creating
|
||||
one, you should create and cache an FFT object for each size/direction of transform
|
||||
that you need, and re-use them to perform the actual operation.
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
class JUCE_API FFT
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Initialises an object for performing forward and inverse FFT with the given size.
|
||||
The number of points the FFT will operate on will be 2 ^ order.
|
||||
*/
|
||||
FFT (int order);
|
||||
|
||||
/** Move constructor. */
|
||||
FFT (FFT&&) noexcept;
|
||||
|
||||
/** Move assignment operator. */
|
||||
FFT& operator= (FFT&&) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~FFT();
|
||||
|
||||
//==============================================================================
|
||||
/** Performs an out-of-place FFT, either forward or inverse.
|
||||
The arrays must contain at least getSize() elements.
|
||||
*/
|
||||
void perform (const Complex<float>* input, Complex<float>* output, bool inverse) const noexcept;
|
||||
|
||||
/** Performs an in-place forward transform on a block of real data.
|
||||
|
||||
As the coefficients of the negative frequencies (frequencies higher than
|
||||
N/2 or pi) are the complex conjugate of their positive counterparts,
|
||||
it may not be necessary to calculate them for your particular application.
|
||||
You can use onlyCalculateNonNegativeFrequencies to let the FFT
|
||||
engine know that you do not plan on using them. Note that this is only a
|
||||
hint: some FFT engines (currently only the Fallback engine), will still
|
||||
calculate the negative frequencies even if onlyCalculateNonNegativeFrequencies
|
||||
is true.
|
||||
|
||||
The size of the array passed in must be 2 * getSize(), and the first half
|
||||
should contain your raw input sample data. On return, if
|
||||
onlyCalculateNonNegativeFrequencies is false, the array will contain size
|
||||
complex real + imaginary parts data interleaved. If
|
||||
onlyCalculateNonNegativeFrequencies is true, the array will contain at least
|
||||
(size / 2) + 1 complex numbers. Both outputs can be passed to
|
||||
performRealOnlyInverseTransform() in order to convert it back to reals.
|
||||
*/
|
||||
void performRealOnlyForwardTransform (float* inputOutputData,
|
||||
bool onlyCalculateNonNegativeFrequencies = false) const noexcept;
|
||||
|
||||
/** Performs a reverse operation to data created in performRealOnlyForwardTransform().
|
||||
|
||||
Although performRealOnlyInverseTransform will only use the first ((size / 2) + 1)
|
||||
complex numbers, the size of the array passed in must still be 2 * getSize(), as some
|
||||
FFT engines require the extra space for the calculation. On return, the first half of the
|
||||
array will contain the reconstituted samples.
|
||||
*/
|
||||
void performRealOnlyInverseTransform (float* inputOutputData) const noexcept;
|
||||
|
||||
/** Takes an array and simply transforms it to the magnitude frequency response
|
||||
spectrum. This may be handy for things like frequency displays or analysis.
|
||||
The size of the array passed in must be 2 * getSize().
|
||||
|
||||
On return, if onlyCalculateNonNegativeFrequencies is false, the array will contain size
|
||||
magnitude values. If onlyCalculateNonNegativeFrequencies is true, the array will contain
|
||||
at least size / 2 + 1 magnitude values.
|
||||
*/
|
||||
void performFrequencyOnlyForwardTransform (float* inputOutputData,
|
||||
bool onlyCalculateNonNegativeFrequencies = false) const noexcept;
|
||||
|
||||
/** Returns the number of data points that this FFT was created to work with. */
|
||||
int getSize() const noexcept { return size; }
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
/* internal */
|
||||
struct Instance;
|
||||
template <typename> struct EngineImpl;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct Engine;
|
||||
|
||||
std::unique_ptr<Instance> engine;
|
||||
int size;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FFT)
|
||||
};
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
|
@ -1,214 +1,218 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
struct FFTUnitTest : public UnitTest
|
||||
{
|
||||
FFTUnitTest()
|
||||
: UnitTest ("FFT", UnitTestCategories::dsp)
|
||||
{}
|
||||
|
||||
static void fillRandom (Random& random, Complex<float>* buffer, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
buffer[i] = Complex<float> ((2.0f * random.nextFloat()) - 1.0f,
|
||||
(2.0f * random.nextFloat()) - 1.0f);
|
||||
}
|
||||
|
||||
static void fillRandom (Random& random, float* buffer, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
buffer[i] = (2.0f * random.nextFloat()) - 1.0f;
|
||||
}
|
||||
|
||||
static Complex<float> freqConvolution (const Complex<float>* in, float freq, size_t n)
|
||||
{
|
||||
Complex<float> sum (0.0, 0.0);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += in[i] * exp (Complex<float> (0, static_cast<float> (i) * freq));
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void performReferenceFourier (const Complex<float>* in, Complex<float>* out,
|
||||
size_t n, bool reverse)
|
||||
{
|
||||
auto base_freq = static_cast<float> (((reverse ? 1.0 : -1.0) * MathConstants<double>::twoPi)
|
||||
/ static_cast<float> (n));
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
out[i] = freqConvolution (in, static_cast<float>(i) * base_freq, n);
|
||||
}
|
||||
|
||||
static void performReferenceFourier (const float* in, Complex<float>* out,
|
||||
size_t n, bool reverse)
|
||||
{
|
||||
HeapBlock<Complex<float>> buffer (n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
buffer.getData()[i] = Complex<float> (in[i], 0.0f);
|
||||
|
||||
float base_freq = static_cast<float> (((reverse ? 1.0 : -1.0) * MathConstants<double>::twoPi)
|
||||
/ static_cast<float> (n));
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
out[i] = freqConvolution (buffer.getData(), static_cast<float>(i) * base_freq, n);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
static bool checkArrayIsSimilar (Type* a, Type* b, size_t n) noexcept
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
if (std::abs (a[i] - b[i]) > 1e-3f)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct RealTest
|
||||
{
|
||||
static void run (FFTUnitTest& u)
|
||||
{
|
||||
Random random (378272);
|
||||
|
||||
for (size_t order = 0; order <= 8; ++order)
|
||||
{
|
||||
auto n = (1u << order);
|
||||
|
||||
FFT fft ((int) order);
|
||||
|
||||
HeapBlock<float> input (n);
|
||||
HeapBlock<Complex<float>> reference (n), output (n);
|
||||
|
||||
fillRandom (random, input.getData(), n);
|
||||
performReferenceFourier (input.getData(), reference.getData(), n, false);
|
||||
|
||||
// fill only first half with real numbers
|
||||
zeromem (output.getData(), n * sizeof (Complex<float>));
|
||||
memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
|
||||
|
||||
fft.performRealOnlyForwardTransform ((float*) output.getData());
|
||||
u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), n));
|
||||
|
||||
// fill only first half with real numbers
|
||||
zeromem (output.getData(), n * sizeof (Complex<float>));
|
||||
memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
|
||||
|
||||
fft.performRealOnlyForwardTransform ((float*) output.getData(), true);
|
||||
std::fill (reference.getData() + ((n >> 1) + 1), reference.getData() + n, std::complex<float> (0.0f));
|
||||
u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), (n >> 1) + 1));
|
||||
|
||||
memcpy (output.getData(), reference.getData(), n * sizeof (Complex<float>));
|
||||
fft.performRealOnlyInverseTransform ((float*) output.getData());
|
||||
u.expect (checkArrayIsSimilar ((float*) output.getData(), input.getData(), n));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FrequencyOnlyTest
|
||||
{
|
||||
static void run(FFTUnitTest& u)
|
||||
{
|
||||
Random random (378272);
|
||||
for (size_t order = 0; order <= 8; ++order)
|
||||
{
|
||||
auto n = (1u << order);
|
||||
|
||||
FFT fft ((int) order);
|
||||
|
||||
HeapBlock<float> inout (n << 1), reference (n << 1);
|
||||
HeapBlock<Complex<float>> frequency (n);
|
||||
|
||||
fillRandom (random, inout.getData(), n);
|
||||
zeromem (reference.getData(), sizeof (float) * ((size_t) n << 1));
|
||||
performReferenceFourier (inout.getData(), frequency.getData(), n, false);
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
reference.getData()[i] = std::abs (frequency.getData()[i]);
|
||||
|
||||
fft.performFrequencyOnlyForwardTransform (inout.getData());
|
||||
|
||||
u.expect (checkArrayIsSimilar (inout.getData(), reference.getData(), n));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplexTest
|
||||
{
|
||||
static void run(FFTUnitTest& u)
|
||||
{
|
||||
Random random (378272);
|
||||
|
||||
for (size_t order = 0; order <= 7; ++order)
|
||||
{
|
||||
auto n = (1u << order);
|
||||
|
||||
FFT fft ((int) order);
|
||||
|
||||
HeapBlock<Complex<float>> input (n), buffer (n), output (n), reference (n);
|
||||
|
||||
fillRandom (random, input.getData(), n);
|
||||
performReferenceFourier (input.getData(), reference.getData(), n, false);
|
||||
|
||||
memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
|
||||
fft.perform (buffer.getData(), output.getData(), false);
|
||||
|
||||
u.expect (checkArrayIsSimilar (output.getData(), reference.getData(), n));
|
||||
|
||||
memcpy (buffer.getData(), reference.getData(), sizeof (Complex<float>) * n);
|
||||
fft.perform (buffer.getData(), output.getData(), true);
|
||||
|
||||
|
||||
u.expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class TheTest>
|
||||
void runTestForAllTypes (const char* unitTestName)
|
||||
{
|
||||
beginTest (unitTestName);
|
||||
|
||||
TheTest::run (*this);
|
||||
}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
runTestForAllTypes<RealTest> ("Real input numbers Test");
|
||||
runTestForAllTypes<FrequencyOnlyTest> ("Frequency only Test");
|
||||
runTestForAllTypes<ComplexTest> ("Complex input numbers Test");
|
||||
}
|
||||
};
|
||||
|
||||
static FFTUnitTest fftUnitTest;
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
struct FFTUnitTest : public UnitTest
|
||||
{
|
||||
FFTUnitTest()
|
||||
: UnitTest ("FFT", UnitTestCategories::dsp)
|
||||
{}
|
||||
|
||||
static void fillRandom (Random& random, Complex<float>* buffer, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
buffer[i] = Complex<float> ((2.0f * random.nextFloat()) - 1.0f,
|
||||
(2.0f * random.nextFloat()) - 1.0f);
|
||||
}
|
||||
|
||||
static void fillRandom (Random& random, float* buffer, size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
buffer[i] = (2.0f * random.nextFloat()) - 1.0f;
|
||||
}
|
||||
|
||||
static Complex<float> freqConvolution (const Complex<float>* in, float freq, size_t n)
|
||||
{
|
||||
Complex<float> sum (0.0, 0.0);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += in[i] * exp (Complex<float> (0, static_cast<float> (i) * freq));
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void performReferenceFourier (const Complex<float>* in, Complex<float>* out,
|
||||
size_t n, bool reverse)
|
||||
{
|
||||
auto base_freq = static_cast<float> (((reverse ? 1.0 : -1.0) * MathConstants<double>::twoPi)
|
||||
/ static_cast<float> (n));
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
out[i] = freqConvolution (in, static_cast<float>(i) * base_freq, n);
|
||||
}
|
||||
|
||||
static void performReferenceFourier (const float* in, Complex<float>* out,
|
||||
size_t n, bool reverse)
|
||||
{
|
||||
HeapBlock<Complex<float>> buffer (n);
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
buffer.getData()[i] = Complex<float> (in[i], 0.0f);
|
||||
|
||||
float base_freq = static_cast<float> (((reverse ? 1.0 : -1.0) * MathConstants<double>::twoPi)
|
||||
/ static_cast<float> (n));
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
out[i] = freqConvolution (buffer.getData(), static_cast<float>(i) * base_freq, n);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
template <typename Type>
|
||||
static bool checkArrayIsSimilar (Type* a, Type* b, size_t n) noexcept
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
if (std::abs (a[i] - b[i]) > 1e-3f)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct RealTest
|
||||
{
|
||||
static void run (FFTUnitTest& u)
|
||||
{
|
||||
Random random (378272);
|
||||
|
||||
for (size_t order = 0; order <= 8; ++order)
|
||||
{
|
||||
auto n = (1u << order);
|
||||
|
||||
FFT fft ((int) order);
|
||||
|
||||
HeapBlock<float> input (n);
|
||||
HeapBlock<Complex<float>> reference (n), output (n);
|
||||
|
||||
fillRandom (random, input.getData(), n);
|
||||
performReferenceFourier (input.getData(), reference.getData(), n, false);
|
||||
|
||||
// fill only first half with real numbers
|
||||
zeromem (output.getData(), n * sizeof (Complex<float>));
|
||||
memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
|
||||
|
||||
fft.performRealOnlyForwardTransform ((float*) output.getData());
|
||||
u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), n));
|
||||
|
||||
// fill only first half with real numbers
|
||||
zeromem (output.getData(), n * sizeof (Complex<float>));
|
||||
memcpy (reinterpret_cast<float*> (output.getData()), input.getData(), n * sizeof (float));
|
||||
|
||||
fft.performRealOnlyForwardTransform ((float*) output.getData(), true);
|
||||
std::fill (reference.getData() + ((n >> 1) + 1), reference.getData() + n, std::complex<float> (0.0f));
|
||||
u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), (n >> 1) + 1));
|
||||
|
||||
memcpy (output.getData(), reference.getData(), n * sizeof (Complex<float>));
|
||||
fft.performRealOnlyInverseTransform ((float*) output.getData());
|
||||
u.expect (checkArrayIsSimilar ((float*) output.getData(), input.getData(), n));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FrequencyOnlyTest
|
||||
{
|
||||
static void run (FFTUnitTest& u)
|
||||
{
|
||||
Random random (378272);
|
||||
for (size_t order = 0; order <= 8; ++order)
|
||||
{
|
||||
auto n = (1u << order);
|
||||
|
||||
FFT fft ((int) order);
|
||||
|
||||
std::vector<float> inout ((size_t) n << 1), reference ((size_t) n << 1);
|
||||
std::vector<Complex<float>> frequency (n);
|
||||
|
||||
fillRandom (random, inout.data(), n);
|
||||
zeromem (reference.data(), sizeof (float) * ((size_t) n << 1));
|
||||
performReferenceFourier (inout.data(), frequency.data(), n, false);
|
||||
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
reference[i] = std::abs (frequency[i]);
|
||||
|
||||
for (auto ignoreNegative : { false, true })
|
||||
{
|
||||
auto inoutCopy = inout;
|
||||
fft.performFrequencyOnlyForwardTransform (inoutCopy.data(), ignoreNegative);
|
||||
auto numMatching = ignoreNegative ? (n / 2) + 1 : n;
|
||||
u.expect (checkArrayIsSimilar (inoutCopy.data(), reference.data(), numMatching));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ComplexTest
|
||||
{
|
||||
static void run(FFTUnitTest& u)
|
||||
{
|
||||
Random random (378272);
|
||||
|
||||
for (size_t order = 0; order <= 7; ++order)
|
||||
{
|
||||
auto n = (1u << order);
|
||||
|
||||
FFT fft ((int) order);
|
||||
|
||||
HeapBlock<Complex<float>> input (n), buffer (n), output (n), reference (n);
|
||||
|
||||
fillRandom (random, input.getData(), n);
|
||||
performReferenceFourier (input.getData(), reference.getData(), n, false);
|
||||
|
||||
memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
|
||||
fft.perform (buffer.getData(), output.getData(), false);
|
||||
|
||||
u.expect (checkArrayIsSimilar (output.getData(), reference.getData(), n));
|
||||
|
||||
memcpy (buffer.getData(), reference.getData(), sizeof (Complex<float>) * n);
|
||||
fft.perform (buffer.getData(), output.getData(), true);
|
||||
|
||||
|
||||
u.expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class TheTest>
|
||||
void runTestForAllTypes (const char* unitTestName)
|
||||
{
|
||||
beginTest (unitTestName);
|
||||
|
||||
TheTest::run (*this);
|
||||
}
|
||||
|
||||
void runTest() override
|
||||
{
|
||||
runTestForAllTypes<RealTest> ("Real input numbers Test");
|
||||
runTestForAllTypes<FrequencyOnlyTest> ("Frequency only Test");
|
||||
runTestForAllTypes<ComplexTest> ("Complex input numbers Test");
|
||||
}
|
||||
};
|
||||
|
||||
static FFTUnitTest fftUnitTest;
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
|
@ -1,196 +1,196 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
template <typename FloatType>
|
||||
static FloatType ncos (size_t order, size_t i, size_t size) noexcept
|
||||
{
|
||||
return std::cos (static_cast<FloatType> (order * i)
|
||||
* MathConstants<FloatType>::pi / static_cast<FloatType> (size - 1));
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
WindowingFunction<FloatType>::WindowingFunction (size_t size, WindowingMethod type, bool normalise, FloatType beta)
|
||||
{
|
||||
fillWindowingTables (size, type, normalise, beta);
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
void WindowingFunction<FloatType>::fillWindowingTables (size_t size, WindowingMethod type,
|
||||
bool normalise, FloatType beta) noexcept
|
||||
{
|
||||
windowTable.resize (static_cast<int> (size));
|
||||
fillWindowingTables (windowTable.getRawDataPointer(), size, type, normalise, beta);
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
void WindowingFunction<FloatType>::fillWindowingTables (FloatType* samples, size_t size,
|
||||
WindowingMethod type, bool normalise,
|
||||
FloatType beta) noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case rectangular:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
samples[i] = static_cast<FloatType> (1);
|
||||
}
|
||||
break;
|
||||
|
||||
case triangular:
|
||||
{
|
||||
auto halfSlots = static_cast<FloatType> (0.5) * static_cast<FloatType> (size - 1);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
samples[i] = static_cast<FloatType> (1.0) - std::abs ((static_cast<FloatType> (i) - halfSlots) / halfSlots);
|
||||
}
|
||||
break;
|
||||
|
||||
case hann:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
samples[i] = static_cast<FloatType> (0.5 - 0.5 * cos2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case hamming:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
samples[i] = static_cast<FloatType> (0.54 - 0.46 * cos2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blackman:
|
||||
{
|
||||
constexpr FloatType alpha = 0.16f;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
auto cos4 = ncos<FloatType> (4, i, size);
|
||||
|
||||
samples[i] = static_cast<FloatType> (0.5 * (1 - alpha) - 0.5 * cos2 + 0.5 * alpha * cos4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blackmanHarris:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
auto cos4 = ncos<FloatType> (4, i, size);
|
||||
auto cos6 = ncos<FloatType> (6, i, size);
|
||||
|
||||
samples[i] = static_cast<FloatType> (0.35875 - 0.48829 * cos2 + 0.14128 * cos4 - 0.01168 * cos6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case flatTop:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
auto cos4 = ncos<FloatType> (4, i, size);
|
||||
auto cos6 = ncos<FloatType> (6, i, size);
|
||||
auto cos8 = ncos<FloatType> (8, i, size);
|
||||
|
||||
samples[i] = static_cast<FloatType> (1.0 - 1.93 * cos2 + 1.29 * cos4 - 0.388 * cos6 + 0.028 * cos8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kaiser:
|
||||
{
|
||||
const double factor = 1.0 / SpecialFunctions::besselI0 (beta);
|
||||
const auto doubleSize = (double) size;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
samples[i] = static_cast<FloatType> (SpecialFunctions::besselI0 (beta * std::sqrt (1.0 - std::pow (((double) i - 0.5 * (doubleSize - 1.0))
|
||||
/ ( 0.5 * (doubleSize - 1.0)), 2.0)))
|
||||
* factor);
|
||||
}
|
||||
break;
|
||||
|
||||
case numWindowingMethods:
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
// DC frequency amplitude must be one
|
||||
if (normalise)
|
||||
{
|
||||
FloatType sum (0);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
sum += samples[i];
|
||||
|
||||
auto factor = static_cast<FloatType> (size) / sum;
|
||||
|
||||
FloatVectorOperations::multiply (samples, factor, static_cast<int> (size));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
void WindowingFunction<FloatType>::multiplyWithWindowingTable (FloatType* samples, size_t size) noexcept
|
||||
{
|
||||
FloatVectorOperations::multiply (samples, windowTable.getRawDataPointer(), jmin (static_cast<int> (size), windowTable.size()));
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
const char* WindowingFunction<FloatType>::getWindowingMethodName (WindowingMethod type) noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case rectangular: return "Rectangular";
|
||||
case triangular: return "Triangular";
|
||||
case hann: return "Hann";
|
||||
case hamming: return "Hamming";
|
||||
case blackman: return "Blackman";
|
||||
case blackmanHarris: return "Blackman-Harris";
|
||||
case flatTop: return "Flat Top";
|
||||
case kaiser: return "Kaiser";
|
||||
case numWindowingMethods:
|
||||
default: jassertfalse; return "";
|
||||
}
|
||||
}
|
||||
|
||||
template class WindowingFunction<float>;
|
||||
template class WindowingFunction<double>;
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
template <typename FloatType>
|
||||
static FloatType ncos (size_t order, size_t i, size_t size) noexcept
|
||||
{
|
||||
return std::cos (static_cast<FloatType> (order * i)
|
||||
* MathConstants<FloatType>::pi / static_cast<FloatType> (size - 1));
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
WindowingFunction<FloatType>::WindowingFunction (size_t size, WindowingMethod type, bool normalise, FloatType beta)
|
||||
{
|
||||
fillWindowingTables (size, type, normalise, beta);
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
void WindowingFunction<FloatType>::fillWindowingTables (size_t size, WindowingMethod type,
|
||||
bool normalise, FloatType beta) noexcept
|
||||
{
|
||||
windowTable.resize (static_cast<int> (size));
|
||||
fillWindowingTables (windowTable.getRawDataPointer(), size, type, normalise, beta);
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
void WindowingFunction<FloatType>::fillWindowingTables (FloatType* samples, size_t size,
|
||||
WindowingMethod type, bool normalise,
|
||||
FloatType beta) noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case rectangular:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
samples[i] = static_cast<FloatType> (1);
|
||||
}
|
||||
break;
|
||||
|
||||
case triangular:
|
||||
{
|
||||
auto halfSlots = static_cast<FloatType> (0.5) * static_cast<FloatType> (size - 1);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
samples[i] = static_cast<FloatType> (1.0) - std::abs ((static_cast<FloatType> (i) - halfSlots) / halfSlots);
|
||||
}
|
||||
break;
|
||||
|
||||
case hann:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
samples[i] = static_cast<FloatType> (0.5 - 0.5 * cos2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case hamming:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
samples[i] = static_cast<FloatType> (0.54 - 0.46 * cos2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blackman:
|
||||
{
|
||||
constexpr FloatType alpha = 0.16f;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
auto cos4 = ncos<FloatType> (4, i, size);
|
||||
|
||||
samples[i] = static_cast<FloatType> (0.5 * (1 - alpha) - 0.5 * cos2 + 0.5 * alpha * cos4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case blackmanHarris:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
auto cos4 = ncos<FloatType> (4, i, size);
|
||||
auto cos6 = ncos<FloatType> (6, i, size);
|
||||
|
||||
samples[i] = static_cast<FloatType> (0.35875 - 0.48829 * cos2 + 0.14128 * cos4 - 0.01168 * cos6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case flatTop:
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto cos2 = ncos<FloatType> (2, i, size);
|
||||
auto cos4 = ncos<FloatType> (4, i, size);
|
||||
auto cos6 = ncos<FloatType> (6, i, size);
|
||||
auto cos8 = ncos<FloatType> (8, i, size);
|
||||
|
||||
samples[i] = static_cast<FloatType> (1.0 - 1.93 * cos2 + 1.29 * cos4 - 0.388 * cos6 + 0.028 * cos8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kaiser:
|
||||
{
|
||||
const double factor = 1.0 / SpecialFunctions::besselI0 (beta);
|
||||
const auto doubleSize = (double) size;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
samples[i] = static_cast<FloatType> (SpecialFunctions::besselI0 (beta * std::sqrt (1.0 - std::pow (((double) i - 0.5 * (doubleSize - 1.0))
|
||||
/ ( 0.5 * (doubleSize - 1.0)), 2.0)))
|
||||
* factor);
|
||||
}
|
||||
break;
|
||||
|
||||
case numWindowingMethods:
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
// DC frequency amplitude must be one
|
||||
if (normalise)
|
||||
{
|
||||
FloatType sum (0);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
sum += samples[i];
|
||||
|
||||
auto factor = static_cast<FloatType> (size) / sum;
|
||||
|
||||
FloatVectorOperations::multiply (samples, factor, static_cast<int> (size));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
void WindowingFunction<FloatType>::multiplyWithWindowingTable (FloatType* samples, size_t size) const noexcept
|
||||
{
|
||||
FloatVectorOperations::multiply (samples, windowTable.getRawDataPointer(), jmin (static_cast<int> (size), windowTable.size()));
|
||||
}
|
||||
|
||||
template <typename FloatType>
|
||||
const char* WindowingFunction<FloatType>::getWindowingMethodName (WindowingMethod type) noexcept
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case rectangular: return "Rectangular";
|
||||
case triangular: return "Triangular";
|
||||
case hann: return "Hann";
|
||||
case hamming: return "Hamming";
|
||||
case blackman: return "Blackman";
|
||||
case blackmanHarris: return "Blackman-Harris";
|
||||
case flatTop: return "Flat Top";
|
||||
case kaiser: return "Kaiser";
|
||||
case numWindowingMethods:
|
||||
default: jassertfalse; return "";
|
||||
}
|
||||
}
|
||||
|
||||
template class WindowingFunction<float>;
|
||||
template class WindowingFunction<double>;
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
|
@ -1,111 +1,111 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/**
|
||||
A class which provides multiple windowing functions useful for filter design
|
||||
and spectrum analyzers.
|
||||
|
||||
The different functions provided here can be used by creating either a
|
||||
WindowingFunction object, or a static function to fill an array with the
|
||||
windowing method samples.
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
template <typename FloatType>
|
||||
class JUCE_API WindowingFunction
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** The windowing methods available. */
|
||||
enum WindowingMethod
|
||||
{
|
||||
rectangular = 0,
|
||||
triangular,
|
||||
hann,
|
||||
hamming,
|
||||
blackman,
|
||||
blackmanHarris,
|
||||
flatTop,
|
||||
kaiser,
|
||||
numWindowingMethods
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** This constructor automatically fills a buffer of the specified size using
|
||||
the fillWindowingTables function and the specified arguments.
|
||||
|
||||
@see fillWindowingTables
|
||||
*/
|
||||
WindowingFunction (size_t size, WindowingMethod,
|
||||
bool normalise = true, FloatType beta = 0);
|
||||
|
||||
//==============================================================================
|
||||
/** Fills the content of the object array with a given windowing method table.
|
||||
|
||||
@param size the size of the destination buffer allocated in the object
|
||||
@param type the type of windowing method being used
|
||||
@param normalise if the result must be normalised, creating a DC amplitude
|
||||
response of one
|
||||
@param beta an optional argument useful only for Kaiser's method
|
||||
which must be positive and sets the properties of the
|
||||
method (bandwidth and attenuation increases with beta)
|
||||
*/
|
||||
void fillWindowingTables (size_t size, WindowingMethod type,
|
||||
bool normalise = true, FloatType beta = 0) noexcept;
|
||||
|
||||
/** Fills the content of an array with a given windowing method table.
|
||||
|
||||
@param samples the destination buffer pointer
|
||||
@param size the size of the destination buffer allocated in the object
|
||||
@param normalise if the result must be normalised, creating a DC amplitude
|
||||
response of one
|
||||
@param beta an optional argument useful only for Kaiser's method,
|
||||
which must be positive and sets the properties of the
|
||||
method (bandwidth and attenuation increases with beta)
|
||||
*/
|
||||
static void fillWindowingTables (FloatType* samples, size_t size, WindowingMethod,
|
||||
bool normalise = true, FloatType beta = 0) noexcept;
|
||||
|
||||
/** Multiplies the content of a buffer with the given window. */
|
||||
void multiplyWithWindowingTable (FloatType* samples, size_t size) noexcept;
|
||||
|
||||
/** Returns the name of a given windowing method. */
|
||||
static const char* getWindowingMethodName (WindowingMethod) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array<FloatType> windowTable;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowingFunction)
|
||||
};
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
namespace dsp
|
||||
{
|
||||
|
||||
/**
|
||||
A class which provides multiple windowing functions useful for filter design
|
||||
and spectrum analyzers.
|
||||
|
||||
The different functions provided here can be used by creating either a
|
||||
WindowingFunction object, or a static function to fill an array with the
|
||||
windowing method samples.
|
||||
|
||||
@tags{DSP}
|
||||
*/
|
||||
template <typename FloatType>
|
||||
class JUCE_API WindowingFunction
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** The windowing methods available. */
|
||||
enum WindowingMethod
|
||||
{
|
||||
rectangular = 0,
|
||||
triangular,
|
||||
hann,
|
||||
hamming,
|
||||
blackman,
|
||||
blackmanHarris,
|
||||
flatTop,
|
||||
kaiser,
|
||||
numWindowingMethods
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** This constructor automatically fills a buffer of the specified size using
|
||||
the fillWindowingTables function and the specified arguments.
|
||||
|
||||
@see fillWindowingTables
|
||||
*/
|
||||
WindowingFunction (size_t size, WindowingMethod,
|
||||
bool normalise = true, FloatType beta = 0);
|
||||
|
||||
//==============================================================================
|
||||
/** Fills the content of the object array with a given windowing method table.
|
||||
|
||||
@param size the size of the destination buffer allocated in the object
|
||||
@param type the type of windowing method being used
|
||||
@param normalise if the result must be normalised, creating a DC amplitude
|
||||
response of one
|
||||
@param beta an optional argument useful only for Kaiser's method
|
||||
which must be positive and sets the properties of the
|
||||
method (bandwidth and attenuation increases with beta)
|
||||
*/
|
||||
void fillWindowingTables (size_t size, WindowingMethod type,
|
||||
bool normalise = true, FloatType beta = 0) noexcept;
|
||||
|
||||
/** Fills the content of an array with a given windowing method table.
|
||||
|
||||
@param samples the destination buffer pointer
|
||||
@param size the size of the destination buffer allocated in the object
|
||||
@param normalise if the result must be normalised, creating a DC amplitude
|
||||
response of one
|
||||
@param beta an optional argument useful only for Kaiser's method,
|
||||
which must be positive and sets the properties of the
|
||||
method (bandwidth and attenuation increases with beta)
|
||||
*/
|
||||
static void fillWindowingTables (FloatType* samples, size_t size, WindowingMethod,
|
||||
bool normalise = true, FloatType beta = 0) noexcept;
|
||||
|
||||
/** Multiplies the content of a buffer with the given window. */
|
||||
void multiplyWithWindowingTable (FloatType* samples, size_t size) const noexcept;
|
||||
|
||||
/** Returns the name of a given windowing method. */
|
||||
static const char* getWindowingMethodName (WindowingMethod) noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array<FloatType> windowTable;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowingFunction)
|
||||
};
|
||||
|
||||
} // namespace dsp
|
||||
} // namespace juce
|
||||
|
Reference in New Issue
Block a user