1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

DSP: Refactored AudioBlock

This commit is contained in:
Tom Poole 2019-08-14 17:14:20 +01:00
parent 462ed5468c
commit 41055ad782
13 changed files with 826 additions and 360 deletions

View file

@ -1,6 +1,35 @@
JUCE breaking changes
=====================
Develop
=======
Change
------
The AudioBlock class has been refactored and some of the method names have
changed. Additionally the `const` behaviour now mirrors that of `std::span`,
with the `const`-ness of the contained data decoupled from the `const`-ness of
the container.
Possible Issues
---------------
Code using the old method names or violating `const`-correctness will fail to
compile.
Workaround
----------
You will need to update your code to use the new method names and select an
appropriate `const`-ness for the AudioBlock and the data it references.
Rationale
---------
The names of some of the methods in the AudioBlock class were ambiguous,
particularly when chaining methods involving references to other blocks. The
interaction between the `const`-ness of the AudioBlock and the `const`-ness of
the referenced data was also ambiguous and has now been standardised to the
same behaviour as other non-owning data views like `std::span`.
Version 5.4.4
=============

View file

@ -73,11 +73,11 @@ struct OscillatorDemoDSP
void process (const ProcessContextReplacing<float>& context)
{
tempBuffer.copy (context.getInputBlock());
tempBuffer.multiply (static_cast<float> (fileMix));
tempBuffer.copyFrom (context.getInputBlock());
tempBuffer.multiplyBy (static_cast<float> (fileMix));
oscillators[currentOscillatorIdx].process (context);
context.getOutputBlock().multiply (static_cast<float> (1.0 - fileMix));
context.getOutputBlock().multiplyBy (static_cast<float> (1.0 - fileMix));
context.getOutputBlock().add (tempBuffer);

View file

@ -196,7 +196,7 @@ public:
process (dsp::ProcessContextReplacing<float> (firstChan));
for (size_t chan = 1; chan < block.getNumChannels(); ++chan)
block.getSingleChannelBlock (chan).copy (firstChan);
block.getSingleChannelBlock (chan).copyFrom (firstChan);
}
}

View file

@ -78,14 +78,14 @@ public:
//==============================================================================
/** Create a zero-sized AudioBlock. */
forcedinline AudioBlock() noexcept = default;
AudioBlock() noexcept = default;
/** Creates an AudioBlock from a pointer to an array of channels.
AudioBlock does not copy nor own the memory pointed to by dataToUse.
Therefore it is the user's responsibility to ensure that the memory is retained
throughout the life-time of the AudioBlock and released when no longer needed.
*/
forcedinline AudioBlock (SampleType* const* channelData,
constexpr AudioBlock (SampleType* const* channelData,
size_t numberOfChannels, size_t numberOfSamples) noexcept
: channels (channelData),
numChannels (static_cast<ChannelCountType> (numberOfChannels)),
@ -98,7 +98,7 @@ public:
Therefore it is the user's responsibility to ensure that the memory is retained
throughout the life-time of the AudioBlock and released when no longer needed.
*/
forcedinline AudioBlock (SampleType* const* channelData, size_t numberOfChannels,
constexpr AudioBlock (SampleType* const* channelData, size_t numberOfChannels,
size_t startSampleIndex, size_t numberOfSamples) noexcept
: channels (channelData),
numChannels (static_cast<ChannelCountType> (numberOfChannels)),
@ -144,7 +144,7 @@ public:
throughout the life-time of the AudioBlock without being modified.
*/
template <typename OtherSampleType>
AudioBlock (AudioBuffer<OtherSampleType>& buffer) noexcept
constexpr AudioBlock (AudioBuffer<OtherSampleType>& buffer) noexcept
: channels (buffer.getArrayOfWritePointers()),
numChannels (static_cast<ChannelCountType> (buffer.getNumChannels())),
numSamples (static_cast<size_t> (buffer.getNumSamples()))
@ -196,7 +196,7 @@ public:
//==============================================================================
template <typename OtherSampleType>
bool operator== (const AudioBlock<OtherSampleType>& other) const noexcept
constexpr bool operator== (const AudioBlock<OtherSampleType>& other) const noexcept
{
return std::equal (channels,
channels + numChannels,
@ -207,25 +207,20 @@ public:
}
template <typename OtherSampleType>
bool operator!= (const AudioBlock<OtherSampleType>& other) const noexcept
constexpr bool operator!= (const AudioBlock<OtherSampleType>& other) const noexcept
{
return ! (*this == other);
}
//==============================================================================
forcedinline size_t getNumSamples() const noexcept { return numSamples; }
forcedinline size_t getNumChannels() const noexcept { return static_cast<size_t> (numChannels); }
/** Returns the number of channels referenced by this block. */
constexpr size_t getNumChannels() const noexcept { return static_cast<size_t> (numChannels); }
/** Returns the number of samples referenced by this block. */
constexpr size_t getNumSamples() const noexcept { return numSamples; }
/** Returns a raw pointer into one of the channels in this block. */
forcedinline const SampleType* getChannelPointer (size_t channel) const noexcept
{
jassert (channel < numChannels);
jassert (numSamples > 0);
return channels[channel] + startSample;
}
/** Returns a raw pointer into one of the channels in this block. */
forcedinline SampleType* getChannelPointer (size_t channel) noexcept
SampleType* getChannelPointer (size_t channel) const noexcept
{
jassert (channel < numChannels);
jassert (numSamples > 0);
@ -233,7 +228,7 @@ public:
}
/** Returns an AudioBlock that represents one of the channels in this block. */
forcedinline AudioBlock getSingleChannelBlock (size_t channel) const noexcept
AudioBlock getSingleChannelBlock (size_t channel) const noexcept
{
jassert (channel < numChannels);
return AudioBlock (channels + channel, 1, startSample, numSamples);
@ -243,7 +238,7 @@ public:
@param channelStart First channel of the subset
@param numChannelsToUse Count of channels in the subset
*/
forcedinline AudioBlock getSubsetChannelBlock (size_t channelStart, size_t numChannelsToUse) const noexcept
AudioBlock getSubsetChannelBlock (size_t channelStart, size_t numChannelsToUse) const noexcept
{
jassert (channelStart < numChannels);
jassert ((channelStart + numChannelsToUse) <= numChannels);
@ -260,7 +255,7 @@ public:
{
jassert (isPositiveAndBelow (channel, numChannels));
jassert (isPositiveAndBelow (sampleIndex, numSamples));
return channels[channel][startSample + sampleIndex];
return channels[channel][(size_t) startSample + (size_t) sampleIndex];
}
/** Modifies a sample in the buffer.
@ -268,11 +263,11 @@ public:
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
void setSample (int destChannel, int destSample, SampleType newValue) noexcept
void setSample (int destChannel, int destSample, SampleType newValue) const noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (isPositiveAndBelow (destSample, numSamples));
channels[destChannel][startSample + destSample] = newValue;
channels[destChannel][(size_t) startSample + (size_t) destSample] = newValue;
}
/** Adds a value to a sample in the buffer.
@ -280,78 +275,51 @@ public:
an assertion will be thrown, but in a release build, you're into 'undefined behaviour'
territory.
*/
void addSample (int destChannel, int destSample, SampleType valueToAdd) noexcept
void addSample (int destChannel, int destSample, SampleType valueToAdd) const noexcept
{
jassert (isPositiveAndBelow (destChannel, numChannels));
jassert (isPositiveAndBelow (destSample, numSamples));
channels[destChannel][startSample + destSample] += valueToAdd;
channels[destChannel][(size_t) startSample + (size_t) destSample] += valueToAdd;
}
//==============================================================================
/** Clear the memory described by this AudioBlock. */
forcedinline AudioBlock& clear() noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
/** Clears the memory referenced by this AudioBlock. */
AudioBlock& clear() noexcept { clearInternal(); return *this; }
const AudioBlock& clear() const noexcept { clearInternal(); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::clear (channelPtr (ch), n);
/** Fills the memory referenced by this AudioBlock with value. */
AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) noexcept { fillInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) const noexcept { fillInternal (value); return *this; }
return *this;
}
/** Fill memory with value. */
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE fill (SampleType value) noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::fill (channelPtr (ch), value, n);
return *this;
}
/** Copy the values in src to the receiver. */
/** Copies the values in src to this block. */
template <typename OtherSampleType>
forcedinline AudioBlock& copy (const AudioBlock<OtherSampleType>& src) noexcept
{
auto maxChannels = jmin (src.numChannels, numChannels);
auto n = static_cast<int> (jmin (src.numSamples, numSamples) * sizeFactor);
AudioBlock& copyFrom (const AudioBlock<OtherSampleType>& src) noexcept { copyFromInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& copyFrom (const AudioBlock<OtherSampleType>& src) const noexcept { copyFromInternal (src); return *this; }
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (channelPtr (ch), src.channelPtr (ch), n);
return *this;
}
/** Copy the values from a JUCE's AudioBuffer to the receiver.
/** Copy the values from a JUCE's AudioBuffer to this block.
All indices and sizes are in the receiver's units, i.e. if SampleType is a
SIMDRegister then incrementing srcPos by one will increase the sample position
in the AudioBuffer's units by a factor of SIMDRegister<SampleType>::SIMDNumElements.
*/
forcedinline AudioBlock& copyFrom (const AudioBuffer<NumericType>& src, size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max())
{
auto srclen = static_cast<size_t> (src.getNumSamples()) / sizeFactor;
auto n = static_cast<int> (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor);
auto maxChannels = jmin (static_cast<size_t> (src.getNumChannels()), static_cast<size_t> (numChannels));
template <typename OtherSampleType>
AudioBlock& copyFrom (const AudioBuffer<OtherSampleType>& src,
size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max()) { copyFromInternal (src, srcPos, dstPos, numElements); return *this; }
template <typename OtherSampleType>
const AudioBlock& copyFrom (const AudioBuffer<OtherSampleType>& src,
size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max()) const { copyFromInternal (src, srcPos, dstPos, numElements); return *this; }
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (channelPtr (ch) + dstPos,
src.getReadPointer (static_cast<int> (ch),
static_cast<int> (srcPos * sizeFactor)),
n);
return *this;
}
/** Copy the values from the receiver to a JUCE's AudioBuffer.
/** Copies the values from this block to an AudioBuffer.
All indices and sizes are in the receiver's units, i.e. if SampleType is a
SIMDRegister then incrementing dstPos by one will increase the sample position
in the AudioBuffer's units by a factor of SIMDRegister<SampleType>::SIMDNumElements.
*/
forcedinline const AudioBlock& copyTo (AudioBuffer<NumericType>& dst, size_t srcPos = 0, size_t dstPos = 0,
void copyTo (AudioBuffer<typename std::remove_const<NumericType>::type>& dst, size_t srcPos = 0, size_t dstPos = 0,
size_t numElements = std::numeric_limits<size_t>::max()) const
{
auto dstlen = static_cast<size_t> (dst.getNumSamples()) / sizeFactor;
@ -361,30 +329,19 @@ public:
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (dst.getWritePointer (static_cast<int> (ch),
static_cast<int> (dstPos * sizeFactor)),
channelPtr (ch) + srcPos, n);
return *this;
getChannelPointer (ch) + srcPos, n);
}
/** Move memory within the receiver from the position srcPos to the position dstPos.
/** Move memory within this block from the position srcPos to the position dstPos.
If numElements is not specified then move will move the maximum amount of memory.
*/
forcedinline AudioBlock& move (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) noexcept
{
jassert (srcPos <= numSamples && dstPos <= numSamples);
auto len = jmin (numSamples - srcPos, numSamples - dstPos, numElements) * sizeof (SampleType);
if (len != 0)
for (size_t ch = 0; ch < numChannels; ++ch)
::memmove (getChannelPointer (ch) + dstPos,
getChannelPointer (ch) + srcPos, len);
return *this;
}
AudioBlock& move (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) noexcept { moveInternal (srcPos, dstPos, numElements); return *this; }
const AudioBlock& move (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) const noexcept { moveInternal (srcPos, dstPos, numElements); return *this; }
//==============================================================================
/** Return a new AudioBlock pointing to a sub-block inside the receiver. This
/** Return a new AudioBlock pointing to a sub-block inside this block. This
function does not copy the memory and you must ensure that the original memory
pointed to by the receiver remains valid through-out the life-time of the
returned sub-block.
@ -393,7 +350,7 @@ public:
will become the first element of the return value.
@param newLength The number of elements of the newly created sub-block.
*/
inline AudioBlock getSubBlock (size_t newOffset, size_t newLength) const noexcept
AudioBlock getSubBlock (size_t newOffset, size_t newLength) const noexcept
{
jassert (newOffset < numSamples);
jassert (newOffset + newLength <= numSamples);
@ -401,318 +358,186 @@ public:
return AudioBlock (channels, numChannels, startSample + newOffset, newLength);
}
/** Return a new AudioBlock pointing to a sub-block inside the receiver. This
/** Return a new AudioBlock pointing to a sub-block inside this block. This
function does not copy the memory and you must ensure that the original memory
pointed to by the receiver remains valid through-out the life-time of the
returned sub-block.
@param newOffset The index of an element inside the receiver which will
@param newOffset The index of an element inside the block which will
will become the first element of the return value.
The return value will include all subsequent elements
of the receiver.
*/
inline AudioBlock getSubBlock (size_t newOffset) const noexcept
AudioBlock getSubBlock (size_t newOffset) const noexcept
{
return getSubBlock (newOffset, getNumSamples() - newOffset);
}
//==============================================================================
/** Adds a fixed value to the receiver. */
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
/** Adds a fixed value to the elements in this block. */
AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) noexcept { addInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE add (SampleType value) const noexcept { addInternal (value); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (channelPtr (ch), value, n);
return *this;
}
/** Adds the source values to the receiver. */
/** Adds the elements in the src block to the elements in this block. */
template <typename OtherSampleType>
forcedinline AudioBlock& add (AudioBlock<OtherSampleType> src) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (channelPtr (ch), src.channelPtr (ch), n);
return *this;
}
/** Adds a fixed value to each source value and stores it in the destination array of the receiver. */
AudioBlock& add (AudioBlock<OtherSampleType> src) noexcept { addInternal (src); return *this; }
template <typename OtherSampleType>
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE add (AudioBlock<OtherSampleType> src, SampleType value) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
const AudioBlock& add (AudioBlock<OtherSampleType> src) const noexcept { addInternal (src); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (channelPtr (ch), src.channelPtr (ch), value, n);
/** Adds a fixed value to each source value and replaces the contents of this block. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, SampleType value) noexcept { replaceWithSumOfInternal (src, value); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock<OtherSampleType> src, SampleType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; }
return *this;
}
/** Adds each source1 value to the corresponding source2 value and stores it in the destination array of the receiver. */
/** Adds each source1 value to the corresponding source2 value and replaces the contents of this block. */
template <typename Src1SampleType, typename Src2SampleType>
forcedinline AudioBlock& add (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (channelPtr (ch), src1.channelPtr (ch), src2.getChannelPointer (ch), n);
return *this;
}
/** Subtracts a fixed value from the receiver. */
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) noexcept
{
return add (value * static_cast<SampleType> (-1.0));
}
/** Subtracts the source values from the receiver. */
template <typename OtherSampleType>
forcedinline AudioBlock& subtract (AudioBlock<OtherSampleType> src) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::subtract (channelPtr (ch), src.channelPtr (ch), n);
return *this;
}
/** Subtracts a fixed value from each source value and stores it in the destination array of the receiver. */
template <typename OtherSampleType>
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE subtract (AudioBlock<OtherSampleType> src, SampleType value) noexcept
{
return add (src, static_cast<SampleType> (-1.0) * value);
}
/** Subtracts each source2 value from the corresponding source1 value and stores it in the destination array of the receiver. */
AudioBlock& replaceWithSumOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithSumOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
forcedinline AudioBlock& subtract (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
const AudioBlock& replaceWithSumOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithSumOfInternal (src1, src2); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::subtract (channelPtr (ch), src1.channelPtr (ch), src2.channelPtr (ch), n);
//==============================================================================
/** Subtracts a fixed value from the elements in this block. */
AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) noexcept { subtractInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (SampleType value) const noexcept { subtractInternal (value); return *this; }
return *this;
}
/** Multiplies a fixed value to the receiver. */
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE multiply (SampleType value) noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (channelPtr (ch), value, n);
return *this;
}
/** Multiplies the source values to the receiver. */
/** Subtracts the source values from the elements in this block. */
template <typename OtherSampleType>
forcedinline AudioBlock& multiply (AudioBlock<OtherSampleType> src) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (channelPtr (ch), src.channelPtr (ch), n);
return *this;
}
/** Multiplies a fixed value to each source value and stores it in the destination array of the receiver. */
AudioBlock& subtract (AudioBlock<OtherSampleType> src) noexcept { subtractInternal (src); return *this; }
template <typename OtherSampleType>
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE multiply (AudioBlock<OtherSampleType> src, SampleType value) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
const AudioBlock& subtract (AudioBlock<OtherSampleType> src) const noexcept { subtractInternal (src); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (channelPtr (ch), src.channelPtr (ch), value, n);
/** Subtracts a fixed value from each source value and replaces the contents of this block. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, SampleType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock<OtherSampleType> src, SampleType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; }
return *this;
}
/** Multiplies each source1 value to the corresponding source2 value and stores it in the destination array of the receiver. */
/** Subtracts each source2 value from the corresponding source1 value and replaces the contents of this block. */
template <typename Src1SampleType, typename Src2SampleType>
forcedinline AudioBlock& multiply (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
AudioBlock& replaceWithDifferenceOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithDifferenceOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithDifferenceOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithDifferenceOfInternal (src1, src2); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (channelPtr (ch), src1.channelPtr (ch), src2.channelPtr (ch), n);
//==============================================================================
/** Multiplies the elements in this block by a fixed value. */
AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (SampleType value) noexcept { multiplyByInternal (value); return *this; }
const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (SampleType value) const noexcept { multiplyByInternal (value); return *this; }
return *this;
}
/** Multiplies the elements in this block by the elements in the src block */
template <typename OtherSampleType>
AudioBlock& multiplyBy (AudioBlock<OtherSampleType> src) noexcept { multiplyByInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& multiplyBy (AudioBlock<OtherSampleType> src) const noexcept { multiplyByInternal (src); return *this; }
/** Multiplies all channels of the AudioBlock by a smoothly changing value and stores them . */
/** Replaces the elements in this block with the product of the elements in the source src block and a fixed value. */
template <typename OtherSampleType>
AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, SampleType value) noexcept { replaceWithProductOfInternal (src, value); return *this; }
template <typename OtherSampleType>
const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock<OtherSampleType> src, SampleType value) const noexcept { replaceWithProductOfInternal (src, value); return *this; }
/** Replaces the elements in this block with the product of the elements in the src1 and scr2 blocks. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithProductOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithProductOfInternal (src1, src2); return *this; }
//==============================================================================
/** Multiplies each channels of this block by a smoothly changing value. */
template <typename SmoothingType>
AudioBlock& multiply (SmoothedValue<SampleType, SmoothingType>& value) noexcept
{
if (! value.isSmoothing())
{
*this *= value.getTargetValue();
}
else
{
for (size_t i = 0; i < numSamples; ++i)
{
const auto scaler = value.getNextValue();
AudioBlock& multiplyBy (SmoothedValue<SampleType, SmoothingType>& value) noexcept { multiplyByInternal (value); return *this; }
template <typename SmoothingType>
const AudioBlock& multiplyBy (SmoothedValue<SampleType, SmoothingType>& value) const noexcept { multiplyByInternal (value); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
channelPtr (ch)[i] *= scaler;
}
}
return *this;
}
/** Multiplies all channels of the source by a smoothly changing value and stores them in the receiver. */
/** Replaces each channel of this block with the product of the src block and a smoothed value. */
template <typename OtherSampleType, typename SmoothingType>
AudioBlock& multiply (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) noexcept
{
jassert (numChannels == src.numChannels);
AudioBlock& replaceWithProductOf (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) noexcept { replaceWithProductOfInternal (src, value); return *this; }
template <typename OtherSampleType, typename SmoothingType>
const AudioBlock& replaceWithProductOf (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) const noexcept { replaceWithProductOfInternal (src, value); return *this; }
if (! value.isSmoothing())
{
multiply (src, value.getTargetValue());
}
else
{
auto n = jmin (numSamples, src.numSamples) * sizeFactor;
for (size_t i = 0; i < n; ++i)
{
const auto scaler = value.getNextValue();
for (size_t ch = 0; ch < numChannels; ++ch)
channelPtr (ch)[i] = scaler * src.getChannelPointer (ch)[i];
}
}
return *this;
}
/** Multiplies each value in src with factor and adds the result to the receiver. */
//==============================================================================
/** Multiplies each value in src by a fixed value and adds the result to this block. */
template <typename OtherSampleType>
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE addWithMultiply (AudioBlock<OtherSampleType> src, SampleType factor) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::addWithMultiply (channelPtr (ch), src.channelPtr (ch), factor, n);
return *this;
}
/** Multiplies each value in srcA with the corresponding value in srcB and adds the result to the receiver. */
template <typename Src1SampleType, typename Src2SampleType>
forcedinline AudioBlock& addWithMultiply (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::addWithMultiply (channelPtr (ch), src1.channelPtr (ch), src2.channelPtr (ch), n);
return *this;
}
/** Negates each value of the receiver. */
forcedinline AudioBlock& negate() noexcept
{
return multiply (static_cast<SampleType> (-1.0));
}
/** Negates each value of source and stores it in the receiver. */
AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, SampleType factor) noexcept { addProductOfInternal (src, factor); return *this; }
template <typename OtherSampleType>
forcedinline AudioBlock& replaceWithNegativeOf (AudioBlock<OtherSampleType> src) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock<OtherSampleType> src, SampleType factor) const noexcept { addProductOfInternal (src, factor); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::negate (channelPtr (ch), src.channelPtr (ch), n);
/** Multiplies each value in srcA with the corresponding value in srcB and adds the result to this block. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& addProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { addProductOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& addProductOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { addProductOfInternal (src1, src2); return *this; }
return *this;
}
//==============================================================================
/** Negates each value of this block. */
AudioBlock& negate() noexcept { negateInternal(); return *this; }
const AudioBlock& negate() const noexcept { negateInternal(); return *this; }
/** Takes the absolute value of each element of src and stores it inside the receiver. */
/** Replaces the contents of this block with the negative of the values in the src block. */
template <typename OtherSampleType>
forcedinline AudioBlock& replaceWithAbsoluteValueOf (AudioBlock<OtherSampleType> src) noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
AudioBlock& replaceWithNegativeOf (AudioBlock<OtherSampleType> src) noexcept { replaceWithNegativeOfInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& replaceWithNegativeOf (AudioBlock<OtherSampleType> src) const noexcept { replaceWithNegativeOfInternal (src); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::abs (channelPtr (ch), src.channelPtr (ch), n);
/** Replaces the contents of this block with the absolute values of the src block. */
template <typename OtherSampleType>
AudioBlock& replaceWithAbsoluteValueOf (AudioBlock<OtherSampleType> src) noexcept { replaceWithAbsoluteValueOfInternal (src); return *this; }
template <typename OtherSampleType>
const AudioBlock& replaceWithAbsoluteValueOf (AudioBlock<OtherSampleType> src) const noexcept { replaceWithAbsoluteValueOfInternal (src); return *this; }
return *this;
}
/** Each element of receiver will be the minimum of the corresponding element of the source arrays. */
//==============================================================================
/** Replaces each element of this block with the minimum of the corresponding element of the source arrays. */
template <typename Src1SampleType, typename Src2SampleType>
forcedinline AudioBlock& min (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::min (channelPtr (ch), src1.channelPtr (ch), src2.channelPtr (ch), n);
return *this;
}
/** Each element of the receiver will be the maximum of the corresponding element of the source arrays. */
AudioBlock& replaceWithMinOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithMinOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
forcedinline AudioBlock& max (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);
const AudioBlock& replaceWithMinOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithMinOfInternal (src1, src2); return *this; }
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::max (channelPtr (ch), src1.channelPtr (ch), src2.channelPtr (ch), n);
return *this;
}
/** Replaces each element of this block with the maximum of the corresponding element of the source arrays. */
template <typename Src1SampleType, typename Src2SampleType>
AudioBlock& replaceWithMaxOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) noexcept { replaceWithMaxOfInternal (src1, src2); return *this; }
template <typename Src1SampleType, typename Src2SampleType>
const AudioBlock& replaceWithMaxOf (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept { replaceWithMaxOfInternal (src1, src2); return *this; }
//==============================================================================
/** Finds the minimum and maximum value of the buffer. */
forcedinline Range<NumericType> findMinAndMax() const noexcept
Range<typename std::remove_const<NumericType>::type> findMinAndMax() const noexcept
{
if (numChannels == 0)
return {};
auto n = static_cast<int> (numSamples * sizeFactor);
auto minmax = FloatVectorOperations::findMinAndMax (channelPtr (0), n);
auto minmax = FloatVectorOperations::findMinAndMax (getChannelPointer (0), n);
for (size_t ch = 1; ch < numChannels; ++ch)
minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (channelPtr (ch), n));
minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getChannelPointer (ch), n));
return minmax;
}
//==============================================================================
// convenient operator wrappers
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType src) noexcept { return add (src); }
forcedinline AudioBlock& operator+= (AudioBlock src) noexcept { return add (src); }
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType src) noexcept { return subtract (src); }
forcedinline AudioBlock& operator-= (AudioBlock src) noexcept { return subtract (src); }
forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType src) noexcept { return multiply (src); }
forcedinline AudioBlock& operator*= (AudioBlock src) noexcept { return multiply (src); }
// Convenient operator wrappers.
AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType value) noexcept { return add (value); }
const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (SampleType value) const noexcept { return add (value); }
AudioBlock& operator+= (AudioBlock src) noexcept { return add (src); }
const AudioBlock& operator+= (AudioBlock src) const noexcept { return add (src); }
AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType value) noexcept { return subtract (value); }
const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (SampleType value) const noexcept { return subtract (value); }
AudioBlock& operator-= (AudioBlock src) noexcept { return subtract (src); }
const AudioBlock& operator-= (AudioBlock src) const noexcept { return subtract (src); }
AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType value) noexcept { return multiplyBy (value); }
const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (SampleType value) const noexcept { return multiplyBy (value); }
AudioBlock& operator*= (AudioBlock src) noexcept { return multiplyBy (src); }
const AudioBlock& operator*= (AudioBlock src) const noexcept { return multiplyBy (src); }
template <typename SmoothingType>
forcedinline AudioBlock& operator*= (SmoothedValue<SampleType, SmoothingType>& value) noexcept { return multiply (value); }
AudioBlock& operator*= (SmoothedValue<SampleType, SmoothingType>& value) noexcept { return multiplyBy (value); }
template <typename SmoothingType>
const AudioBlock& operator*= (SmoothedValue<SampleType, SmoothingType>& value) const noexcept { return multiplyBy (value); }
//==============================================================================
// This class can only be used with floating point types
@ -750,8 +575,277 @@ public:
private:
//==============================================================================
NumericType* channelPtr (size_t ch) noexcept { return reinterpret_cast<NumericType*> (getChannelPointer (ch)); }
const NumericType* channelPtr (size_t ch) const noexcept { return reinterpret_cast<const NumericType*> (getChannelPointer (ch)); }
void JUCE_VECTOR_CALLTYPE clearInternal() const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::clear (getChannelPointer (ch), n);
}
void JUCE_VECTOR_CALLTYPE fillInternal (SampleType value) const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::fill (getChannelPointer (ch), value, n);
}
template <typename OtherSampleType>
void copyFromInternal (const AudioBlock<OtherSampleType>& src) const noexcept
{
auto maxChannels = jmin (src.numChannels, numChannels);
auto n = static_cast<int> (jmin (src.numSamples, numSamples) * sizeFactor);
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (getChannelPointer (ch), src.getChannelPointer (ch), n);
}
template <typename OtherSampleType>
void copyFromInternal (const AudioBuffer<OtherSampleType>& src, size_t srcPos, size_t dstPos, size_t numElements) const
{
auto srclen = static_cast<size_t> (src.getNumSamples()) / sizeFactor;
auto n = static_cast<int> (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor);
auto maxChannels = jmin (static_cast<size_t> (src.getNumChannels()), static_cast<size_t> (numChannels));
for (size_t ch = 0; ch < maxChannels; ++ch)
FloatVectorOperations::copy (getChannelPointer (ch) + dstPos,
src.getReadPointer (static_cast<int> (ch),
static_cast<int> (srcPos * sizeFactor)),
n);
}
void moveInternal (size_t srcPos, size_t dstPos,
size_t numElements = std::numeric_limits<size_t>::max()) const noexcept
{
jassert (srcPos <= numSamples && dstPos <= numSamples);
auto len = jmin (numSamples - srcPos, numSamples - dstPos, numElements) * sizeof (SampleType);
if (len != 0)
for (size_t ch = 0; ch < numChannels; ++ch)
::memmove (getChannelPointer (ch) + dstPos,
getChannelPointer (ch) + srcPos, len);
}
//==============================================================================
void JUCE_VECTOR_CALLTYPE addInternal (SampleType value) const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getChannelPointer (ch), value, n);
}
template <typename OtherSampleType>
void addInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), n);
}
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock<OtherSampleType> src, SampleType value) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), value, n);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithSumOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::add (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);
}
//==============================================================================
constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (SampleType value) const noexcept
{
addInternal (value * static_cast<SampleType> (-1.0));
}
template <typename OtherSampleType>
void subtractInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::subtract (getChannelPointer (ch), src.getChannelPointer (ch), n);
}
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock<OtherSampleType> src, SampleType value) const noexcept
{
replaceWithSumOfInternal (src, static_cast<SampleType> (-1.0) * value);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithDifferenceOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::subtract (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);
}
//==============================================================================
void JUCE_VECTOR_CALLTYPE multiplyByInternal (SampleType value) const noexcept
{
auto n = static_cast<int> (numSamples * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getChannelPointer (ch), value, n);
}
template <typename OtherSampleType>
void multiplyByInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), n);
}
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock<OtherSampleType> src, SampleType value) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), value, n);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithProductOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::multiply (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);
}
template <typename SmoothingType>
void multiplyByInternal (SmoothedValue<SampleType, SmoothingType>& value) const noexcept
{
if (! value.isSmoothing())
{
multiplyByInternal (value.getTargetValue());
}
else
{
for (size_t i = 0; i < numSamples; ++i)
{
const auto scaler = value.getNextValue();
for (size_t ch = 0; ch < numChannels; ++ch)
getChannelPointer (ch)[i] *= scaler;
}
}
}
template <typename OtherSampleType, typename SmoothingType>
void replaceWithProductOfInternal (AudioBlock<OtherSampleType> src, SmoothedValue<SampleType, SmoothingType>& value) const noexcept
{
jassert (numChannels == src.numChannels);
if (! value.isSmoothing())
{
replaceWithProductOfInternal (src, value.getTargetValue());
}
else
{
auto n = jmin (numSamples, src.numSamples) * sizeFactor;
for (size_t i = 0; i < n; ++i)
{
const auto scaler = value.getNextValue();
for (size_t ch = 0; ch < numChannels; ++ch)
getChannelPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i];
}
}
}
//==============================================================================
template <typename OtherSampleType>
void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock<OtherSampleType> src, SampleType factor) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src.getChannelPointer (ch), factor, n);
}
template <typename Src1SampleType, typename Src2SampleType>
void addProductOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);
}
//==============================================================================
constexpr void negateInternal() const noexcept
{
multiplyByInternal (static_cast<SampleType> (-1.0));
}
template <typename OtherSampleType>
void replaceWithNegativeOfInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::negate (getChannelPointer (ch), src.getChannelPointer (ch), n);
}
template <typename OtherSampleType>
void replaceWithAbsoluteValueOfInternal (AudioBlock<OtherSampleType> src) const noexcept
{
jassert (numChannels == src.numChannels);
auto n = static_cast<int> (jmin (numSamples, src.numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::abs (getChannelPointer (ch), src.getChannelPointer (ch), n);
}
//==============================================================================
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithMinOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::min (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);
}
template <typename Src1SampleType, typename Src2SampleType>
void replaceWithMaxOfInternal (AudioBlock<Src1SampleType> src1, AudioBlock<Src2SampleType> src2) const noexcept
{
jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels);
auto n = static_cast<int> (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor);
for (size_t ch = 0; ch < numChannels; ++ch)
FloatVectorOperations::max (getChannelPointer (ch), src1.getChannelPointer (ch), src2.getChannelPointer (ch), n);
}
//==============================================================================
using ChannelCountType = unsigned int;

View file

@ -0,0 +1,342 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
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 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-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
{
class AudioBlockUnitTests : public UnitTest
{
public:
AudioBlockUnitTests()
: UnitTest ("AudioBlock", UnitTestCategories::dsp)
{}
void runTest() override
{
beginTest ("Equality");
{
expect (block == block);
expect (block != otherBlock);
}
beginTest ("Constructors");
{
expect (block == AudioBlock<float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples()));
expect (block == AudioBlock<float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples()));
expect (block == AudioBlock<float> (block));
expect (block == AudioBlock<const float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples()));
expect (block == AudioBlock<const float> (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples()));
expect (block == AudioBlock<const float> (block));
}
beginTest ("Swap");
{
resetBlocks();
expect (block != otherBlock);
expectEquals (block.getSample (0, 0), 1.0f);
expectEquals (block.getSample (0, 4), 5.0f);
expectEquals (otherBlock.getSample (0, 0), -1.0f);
expectEquals (otherBlock.getSample (0, 3), -4.0f);
block.swap (otherBlock);
expect (block != otherBlock);
expectEquals (otherBlock.getSample (0, 0), 1.0f);
expectEquals (otherBlock.getSample (0, 4), 5.0f);
expectEquals (block.getSample (0, 0), -1.0f);
expectEquals (block.getSample (0, 3), -4.0f);
}
beginTest ("Getters and setters");
{
resetBlocks();
expectEquals ((int) block.getNumChannels(), data.getNumChannels());
expectEquals ((int) block.getNumSamples(), data.getNumSamples());
expectEquals (block.getChannelPointer (0)[2], 3.0f);
block.getChannelPointer (0)[2] = 999.0f;
expectEquals (block.getChannelPointer (0)[2], 999.0f);
expectEquals (block.getSample (0, 4), 5.0f);
expectEquals (block.getSample (1, 4), 11.0f);
expectEquals (block.getSingleChannelBlock (1).getSample (0, 3), block.getSample (1, 3));
expectEquals (block.getSubsetChannelBlock (0, 2).getSample (1, 3), block.getSample (1, 3));
expectEquals (block.getSubsetChannelBlock (1, 1).getSample (0, 3), block.getSample (1, 3));
block.setSample (1, 1, 777.0f);
expectEquals (block.getSample (1, 1), 777.0f);
block.addSample (1, 1, 1.0f);
expectEquals (block.getSample (1, 1), 778.0f);
}
beginTest ("Copying");
{
block.clear();
expectEquals (block.getSample (0, 2), 0.0f);
expectEquals (block.getSample (1, 4), 0.0f);
block.fill (456.0f);
expectEquals (block.getSample (0, 2), 456.0f);
expectEquals (block.getSample (1, 4), 456.0f);
block.copyFrom (otherBlock);
expect (block != otherBlock);
expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2));
expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4));
resetBlocks();
AudioBuffer<float> otherBuffer ((int) block.getNumChannels(), (int) block.getNumSamples());
otherBlock.copyTo (otherBuffer);
expectEquals (otherBlock.getSample (0, 2), otherBuffer.getSample (0, 2));
expectEquals (otherBlock.getSample (1, 4), otherBuffer.getSample (1, 4));
block.copyFrom (otherBuffer);
expectEquals (block.getSample (0, 2), otherBlock.getSample (0, 2));
expectEquals (block.getSample (1, 4), otherBlock.getSample (1, 4));
float testSample1 = block.getSample (0, 2);
float testSample2 = block.getSample (1, 3);
expect (testSample1 != block.getSample (0, 4));
expect (testSample2 != block.getSample (1, 5));
block.move (0, 2);
expectEquals (block.getSample (0, 4), testSample1);
expectEquals (block.getSample (1, 5), testSample2);
}
beginTest ("Addition");
{
resetBlocks();
block.add (15.0f);
expectEquals (block.getSample (0, 4), 20.0f);
expectEquals (block.getSample (1, 4), 26.0f);
block.add (otherBlock);
expectEquals (block.getSample (0, 4), 15.0f);
expectEquals (block.getSample (1, 4), 15.0f);
block.replaceWithSumOf (otherBlock, 9.0f);
expectEquals (block.getSample (0, 4), 4.0f);
expectEquals (block.getSample (1, 4), -2.0f);
resetBlocks();
block.replaceWithSumOf (block, otherBlock);
expectEquals (block.getSample (0, 4), 0.0f);
expectEquals (block.getSample (1, 4), 0.0f);
}
beginTest ("Subtraction");
{
resetBlocks();
block.subtract (15.0f);
expectEquals (block.getSample (0, 4), -10.0f);
expectEquals (block.getSample (1, 4), -4.0f);
block.subtract (otherBlock);
expectEquals (block.getSample (0, 4), -5.0f);
expectEquals (block.getSample (1, 4), 7.0f);
block.replaceWithDifferenceOf (otherBlock, 9.0f);
expectEquals (block.getSample (0, 4), -14.0f);
expectEquals (block.getSample (1, 4), -20.0f);
resetBlocks();
block.replaceWithDifferenceOf (block, otherBlock);
expectEquals (block.getSample (0, 4), 10.0f);
expectEquals (block.getSample (1, 4), 22.0f);
}
beginTest ("Multiplication");
{
resetBlocks();
block.multiplyBy (10.0f);
expectEquals (block.getSample (0, 4), 50.0f);
expectEquals (block.getSample (1, 4), 110.0f);
block.multiplyBy (otherBlock);
expectEquals (block.getSample (0, 4), -250.0f);
expectEquals (block.getSample (1, 4), -1210.0f);
block.replaceWithProductOf (otherBlock, 3.0f);
expectEquals (block.getSample (0, 4), -15.0f);
expectEquals (block.getSample (1, 4), -33.0f);
resetBlocks();
block.replaceWithProductOf (block, otherBlock);
expectEquals (block.getSample (0, 4), -25.0f);
expectEquals (block.getSample (1, 4), -121.0f);
}
beginTest ("Smoothing");
{
block.fill (1.0f);
SmoothedValue<float> sv { 1.0f };
sv.reset (1, 4);
sv.setTargetValue (0.0f);
block.multiplyBy (sv);
expect (block.getSample (0, 2) < 1.0f);
expect (block.getSample (1, 2) < 1.0f);
expect (block.getSample (0, 2) > 0.0f);
expect (block.getSample (1, 2) > 0.0f);
expectEquals (block.getSample (0, 5), 0.0f);
expectEquals (block.getSample (1, 5), 0.0f);
sv.setCurrentAndTargetValue (-1.0f);
sv.setTargetValue (0.0f);
otherBlock.fill (-1.0f);
block.replaceWithProductOf (otherBlock, sv);
expect (block.getSample (0, 2) < 1.0f);
expect (block.getSample (1, 2) < 1.0f);
expect (block.getSample (0, 2) > 0.0f);
expect (block.getSample (1, 2) > 0.0f);
expectEquals (block.getSample (0, 5), 0.0f);
expectEquals (block.getSample (1, 5), 0.0f);
}
beginTest ("Multiply add");
{
resetBlocks();
block.addProductOf (otherBlock, -1.0f);
expectEquals (block.getSample (0, 4), 10.0f);
expectEquals (block.getSample (1, 4), 22.0f);
block.addProductOf (otherBlock, otherBlock);
expectEquals (block.getSample (0, 4), 35.0f);
expectEquals (block.getSample (1, 4), 143.0f);
}
beginTest ("Negative abs min max");
{
resetBlocks();
otherBlock.negate();
block.add (otherBlock);
expectEquals (block.getSample (0, 4), 10.0f);
expectEquals (block.getSample (1, 4), 22.0f);
block.replaceWithNegativeOf (otherBlock);
expectEquals (block.getSample (0, 4), -5.0f);
expectEquals (block.getSample (1, 4), -11.0f);
block.clear();
otherBlock.negate();
block.replaceWithAbsoluteValueOf (otherBlock);
expectEquals (block.getSample (0, 4), 5.0f);
expectEquals (block.getSample (1, 4), 11.0f);
resetBlocks();
block.replaceWithMinOf (block, otherBlock);
expectEquals (block.getSample (0, 4), -5.0f);
expectEquals (block.getSample (1, 4), -11.0f);
resetBlocks();
block.replaceWithMaxOf (block, otherBlock);
expectEquals (block.getSample (0, 4), 5.0f);
expectEquals (block.getSample (1, 4), 11.0f);
resetBlocks();
auto range = block.findMinAndMax();
expectEquals (range.getStart(), 1.0f);
expectEquals (range.getEnd(), 12.0f);
}
beginTest ("Operators");
{
resetBlocks();
block += 10.0f;
expectEquals (block.getSample (0, 4), 15.0f);
expectEquals (block.getSample (1, 4), 21.0f);
block += otherBlock;
expectEquals (block.getSample (0, 4), 10.0f);
expectEquals (block.getSample (1, 4), 10.0f);
resetBlocks();
block -= 10.0f;
expectEquals (block.getSample (0, 4), -5.0f);
expectEquals (block.getSample (1, 4), 1.0f);
block -= otherBlock;
expectEquals (block.getSample (0, 4), 0.0f);
expectEquals (block.getSample (1, 4), 12.0f);
resetBlocks();
block *= 10.0f;
expectEquals (block.getSample (0, 4), 50.0f);
expectEquals (block.getSample (1, 4), 110.0f);
block *= otherBlock;
expectEquals (block.getSample (0, 4), -250.0f);
expectEquals (block.getSample (1, 4), -1210.0f);
}
beginTest ("Process");
{
resetBlocks();
AudioBlock<float>::process (block, otherBlock, [](float x) { return x + 1.0f; });
expectEquals (otherBlock.getSample (0, 4), 6.0f);
expectEquals (otherBlock.getSample (1, 4), 12.0f);
}
}
private:
AudioBuffer<float> data { 2, 6 }, otherData { 2, 6 };
AudioBlock<float> block { data }, otherBlock { otherData };
void resetBlocks()
{
auto value = 1.0f;
for (size_t c = 0; c < block.getNumChannels(); ++c)
{
for (size_t i = 0; i < block.getNumSamples(); ++i)
{
block.setSample ((int) c, (int) i, value);
value += 1.0f;
}
}
otherBlock.replaceWithNegativeOf (block);
}
};
static AudioBlockUnitTests audioBlockUnitTests;
} // namespace dsp
} // namespace juce

View file

@ -768,7 +768,7 @@ struct Convolution::Pimpl : private Thread
}
if (input.getNumChannels() > 1 && currentInfo.wantsStereo == false)
output.getSingleChannelBlock (1).copy (output.getSingleChannelBlock (0));
output.getSingleChannelBlock (1).copyFrom (output.getSingleChannelBlock (0));
}
//==============================================================================
@ -1212,7 +1212,7 @@ void Convolution::processSamples (const AudioBlock<const float>& input, AudioBlo
if (volumeDry[0].isSmoothing())
{
dry.copy (input);
dry.copyFrom (input);
for (size_t channel = 0; channel < numChannels; ++channel)
volumeDry[channel].applyGain (dry.getChannelPointer (channel), (int) numSamples);

View file

@ -89,6 +89,7 @@
#include "containers/juce_SIMDRegister_test.cpp"
#endif
#include "containers/juce_AudioBlock_test.cpp"
#include "frequency/juce_FFT_test.cpp"
#include "processors/juce_FIRFilter_test.cpp"
#endif

View file

@ -114,7 +114,7 @@ public:
bias.skip (static_cast<int> (len));
if (context.usesSeparateInputAndOutputBlocks())
outBlock.copy (inBlock);
outBlock.copyFrom (inBlock);
return;
}

View file

@ -110,7 +110,7 @@ public:
gain.skip (static_cast<int> (len));
if (context.usesSeparateInputAndOutputBlocks())
outBlock.copy (inBlock);
outBlock.copyFrom (inBlock);
return;
}

View file

@ -92,7 +92,7 @@ public:
if (! enabled || context.isBypassed)
{
outputBlock.copy (inputBlock);
outputBlock.copyFrom (inputBlock);
return;
}

View file

@ -98,7 +98,7 @@ struct OversamplingDummy : public Oversampling<SampleType>::OversamplingStage
jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
outputBlock.copy (ParentType::getProcessedSamples (outputBlock.getNumSamples()));
outputBlock.copyFrom (ParentType::getProcessedSamples (outputBlock.getNumSamples()));
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingDummy)

View file

@ -85,7 +85,7 @@ public:
jassert (inputBlock.getNumSamples() == numSamples);
outputBlock.copy (inputBlock);
outputBlock.copyFrom (inputBlock);
if (! enabled || context.isBypassed)
return;

View file

@ -58,7 +58,7 @@ struct WaveShaper
if (context.isBypassed)
{
if (context.usesSeparateInputAndOutputBlocks())
context.getOutputBlock().copy (context.getInputBlock());
context.getOutputBlock().copyFrom (context.getInputBlock());
}
else
{