/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2020 - Raw Material Software Limited JUCE is an open source library subject to commercial or open-source licensing. By using JUCE, you agree to the terms of both the JUCE 6 End-User License Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020). End User License Agreement: www.juce.com/juce-6-licence Privacy Policy: www.juce.com/juce-privacy-policy Or: You may also use this code under the terms of the GPL v3 (see www.gnu.org/licenses). JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { namespace dsp { #ifndef DOXYGEN namespace SampleTypeHelpers // Internal classes needed for handling sample type classes { template ::value> struct ElementType { using Type = T; }; template struct ElementType { using Type = typename T::value_type; }; } #endif //============================================================================== /** Minimal and lightweight data-structure which contains a list of pointers to channels containing some kind of sample data. This class doesn't own any of the data which it points to, it's simply a view into data that is owned elsewhere. You can construct one from some raw data that you've allocated yourself, or give it a HeapBlock to use, or give it an AudioBuffer which it can refer to, but in all cases the user is responsible for making sure that the data doesn't get deleted while there's still an AudioBlock using it. @tags{DSP} */ template class AudioBlock { private: template using MayUseConvertingConstructor = std::enable_if_t, std::remove_const_t>::value && std::is_const::value && ! std::is_const::value, int>; public: //============================================================================== using NumericType = typename SampleTypeHelpers::ElementType::Type; //============================================================================== /** Create a zero-sized AudioBlock. */ 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. */ constexpr AudioBlock (SampleType* const* channelData, size_t numberOfChannels, size_t numberOfSamples) noexcept : channels (channelData), numChannels (static_cast (numberOfChannels)), numSamples (numberOfSamples) { } /** 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. */ constexpr AudioBlock (SampleType* const* channelData, size_t numberOfChannels, size_t startSampleIndex, size_t numberOfSamples) noexcept : channels (channelData), numChannels (static_cast (numberOfChannels)), startSample (startSampleIndex), numSamples (numberOfSamples) { } /** Allocates a suitable amount of space in a HeapBlock, and initialises this object to point into it. The HeapBlock must of course not be freed or re-allocated while this object is still in use, because it will be referencing its data. */ AudioBlock (HeapBlock& heapBlockToUseForAllocation, size_t numberOfChannels, size_t numberOfSamples, size_t alignmentInBytes = defaultAlignment) noexcept : numChannels (static_cast (numberOfChannels)), numSamples (numberOfSamples) { auto roundedUpNumSamples = (numberOfSamples + elementMask) & ~elementMask; auto channelSize = sizeof (SampleType) * roundedUpNumSamples; auto channelListBytes = sizeof (SampleType*) * numberOfChannels; auto extraBytes = alignmentInBytes - 1; heapBlockToUseForAllocation.malloc (channelListBytes + extraBytes + channelSize * numberOfChannels); auto* chanArray = unalignedPointerCast (heapBlockToUseForAllocation.getData()); channels = chanArray; auto* data = unalignedPointerCast (addBytesToPointer (chanArray, channelListBytes)); data = snapPointerToAlignment (data, alignmentInBytes); for (ChannelCountType i = 0; i < numChannels; ++i) { chanArray[i] = data; data += roundedUpNumSamples; } } /** Creates an AudioBlock that points to the data in an AudioBuffer. AudioBlock does not copy nor own the memory pointed to by dataToUse. Therefore it is the user's responsibility to ensure that the buffer is retained throughout the life-time of the AudioBlock without being modified. */ template constexpr AudioBlock (AudioBuffer& buffer) noexcept : channels (buffer.getArrayOfWritePointers()), numChannels (static_cast (buffer.getNumChannels())), numSamples (static_cast (buffer.getNumSamples())) { } /** Creates an AudioBlock that points to the data in an AudioBuffer. AudioBlock does not copy nor own the memory pointed to by dataToUse. Therefore it is the user's responsibility to ensure that the buffer is retained throughout the life-time of the AudioBlock without being modified. */ template constexpr AudioBlock (const AudioBuffer& buffer) noexcept : channels (buffer.getArrayOfReadPointers()), numChannels (static_cast (buffer.getNumChannels())), numSamples (static_cast (buffer.getNumSamples())) { } /** Creates an AudioBlock that points to the data in an AudioBuffer. AudioBlock does not copy nor own the memory pointed to by dataToUse. Therefore it is the user's responsibility to ensure that the buffer is retained throughout the life-time of the AudioBlock without being modified. */ template AudioBlock (AudioBuffer& buffer, size_t startSampleIndex) noexcept : channels (buffer.getArrayOfWritePointers()), numChannels (static_cast (buffer.getNumChannels())), startSample (startSampleIndex), numSamples (static_cast (buffer.getNumSamples()) - startSampleIndex) { jassert (startSample < static_cast (buffer.getNumSamples())); } AudioBlock (const AudioBlock& other) noexcept = default; AudioBlock& operator= (const AudioBlock& other) noexcept = default; template = 0> AudioBlock (const AudioBlock& other) noexcept : channels { other.channels }, numChannels { other.numChannels }, startSample { other.startSample }, numSamples { other.numSamples } { } template = 0> AudioBlock& operator= (const AudioBlock& other) noexcept { AudioBlock blockCopy { other }; swap (blockCopy); return *this; } void swap (AudioBlock& other) noexcept { std::swap (other.channels, channels); std::swap (other.numChannels, numChannels); std::swap (other.startSample, startSample); std::swap (other.numSamples, numSamples); } //============================================================================== template constexpr bool operator== (const AudioBlock& other) const noexcept { return std::equal (channels, channels + numChannels, other.channels, other.channels + other.numChannels) && startSample == other.startSample && numSamples == other.numSamples; } template constexpr bool operator!= (const AudioBlock& other) const noexcept { return ! (*this == other); } //============================================================================== /** 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. */ SampleType* getChannelPointer (size_t channel) const noexcept { jassert (channel < numChannels); jassert (numSamples > 0); return channels[channel] + startSample; } /** Returns an AudioBlock that represents one of the channels in this block. */ AudioBlock getSingleChannelBlock (size_t channel) const noexcept { jassert (channel < numChannels); return AudioBlock (channels + channel, 1, startSample, numSamples); } /** Returns a subset of contiguous channels @param channelStart First channel of the subset @param numChannelsToUse Count of channels in the subset */ AudioBlock getSubsetChannelBlock (size_t channelStart, size_t numChannelsToUse) const noexcept { jassert (channelStart < numChannels); jassert ((channelStart + numChannelsToUse) <= numChannels); return AudioBlock (channels + channelStart, numChannelsToUse, startSample, numSamples); } /** Returns a sample from the buffer. The channel and index are not checked - they are expected to be in-range. If not, an assertion will be thrown, but in a release build, you're into 'undefined behaviour' territory. */ SampleType getSample (int channel, int sampleIndex) const noexcept { jassert (isPositiveAndBelow (channel, numChannels)); jassert (isPositiveAndBelow (sampleIndex, numSamples)); return channels[channel][(size_t) startSample + (size_t) sampleIndex]; } /** Modifies a sample in the buffer. The channel and index are not checked - they are expected to be in-range. If not, an assertion will be thrown, but in a release build, you're into 'undefined behaviour' territory. */ void setSample (int destChannel, int destSample, SampleType newValue) const noexcept { jassert (isPositiveAndBelow (destChannel, numChannels)); jassert (isPositiveAndBelow (destSample, numSamples)); channels[destChannel][(size_t) startSample + (size_t) destSample] = newValue; } /** Adds a value to a sample in the buffer. The channel and index are not checked - they are expected to be in-range. If not, an assertion will be thrown, but in a release build, you're into 'undefined behaviour' territory. */ void addSample (int destChannel, int destSample, SampleType valueToAdd) const noexcept { jassert (isPositiveAndBelow (destChannel, numChannels)); jassert (isPositiveAndBelow (destSample, numSamples)); channels[destChannel][(size_t) startSample + (size_t) destSample] += valueToAdd; } //============================================================================== /** Clears the memory referenced by this AudioBlock. */ AudioBlock& clear() noexcept { clearInternal(); return *this; } const AudioBlock& clear() const noexcept { clearInternal(); return *this; } /** Fills the memory referenced by this AudioBlock with value. */ AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) noexcept { fillInternal (value); return *this; } const AudioBlock& JUCE_VECTOR_CALLTYPE fill (NumericType value) const noexcept { fillInternal (value); return *this; } /** Copies the values in src to this block. */ template AudioBlock& copyFrom (const AudioBlock& src) noexcept { copyFromInternal (src); return *this; } template const AudioBlock& copyFrom (const AudioBlock& src) const noexcept { copyFromInternal (src); return *this; } /** Copy the values from an AudioBuffer to this block. All indices and sizes are in this AudioBlock'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. */ 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; } /** Copies the values from this block to an AudioBuffer. All indices and sizes are in this AudioBlock'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. */ 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); auto maxChannels = jmin (static_cast (dst.getNumChannels()), static_cast (numChannels)); for (size_t ch = 0; ch < maxChannels; ++ch) FloatVectorOperations::copy (dst.getWritePointer (static_cast (ch), static_cast (dstPos * sizeFactor)), getDataPointer (ch) + (srcPos * sizeFactor), n); } /** 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. */ 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 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 will become the first element of the return value. @param newLength The number of elements of the newly created sub-block. */ AudioBlock getSubBlock (size_t newOffset, size_t newLength) const noexcept { jassert (newOffset < numSamples); jassert (newOffset + newLength <= numSamples); return AudioBlock (channels, numChannels, startSample + newOffset, newLength); } /** 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 block which will will become the first element of the return value. The return value will include all subsequent elements of the receiver. */ AudioBlock getSubBlock (size_t newOffset) const noexcept { return getSubBlock (newOffset, getNumSamples() - newOffset); } //============================================================================== /** Adds a fixed value to the elements in this block. */ AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) noexcept { addInternal (value); return *this; } const AudioBlock& JUCE_VECTOR_CALLTYPE add (NumericType value) const noexcept { addInternal (value); return *this; } /** Adds the elements in the src block to the elements in this block. */ template AudioBlock& add (AudioBlock src) noexcept { addInternal (src); return *this; } template const AudioBlock& add (AudioBlock src) const noexcept { addInternal (src); return *this; } /** Adds a fixed value to each source value and replaces the contents of this block. */ template AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, NumericType value) noexcept { replaceWithSumOfInternal (src, value); return *this; } template const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithSumOf (AudioBlock src, NumericType value) const noexcept { replaceWithSumOfInternal (src, value); return *this; } /** Adds each source1 value to the corresponding source2 value and replaces the contents of this block. */ template AudioBlock& replaceWithSumOf (AudioBlock src1, AudioBlock src2) noexcept { replaceWithSumOfInternal (src1, src2); return *this; } template const AudioBlock& replaceWithSumOf (AudioBlock src1, AudioBlock src2) const noexcept { replaceWithSumOfInternal (src1, src2); return *this; } //============================================================================== /** Subtracts a fixed value from the elements in this block. */ AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) noexcept { subtractInternal (value); return *this; } const AudioBlock& JUCE_VECTOR_CALLTYPE subtract (NumericType value) const noexcept { subtractInternal (value); return *this; } /** Subtracts the source values from the elements in this block. */ template AudioBlock& subtract (AudioBlock src) noexcept { subtractInternal (src); return *this; } template const AudioBlock& subtract (AudioBlock src) const noexcept { subtractInternal (src); return *this; } /** Subtracts a fixed value from each source value and replaces the contents of this block. */ template AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, NumericType value) noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } template const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithDifferenceOf (AudioBlock src, NumericType value) const noexcept { replaceWithDifferenceOfInternal (src, value); return *this; } /** Subtracts each source2 value from the corresponding source1 value and replaces the contents of this block. */ template 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; } //============================================================================== /** Multiplies the elements in this block by a fixed value. */ AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) noexcept { multiplyByInternal (value); return *this; } const AudioBlock& JUCE_VECTOR_CALLTYPE multiplyBy (NumericType value) const noexcept { multiplyByInternal (value); 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; } /** 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, NumericType value) noexcept { replaceWithProductOfInternal (src, value); return *this; } template const AudioBlock& JUCE_VECTOR_CALLTYPE replaceWithProductOf (AudioBlock src, NumericType 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& multiplyBy (SmoothedValue& value) noexcept { multiplyByInternal (value); return *this; } template const AudioBlock& multiplyBy (SmoothedValue& value) const noexcept { multiplyByInternal (value); return *this; } /** Replaces each channel of this block with the product of the src block and a smoothed value. */ template 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; } //============================================================================== /** Multiplies each value in src by a fixed value and adds the result to this block. */ template AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, NumericType factor) noexcept { addProductOfInternal (src, factor); return *this; } template const AudioBlock& JUCE_VECTOR_CALLTYPE addProductOf (AudioBlock src, NumericType factor) const noexcept { addProductOfInternal (src, factor); return *this; } /** 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; } //============================================================================== /** Negates each value of this block. */ AudioBlock& negate() noexcept { negateInternal(); return *this; } const AudioBlock& negate() const noexcept { negateInternal(); return *this; } /** Replaces the contents of this block with the negative of the values in the src block. */ template AudioBlock& replaceWithNegativeOf (AudioBlock src) noexcept { replaceWithNegativeOfInternal (src); return *this; } template const AudioBlock& replaceWithNegativeOf (AudioBlock src) const noexcept { replaceWithNegativeOfInternal (src); return *this; } /** 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; } //============================================================================== /** Replaces each element of this block with the minimum of the corresponding element of the source arrays. */ template AudioBlock& replaceWithMinOf (AudioBlock src1, AudioBlock src2) noexcept { replaceWithMinOfInternal (src1, src2); return *this; } template const AudioBlock& replaceWithMinOf (AudioBlock src1, AudioBlock src2) const noexcept { replaceWithMinOfInternal (src1, src2); 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. */ Range::type> findMinAndMax() const noexcept { if (numChannels == 0) return {}; auto n = static_cast (numSamples * sizeFactor); auto minmax = FloatVectorOperations::findMinAndMax (getDataPointer (0), n); for (size_t ch = 1; ch < numChannels; ++ch) minmax = minmax.getUnionWith (FloatVectorOperations::findMinAndMax (getDataPointer (ch), n)); return minmax; } //============================================================================== // Convenient operator wrappers. AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType value) noexcept { return add (value); } const AudioBlock& JUCE_VECTOR_CALLTYPE operator+= (NumericType 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-= (NumericType value) noexcept { return subtract (value); } const AudioBlock& JUCE_VECTOR_CALLTYPE operator-= (NumericType 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*= (NumericType value) noexcept { return multiplyBy (value); } const AudioBlock& JUCE_VECTOR_CALLTYPE operator*= (NumericType 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 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 static_assert (std::is_same, float>::value || std::is_same, double>::value #if JUCE_USE_SIMD || std::is_same, SIMDRegister>::value || std::is_same, SIMDRegister>::value #endif , "AudioBlock only supports single or double precision floating point types"); //============================================================================== /** Applies a function to each value in an input block, putting the result into an output block. The function supplied must take a SampleType as its parameter, and return a SampleType. The two blocks must have the same number of channels and samples. */ template static void process (AudioBlock inBlock, AudioBlock outBlock, FunctionType&& function) { auto len = inBlock.getNumSamples(); auto numChans = inBlock.getNumChannels(); jassert (len == outBlock.getNumSamples()); jassert (numChans == outBlock.getNumChannels()); for (ChannelCountType c = 0; c < numChans; ++c) { auto* src = inBlock.getChannelPointer (c); auto* dst = outBlock.getChannelPointer (c); for (size_t i = 0; i < len; ++i) dst[i] = function (src[i]); } } private: NumericType* getDataPointer (size_t channel) const noexcept { return reinterpret_cast (getChannelPointer (channel)); } //============================================================================== void JUCE_VECTOR_CALLTYPE clearInternal() const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) FloatVectorOperations::clear (getDataPointer (ch), n); } void JUCE_VECTOR_CALLTYPE fillInternal (NumericType value) const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) FloatVectorOperations::fill (getDataPointer (ch), value, n); } template void copyFromInternal (const AudioBlock& src) const noexcept { auto maxChannels = jmin (src.numChannels, numChannels); auto n = static_cast (jmin (src.numSamples * src.sizeFactor, numSamples * sizeFactor)); for (size_t ch = 0; ch < maxChannels; ++ch) FloatVectorOperations::copy (getDataPointer (ch), src.getDataPointer (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 (getDataPointer (ch) + (dstPos * sizeFactor), 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 (NumericType value) const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) FloatVectorOperations::add (getDataPointer (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 (getDataPointer (ch), src.getDataPointer (ch), n); } template void JUCE_VECTOR_CALLTYPE replaceWithSumOfInternal (AudioBlock src, NumericType 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 (getDataPointer (ch), src.getDataPointer (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 (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== constexpr void JUCE_VECTOR_CALLTYPE subtractInternal (NumericType 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 (getDataPointer (ch), src.getDataPointer (ch), n); } template void JUCE_VECTOR_CALLTYPE replaceWithDifferenceOfInternal (AudioBlock src, NumericType 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 (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== void JUCE_VECTOR_CALLTYPE multiplyByInternal (NumericType value) const noexcept { auto n = static_cast (numSamples * sizeFactor); for (size_t ch = 0; ch < numChannels; ++ch) FloatVectorOperations::multiply (getDataPointer (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 (getDataPointer (ch), src.getDataPointer (ch), n); } template void JUCE_VECTOR_CALLTYPE replaceWithProductOfInternal (AudioBlock src, NumericType 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 (getDataPointer (ch), src.getDataPointer (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 (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } template void multiplyByInternal (SmoothedValue& value) const noexcept { if (! value.isSmoothing()) { multiplyByInternal ((NumericType) value.getTargetValue()); } else { for (size_t i = 0; i < numSamples; ++i) { const auto scaler = (NumericType) value.getNextValue(); for (size_t ch = 0; ch < numChannels; ++ch) getDataPointer (ch)[i] *= scaler; } } } template void replaceWithProductOfInternal (AudioBlock src, SmoothedValue& value) const noexcept { jassert (numChannels == src.numChannels); if (! value.isSmoothing()) { replaceWithProductOfInternal (src, (NumericType) value.getTargetValue()); } else { auto n = jmin (numSamples, src.numSamples) * sizeFactor; for (size_t i = 0; i < n; ++i) { const auto scaler = (NumericType) value.getNextValue(); for (size_t ch = 0; ch < numChannels; ++ch) getDataPointer (ch)[i] = scaler * src.getChannelPointer (ch)[i]; } } } //============================================================================== template void JUCE_VECTOR_CALLTYPE addProductOfInternal (AudioBlock src, NumericType 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 (getDataPointer (ch), src.getDataPointer (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 (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (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 (getDataPointer (ch), src.getDataPointer (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 (getDataPointer (ch), src.getDataPointer (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 (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (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 (getDataPointer (ch), src1.getDataPointer (ch), src2.getDataPointer (ch), n); } //============================================================================== using ChannelCountType = unsigned int; //============================================================================== static constexpr size_t sizeFactor = sizeof (SampleType) / sizeof (NumericType); static constexpr size_t elementMask = sizeFactor - 1; static constexpr size_t byteMask = (sizeFactor * sizeof (NumericType)) - 1; #if JUCE_USE_SIMD static constexpr size_t defaultAlignment = sizeof (SIMDRegister); #else static constexpr size_t defaultAlignment = sizeof (NumericType); #endif SampleType* const* channels; ChannelCountType numChannels = 0; size_t startSample = 0, numSamples = 0; template friend class AudioBlock; }; } // namespace dsp } // namespace juce