diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index ef40f8a0ed..88e580a7a3 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -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 ============= diff --git a/examples/DSP/OscillatorDemo.h b/examples/DSP/OscillatorDemo.h index 6eadf8b4c7..a564337e1a 100644 --- a/examples/DSP/OscillatorDemo.h +++ b/examples/DSP/OscillatorDemo.h @@ -73,11 +73,11 @@ struct OscillatorDemoDSP void process (const ProcessContextReplacing& context) { - tempBuffer.copy (context.getInputBlock()); - tempBuffer.multiply (static_cast (fileMix)); + tempBuffer.copyFrom (context.getInputBlock()); + tempBuffer.multiplyBy (static_cast (fileMix)); oscillators[currentOscillatorIdx].process (context); - context.getOutputBlock().multiply (static_cast (1.0 - fileMix)); + context.getOutputBlock().multiplyBy (static_cast (1.0 - fileMix)); context.getOutputBlock().add (tempBuffer); diff --git a/examples/Plugins/DSPModulePluginDemo.h b/examples/Plugins/DSPModulePluginDemo.h index a814a91a3c..43d4f2ef1c 100644 --- a/examples/Plugins/DSPModulePluginDemo.h +++ b/examples/Plugins/DSPModulePluginDemo.h @@ -196,7 +196,7 @@ public: process (dsp::ProcessContextReplacing (firstChan)); for (size_t chan = 1; chan < block.getNumChannels(); ++chan) - block.getSingleChannelBlock (chan).copy (firstChan); + block.getSingleChannelBlock (chan).copyFrom (firstChan); } } diff --git a/modules/juce_dsp/containers/juce_AudioBlock.h b/modules/juce_dsp/containers/juce_AudioBlock.h index 6ffcda7570..7f289cdf08 100644 --- a/modules/juce_dsp/containers/juce_AudioBlock.h +++ b/modules/juce_dsp/containers/juce_AudioBlock.h @@ -78,15 +78,15 @@ 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, - size_t numberOfChannels, size_t numberOfSamples) noexcept + constexpr AudioBlock (SampleType* const* channelData, + size_t numberOfChannels, size_t numberOfSamples) noexcept : channels (channelData), numChannels (static_cast (numberOfChannels)), numSamples (numberOfSamples) @@ -98,8 +98,8 @@ 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, - size_t startSampleIndex, size_t numberOfSamples) noexcept + constexpr AudioBlock (SampleType* const* channelData, size_t numberOfChannels, + size_t startSampleIndex, size_t numberOfSamples) noexcept : channels (channelData), numChannels (static_cast (numberOfChannels)), startSample (startSampleIndex), @@ -144,7 +144,7 @@ public: throughout the life-time of the AudioBlock without being modified. */ template - AudioBlock (AudioBuffer& buffer) noexcept + constexpr AudioBlock (AudioBuffer& buffer) noexcept : channels (buffer.getArrayOfWritePointers()), numChannels (static_cast (buffer.getNumChannels())), numSamples (static_cast (buffer.getNumSamples())) @@ -196,7 +196,7 @@ public: //============================================================================== template - bool operator== (const AudioBlock& other) const noexcept + constexpr bool operator== (const AudioBlock& other) const noexcept { return std::equal (channels, channels + numChannels, @@ -207,25 +207,20 @@ public: } template - bool operator!= (const AudioBlock& other) const noexcept + constexpr bool operator!= (const AudioBlock& other) const noexcept { return ! (*this == other); } //============================================================================== - forcedinline size_t getNumSamples() const noexcept { return numSamples; } - forcedinline size_t getNumChannels() const noexcept { return static_cast (numChannels); } + /** Returns the number of channels referenced by this block. */ + constexpr size_t getNumChannels() const noexcept { return static_cast (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,79 +275,52 @@ 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 (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 (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 - forcedinline AudioBlock& copy (const AudioBlock& src) noexcept - { - auto maxChannels = jmin (src.numChannels, numChannels); - auto n = static_cast (jmin (src.numSamples, numSamples) * sizeFactor); + AudioBlock& copyFrom (const AudioBlock& src) noexcept { copyFromInternal (src); return *this; } + template + const AudioBlock& copyFrom (const AudioBlock& 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::SIMDNumElements. */ - forcedinline AudioBlock& copyFrom (const AudioBuffer& src, size_t srcPos = 0, size_t dstPos = 0, - size_t numElements = std::numeric_limits::max()) - { - auto srclen = static_cast (src.getNumSamples()) / sizeFactor; - auto n = static_cast (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor); - auto maxChannels = jmin (static_cast (src.getNumChannels()), static_cast (numChannels)); + template + AudioBlock& copyFrom (const AudioBuffer& src, + size_t srcPos = 0, size_t dstPos = 0, + size_t numElements = std::numeric_limits::max()) { copyFromInternal (src, srcPos, dstPos, numElements); return *this; } + template + const AudioBlock& copyFrom (const AudioBuffer& src, + size_t srcPos = 0, size_t dstPos = 0, + size_t numElements = std::numeric_limits::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 (ch), - static_cast (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::SIMDNumElements. */ - forcedinline const AudioBlock& copyTo (AudioBuffer& dst, size_t srcPos = 0, size_t dstPos = 0, - size_t numElements = std::numeric_limits::max()) const + void copyTo (AudioBuffer::type>& dst, size_t srcPos = 0, size_t dstPos = 0, + size_t numElements = std::numeric_limits::max()) const { auto dstlen = static_cast (dst.getNumSamples()) / sizeFactor; auto n = static_cast (jmin (numSamples - srcPos, dstlen - dstPos, numElements) * sizeFactor); @@ -361,30 +329,19 @@ public: for (size_t ch = 0; ch < maxChannels; ++ch) FloatVectorOperations::copy (dst.getWritePointer (static_cast (ch), static_cast (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::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::max()) noexcept { moveInternal (srcPos, dstPos, numElements); return *this; } + const AudioBlock& move (size_t srcPos, size_t dstPos, + size_t numElements = std::numeric_limits::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 (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 - forcedinline AudioBlock& add (AudioBlock src) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (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 src) noexcept { addInternal (src); return *this; } template - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE add (AudioBlock src, SampleType value) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + const AudioBlock& add (AudioBlock 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 + AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, SampleType value) noexcept { replaceWithSumOfInternal (src, value); return *this; } + template + const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock 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 - forcedinline AudioBlock& add (AudioBlock src1, AudioBlock src2) noexcept - { - jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); - auto n = static_cast (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 (-1.0)); - } - - /** Subtracts the source values from the receiver. */ - template - forcedinline AudioBlock& subtract (AudioBlock src) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (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 - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE subtract (AudioBlock src, SampleType value) noexcept - { - return add (src, static_cast (-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 src1, AudioBlock src2) noexcept { replaceWithSumOfInternal (src1, src2); return *this; } template - forcedinline AudioBlock& subtract (AudioBlock src1, AudioBlock src2) noexcept - { - jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); - auto n = static_cast (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor); + const AudioBlock& replaceWithSumOf (AudioBlock src1, AudioBlock 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 (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 - forcedinline AudioBlock& multiply (AudioBlock src) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (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 src) noexcept { subtractInternal (src); return *this; } template - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE multiply (AudioBlock src, SampleType value) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + const AudioBlock& subtract (AudioBlock 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 + AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, SampleType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } + template + const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock 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 - forcedinline AudioBlock& multiply (AudioBlock src1, AudioBlock src2) noexcept - { - jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); - auto n = static_cast (jmin (numSamples, src1.numSamples, src2.numSamples) * sizeFactor); + AudioBlock& replaceWithDifferenceOf (AudioBlock src1, AudioBlock src2) noexcept { replaceWithDifferenceOfInternal (src1, src2); return *this; } + template + const AudioBlock& replaceWithDifferenceOf (AudioBlock src1, AudioBlock 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 + AudioBlock& multiplyBy (AudioBlock src) noexcept { multiplyByInternal (src); return *this; } + template + const AudioBlock& multiplyBy (AudioBlock 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 + AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock src, SampleType value) noexcept { replaceWithProductOfInternal (src, value); return *this; } + template + const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock 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 + AudioBlock& replaceWithProductOf (AudioBlock src1, AudioBlock src2) noexcept { replaceWithProductOfInternal (src1, src2); return *this; } + template + const AudioBlock& replaceWithProductOf (AudioBlock src1, AudioBlock src2) const noexcept { replaceWithProductOfInternal (src1, src2); return *this; } + + //============================================================================== + /** Multiplies each channels of this block by a smoothly changing value. */ template - AudioBlock& multiply (SmoothedValue& 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& value) noexcept { multiplyByInternal (value); return *this; } + template + const AudioBlock& multiplyBy (SmoothedValue& 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 - AudioBlock& multiply (AudioBlock src, SmoothedValue& value) noexcept - { - jassert (numChannels == src.numChannels); + AudioBlock& replaceWithProductOf (AudioBlock src, SmoothedValue& value) noexcept { replaceWithProductOfInternal (src, value); return *this; } + template + const AudioBlock& replaceWithProductOf (AudioBlock src, SmoothedValue& 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 - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE addWithMultiply (AudioBlock src, SampleType factor) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (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 - forcedinline AudioBlock& addWithMultiply (AudioBlock src1, AudioBlock src2) noexcept - { - jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); - auto n = static_cast (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 (-1.0)); - } - - /** Negates each value of source and stores it in the receiver. */ + AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, SampleType factor) noexcept { addProductOfInternal (src, factor); return *this; } template - forcedinline AudioBlock& replaceWithNegativeOf (AudioBlock src) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock 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 + AudioBlock& addProductOf (AudioBlock src1, AudioBlock src2) noexcept { addProductOfInternal (src1, src2); return *this; } + template + const AudioBlock& addProductOf (AudioBlock src1, AudioBlock 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 - forcedinline AudioBlock& replaceWithAbsoluteValueOf (AudioBlock src) noexcept - { - jassert (numChannels == src.numChannels); - auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + AudioBlock& replaceWithNegativeOf (AudioBlock src) noexcept { replaceWithNegativeOfInternal (src); return *this; } + template + const AudioBlock& replaceWithNegativeOf (AudioBlock 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 + AudioBlock& replaceWithAbsoluteValueOf (AudioBlock src) noexcept { replaceWithAbsoluteValueOfInternal (src); return *this; } + template + const AudioBlock& replaceWithAbsoluteValueOf (AudioBlock 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 - forcedinline AudioBlock& min (AudioBlock src1, AudioBlock src2) noexcept - { - jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); - auto n = static_cast (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 src1, AudioBlock src2) noexcept { replaceWithMinOfInternal (src1, src2); return *this; } template - forcedinline AudioBlock& max (AudioBlock src1, AudioBlock src2) noexcept - { - jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); - auto n = static_cast (jmin (src1.numSamples, src2.numSamples, numSamples) * sizeFactor); + const AudioBlock& replaceWithMinOf (AudioBlock src1, AudioBlock 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 + AudioBlock& replaceWithMaxOf (AudioBlock src1, AudioBlock src2) noexcept { replaceWithMaxOfInternal (src1, src2); return *this; } + template + const AudioBlock& replaceWithMaxOf (AudioBlock src1, AudioBlock src2) const noexcept { replaceWithMaxOfInternal (src1, src2); return *this; } + //============================================================================== /** Finds the minimum and maximum value of the buffer. */ - forcedinline Range findMinAndMax() const noexcept + Range::type> findMinAndMax() const noexcept { if (numChannels == 0) return {}; auto n = static_cast (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 - forcedinline AudioBlock& operator*= (SmoothedValue& value) noexcept { return multiply (value); } + AudioBlock& operator*= (SmoothedValue& value) noexcept { return multiplyBy (value); } + template + const AudioBlock& operator*= (SmoothedValue& 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 (getChannelPointer (ch)); } - const NumericType* channelPtr (size_t ch) const noexcept { return reinterpret_cast (getChannelPointer (ch)); } + void JUCE_VECTOR_CALLTYPE clearInternal() const noexcept + { + auto n = static_cast (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 (numSamples * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::fill (getChannelPointer (ch), value, n); + } + + template + void copyFromInternal (const AudioBlock& src) const noexcept + { + auto maxChannels = jmin (src.numChannels, numChannels); + auto n = static_cast (jmin (src.numSamples, numSamples) * sizeFactor); + + for (size_t ch = 0; ch < maxChannels; ++ch) + FloatVectorOperations::copy (getChannelPointer (ch), src.getChannelPointer (ch), n); + } + + template + void copyFromInternal (const AudioBuffer& src, size_t srcPos, size_t dstPos, size_t numElements) const + { + auto srclen = static_cast (src.getNumSamples()) / sizeFactor; + auto n = static_cast (jmin (srclen - srcPos, numSamples - dstPos, numElements) * sizeFactor); + auto maxChannels = jmin (static_cast (src.getNumChannels()), static_cast (numChannels)); + + for (size_t ch = 0; ch < maxChannels; ++ch) + FloatVectorOperations::copy (getChannelPointer (ch) + dstPos, + src.getReadPointer (static_cast (ch), + static_cast (srcPos * sizeFactor)), + n); + } + + void moveInternal (size_t srcPos, size_t dstPos, + size_t numElements = std::numeric_limits::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 (numSamples * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::add (getChannelPointer (ch), value, n); + } + + template + void addInternal (AudioBlock src) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), n); + } + + template + void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock src, SampleType value) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::add (getChannelPointer (ch), src.getChannelPointer (ch), value, n); + } + + template + void replaceWithSumOfInternal (AudioBlock src1, AudioBlock src2) const noexcept + { + jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); + auto n = static_cast (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 (-1.0)); + } + + template + void subtractInternal (AudioBlock src) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::subtract (getChannelPointer (ch), src.getChannelPointer (ch), n); + } + + template + void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock src, SampleType value) const noexcept + { + replaceWithSumOfInternal (src, static_cast (-1.0) * value); + } + + template + void replaceWithDifferenceOfInternal (AudioBlock src1, AudioBlock src2) const noexcept + { + jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); + auto n = static_cast (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 (numSamples * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::multiply (getChannelPointer (ch), value, n); + } + + template + void multiplyByInternal (AudioBlock src) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), n); + } + + template + void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock src, SampleType value) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::multiply (getChannelPointer (ch), src.getChannelPointer (ch), value, n); + } + + template + void replaceWithProductOfInternal (AudioBlock src1, AudioBlock src2) const noexcept + { + jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); + auto n = static_cast (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 + void multiplyByInternal (SmoothedValue& 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 + void replaceWithProductOfInternal (AudioBlock src, SmoothedValue& 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 + void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock src, SampleType factor) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::addWithMultiply (getChannelPointer (ch), src.getChannelPointer (ch), factor, n); + } + + template + void addProductOfInternal (AudioBlock src1, AudioBlock src2) const noexcept + { + jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); + auto n = static_cast (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 (-1.0)); + } + + template + void replaceWithNegativeOfInternal (AudioBlock src) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::negate (getChannelPointer (ch), src.getChannelPointer (ch), n); + } + + template + void replaceWithAbsoluteValueOfInternal (AudioBlock src) const noexcept + { + jassert (numChannels == src.numChannels); + auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); + + for (size_t ch = 0; ch < numChannels; ++ch) + FloatVectorOperations::abs (getChannelPointer (ch), src.getChannelPointer (ch), n); + } + + //============================================================================== + template + void replaceWithMinOfInternal (AudioBlock src1, AudioBlock src2) const noexcept + { + jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); + auto n = static_cast (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 + void replaceWithMaxOfInternal (AudioBlock src1, AudioBlock src2) const noexcept + { + jassert (numChannels == src1.numChannels && src1.numChannels == src2.numChannels); + auto n = static_cast (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; diff --git a/modules/juce_dsp/containers/juce_AudioBlock_test.cpp b/modules/juce_dsp/containers/juce_AudioBlock_test.cpp new file mode 100644 index 0000000000..f0192e8ad1 --- /dev/null +++ b/modules/juce_dsp/containers/juce_AudioBlock_test.cpp @@ -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 (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples())); + expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples())); + expect (block == AudioBlock (block)); + + expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) data.getNumSamples())); + expect (block == AudioBlock (data.getArrayOfWritePointers(), (size_t) data.getNumChannels(), (size_t) 0, (size_t) data.getNumSamples())); + expect (block == AudioBlock (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 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 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::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 data { 2, 6 }, otherData { 2, 6 }; + AudioBlock 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 diff --git a/modules/juce_dsp/frequency/juce_Convolution.cpp b/modules/juce_dsp/frequency/juce_Convolution.cpp index f0b5ab2f76..3288651c06 100644 --- a/modules/juce_dsp/frequency/juce_Convolution.cpp +++ b/modules/juce_dsp/frequency/juce_Convolution.cpp @@ -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& 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); diff --git a/modules/juce_dsp/juce_dsp.cpp b/modules/juce_dsp/juce_dsp.cpp index 56748f1450..0d61a417e0 100644 --- a/modules/juce_dsp/juce_dsp.cpp +++ b/modules/juce_dsp/juce_dsp.cpp @@ -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 diff --git a/modules/juce_dsp/processors/juce_Bias.h b/modules/juce_dsp/processors/juce_Bias.h index 4348cdb3e1..a279f61793 100644 --- a/modules/juce_dsp/processors/juce_Bias.h +++ b/modules/juce_dsp/processors/juce_Bias.h @@ -114,7 +114,7 @@ public: bias.skip (static_cast (len)); if (context.usesSeparateInputAndOutputBlocks()) - outBlock.copy (inBlock); + outBlock.copyFrom (inBlock); return; } diff --git a/modules/juce_dsp/processors/juce_Gain.h b/modules/juce_dsp/processors/juce_Gain.h index 3c542b571a..21a3391ddc 100644 --- a/modules/juce_dsp/processors/juce_Gain.h +++ b/modules/juce_dsp/processors/juce_Gain.h @@ -110,7 +110,7 @@ public: gain.skip (static_cast (len)); if (context.usesSeparateInputAndOutputBlocks()) - outBlock.copy (inBlock); + outBlock.copyFrom (inBlock); return; } diff --git a/modules/juce_dsp/processors/juce_LadderFilter.h b/modules/juce_dsp/processors/juce_LadderFilter.h index 8b38aaf784..f3f302d47d 100644 --- a/modules/juce_dsp/processors/juce_LadderFilter.h +++ b/modules/juce_dsp/processors/juce_LadderFilter.h @@ -92,7 +92,7 @@ public: if (! enabled || context.isBypassed) { - outputBlock.copy (inputBlock); + outputBlock.copyFrom (inputBlock); return; } diff --git a/modules/juce_dsp/processors/juce_Oversampling.cpp b/modules/juce_dsp/processors/juce_Oversampling.cpp index 109047b55c..17b6c32a31 100644 --- a/modules/juce_dsp/processors/juce_Oversampling.cpp +++ b/modules/juce_dsp/processors/juce_Oversampling.cpp @@ -98,7 +98,7 @@ struct OversamplingDummy : public Oversampling::OversamplingStage jassert (outputBlock.getNumChannels() <= static_cast (ParentType::buffer.getNumChannels())); jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast (ParentType::buffer.getNumSamples())); - outputBlock.copy (ParentType::getProcessedSamples (outputBlock.getNumSamples())); + outputBlock.copyFrom (ParentType::getProcessedSamples (outputBlock.getNumSamples())); } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingDummy) diff --git a/modules/juce_dsp/processors/juce_Reverb.h b/modules/juce_dsp/processors/juce_Reverb.h index a2ff395343..3e75a55b8c 100644 --- a/modules/juce_dsp/processors/juce_Reverb.h +++ b/modules/juce_dsp/processors/juce_Reverb.h @@ -85,7 +85,7 @@ public: jassert (inputBlock.getNumSamples() == numSamples); - outputBlock.copy (inputBlock); + outputBlock.copyFrom (inputBlock); if (! enabled || context.isBypassed) return; diff --git a/modules/juce_dsp/processors/juce_WaveShaper.h b/modules/juce_dsp/processors/juce_WaveShaper.h index f93151d1a3..8a2c624a77 100644 --- a/modules/juce_dsp/processors/juce_WaveShaper.h +++ b/modules/juce_dsp/processors/juce_WaveShaper.h @@ -58,7 +58,7 @@ struct WaveShaper if (context.isBypassed) { if (context.usesSeparateInputAndOutputBlocks()) - context.getOutputBlock().copy (context.getInputBlock()); + context.getOutputBlock().copyFrom (context.getInputBlock()); } else {