diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index 910e52ad5b..40ee99eac6 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -4,6 +4,28 @@ JUCE breaking changes Develop ======= +Change +------ +The AudioBlock class now differentiates between const and non-const data. + +Possible Issues +--------------- +The return type of the getInputBlock() method of the ProcessContextReplacing +and ProcessContextNonReplacing classes has changed from AudioBlock to +AudioBlock. + +Workaround +---------- +For ProcessContextReplacing you should use getOutputBlock() instead of +getInputBlock(). For ProcessContextNonReplacing attempting to modify the input +block is very likely an error. + +Rationale +--------- +This change makes the intent of the code much clearer and means that we can +remove some const_cast operations. + + Change ------ The formatting of floating point numbers written to XML and JSON files has diff --git a/modules/juce_dsp/containers/juce_AudioBlock.h b/modules/juce_dsp/containers/juce_AudioBlock.h index 6936604142..268a9c00af 100644 --- a/modules/juce_dsp/containers/juce_AudioBlock.h +++ b/modules/juce_dsp/containers/juce_AudioBlock.h @@ -32,10 +32,17 @@ namespace dsp #ifndef DOXYGEN namespace SampleTypeHelpers // Internal classes needed for handling sample type classes { - template struct ElementType { using Type = typename Container::value_type; }; - template <> struct ElementType { using Type = float; }; - template <> struct ElementType { using Type = double; }; - template <> struct ElementType { using Type = long double; }; + template ::value> + struct ElementType + { + using Type = T; + }; + + template + struct ElementType + { + using Type = typename T::value_type; + }; } #endif @@ -56,6 +63,15 @@ namespace SampleTypeHelpers // Internal classes needed for handling sample type 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; @@ -127,7 +143,8 @@ public: Therefore it is the user's responsibility to ensure that the buffer is retained throughout the life-time of the AudioBlock without being modified. */ - AudioBlock (AudioBuffer& buffer) noexcept + template + AudioBlock (AudioBuffer& buffer) noexcept : channels (buffer.getArrayOfWritePointers()), numChannels (static_cast (buffer.getNumChannels())), numSamples (static_cast (buffer.getNumSamples())) @@ -139,7 +156,8 @@ public: Therefore it is the user's responsibility to ensure that the buffer is retained throughout the life-time of the AudioBlock without being modified. */ - AudioBlock (AudioBuffer& buffer, size_t startSampleIndex) noexcept + template + AudioBlock (AudioBuffer& buffer, size_t startSampleIndex) noexcept : channels (buffer.getArrayOfWritePointers()), numChannels (static_cast (buffer.getNumChannels())), startSample (startSampleIndex), @@ -151,16 +169,45 @@ public: 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 copy { other }; + swap (copy); + 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); + } + //============================================================================== - bool operator== (const AudioBlock& other) const noexcept + template + 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; + return std::equal (channels, + channels + numChannels, + other.channels, + other.channels + other.numChannels) + && startSample == other.startSample + && numSamples == other.numSamples; } - bool operator!= (const AudioBlock& other) const noexcept + template + bool operator!= (const AudioBlock& other) const noexcept { return ! (*this == other); } @@ -264,7 +311,8 @@ public: } /** Copy the values in src to the receiver. */ - forcedinline AudioBlock& copy (AudioBlock src) noexcept + template + forcedinline AudioBlock& copy (const AudioBlock& src) noexcept { auto maxChannels = jmin (src.numChannels, numChannels); auto n = static_cast (jmin (src.numSamples, numSamples) * sizeFactor); @@ -381,7 +429,8 @@ public: } /** Adds the source values to the receiver. */ - forcedinline AudioBlock& add (AudioBlock src) noexcept + template + forcedinline AudioBlock& add (AudioBlock src) noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); @@ -393,7 +442,8 @@ public: } /** Adds a fixed value to each source value and stores it in the destination array of the receiver. */ - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE add (AudioBlock src, SampleType value) noexcept + 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); @@ -405,7 +455,8 @@ public: } /** Adds each source1 value to the corresponding source2 value and stores it in the destination array of the receiver. */ - forcedinline AudioBlock& add (AudioBlock src1, AudioBlock src2) noexcept + 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); @@ -423,7 +474,8 @@ public: } /** Subtracts the source values from the receiver. */ - forcedinline AudioBlock& subtract (AudioBlock src) noexcept + template + forcedinline AudioBlock& subtract (AudioBlock src) noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); @@ -435,13 +487,15 @@ public: } /** Subtracts a fixed value from each source value and stores it in the destination array of the receiver. */ - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE subtract (AudioBlock src, SampleType value) noexcept + 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. */ - forcedinline AudioBlock& subtract (AudioBlock src1, AudioBlock src2) noexcept + 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); @@ -464,7 +518,8 @@ public: } /** Multiplies the source values to the receiver. */ - forcedinline AudioBlock& multiply (AudioBlock src) noexcept + template + forcedinline AudioBlock& multiply (AudioBlock src) noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); @@ -476,7 +531,8 @@ public: } /** Multiplies a fixed value to each source value and stores it in the destination array of the receiver. */ - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE multiply (AudioBlock src, SampleType value) noexcept + 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); @@ -488,7 +544,8 @@ public: } /** Multiplies each source1 value to the corresponding source2 value and stores it in the destination array of the receiver. */ - forcedinline AudioBlock& multiply (AudioBlock src1, AudioBlock src2) noexcept + 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); @@ -522,8 +579,8 @@ public: } /** Multiplies all channels of the source by a smoothly changing value and stores them in the receiver. */ - template - AudioBlock& multiply (AudioBlock src, SmoothedValue& value) noexcept + template + AudioBlock& multiply (AudioBlock src, SmoothedValue& value) noexcept { jassert (numChannels == src.numChannels); @@ -548,7 +605,8 @@ public: } /** Multiplies each value in src with factor and adds the result to the receiver. */ - forcedinline AudioBlock& JUCE_VECTOR_CALLTYPE addWithMultiply (AudioBlock src, SampleType factor) noexcept + 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); @@ -560,7 +618,8 @@ public: } /** Multiplies each value in srcA with the corresponding value in srcB and adds the result to the receiver. */ - forcedinline AudioBlock& addWithMultiply (AudioBlock src1, AudioBlock src2) noexcept + 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); @@ -578,7 +637,8 @@ public: } /** Negates each value of source and stores it in the receiver. */ - forcedinline AudioBlock& replaceWithNegativeOf (AudioBlock src) noexcept + template + forcedinline AudioBlock& replaceWithNegativeOf (AudioBlock src) noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); @@ -590,7 +650,8 @@ public: } /** Takes the absolute value of each element of src and stores it inside the receiver. */ - forcedinline AudioBlock& replaceWithAbsoluteValueOf (AudioBlock src) noexcept + template + forcedinline AudioBlock& replaceWithAbsoluteValueOf (AudioBlock src) noexcept { jassert (numChannels == src.numChannels); auto n = static_cast (jmin (numSamples, src.numSamples) * sizeFactor); @@ -602,7 +663,8 @@ public: } /** Each element of receiver will be the minimum of the corresponding element of the source arrays. */ - forcedinline AudioBlock& min (AudioBlock src1, AudioBlock src2) noexcept + 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); @@ -614,7 +676,8 @@ public: } /** Each element of the receiver will be the maximum of the corresponding element of the source arrays. */ - forcedinline AudioBlock& max (AudioBlock src1, AudioBlock src2) noexcept + 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); @@ -653,11 +716,11 @@ public: //============================================================================== // This class can only be used with floating point types - static_assert (std::is_same::value - || std::is_same::value + static_assert (std::is_same, float>::value + || std::is_same, double>::value #if JUCE_USE_SIMD - || std::is_same>::value - || std::is_same>::value + || std::is_same, SIMDRegister>::value + || std::is_same, SIMDRegister>::value #endif , "AudioBlock only supports single or double precision floating point types"); @@ -666,8 +729,8 @@ public: 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) + template + static void process (AudioBlock inBlock, AudioBlock outBlock, FunctionType&& function) { auto len = inBlock.getNumSamples(); auto numChans = inBlock.getNumChannels(); @@ -707,6 +770,9 @@ private: SampleType* const* channels; ChannelCountType numChannels = 0; size_t startSample = 0, numSamples = 0; + + template + friend class AudioBlock; }; } // namespace dsp diff --git a/modules/juce_dsp/containers/juce_SIMDRegister.h b/modules/juce_dsp/containers/juce_SIMDRegister.h index 23e7ab5b30..602d3c081e 100644 --- a/modules/juce_dsp/containers/juce_SIMDRegister.h +++ b/modules/juce_dsp/containers/juce_SIMDRegister.h @@ -358,13 +358,6 @@ struct SIMDRegister return snapPointerToAlignment (ptr, SIMDRegisterSize); } - #ifndef DOXYGEN - static inline const ElementType* getNextSIMDAlignedPtr (const ElementType* ptr) noexcept - { - return snapPointerToAlignment (ptr, SIMDRegisterSize); - } - #endif - private: static inline vMaskType JUCE_VECTOR_CALLTYPE toMaskType (vSIMDType a) noexcept { diff --git a/modules/juce_dsp/frequency/juce_Convolution.cpp b/modules/juce_dsp/frequency/juce_Convolution.cpp index 99d1906b07..3d30eba5ca 100644 --- a/modules/juce_dsp/frequency/juce_Convolution.cpp +++ b/modules/juce_dsp/frequency/juce_Convolution.cpp @@ -718,7 +718,7 @@ struct Convolution::Pimpl : private Thread /** Convolution processing handling interpolation between previous and new states of the convolution engines. */ - void processSamples (const AudioBlock& input, AudioBlock& output) + void processSamples (const AudioBlock& input, AudioBlock& output) { processFifo(); @@ -1197,7 +1197,7 @@ void Convolution::reset() noexcept pimpl->reset(); } -void Convolution::processSamples (const AudioBlock& input, AudioBlock& output, bool isBypassed) noexcept +void Convolution::processSamples (const AudioBlock& input, AudioBlock& output, bool isBypassed) noexcept { if (! isActive) return; diff --git a/modules/juce_dsp/frequency/juce_Convolution.h b/modules/juce_dsp/frequency/juce_Convolution.h index 1a4aae40bc..cdf2fe10b8 100644 --- a/modules/juce_dsp/frequency/juce_Convolution.h +++ b/modules/juce_dsp/frequency/juce_Convolution.h @@ -156,7 +156,7 @@ private: std::unique_ptr pimpl; //============================================================================== - void processSamples (const AudioBlock&, AudioBlock&, bool isBypassed) noexcept; + void processSamples (const AudioBlock&, AudioBlock&, bool isBypassed) noexcept; //============================================================================== double sampleRate; diff --git a/modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h b/modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h index 87d0fc2e64..e45b32e6c7 100644 --- a/modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h +++ b/modules/juce_dsp/native/juce_fallback_SIMDNativeOps.h @@ -43,8 +43,8 @@ namespace SIMDInternal template <> struct MaskTypeFor > { using type = uint32_t; }; template <> struct MaskTypeFor > { using type = uint64_t; }; - template struct PrimitiveType { using type = Primitive; }; - template struct PrimitiveType> { using type = Primitive; }; + template struct PrimitiveType { using type = typename std::remove_cv::type; }; + template struct PrimitiveType> { using type = typename std::remove_cv::type; }; template struct Log2Helper { enum { value = Log2Helper::value + 1 }; }; template <> struct Log2Helper<1> { enum { value = 0 }; }; diff --git a/modules/juce_dsp/processors/juce_FIRFilter_test.cpp b/modules/juce_dsp/processors/juce_FIRFilter_test.cpp index 9f6da271c5..b54054c2d2 100644 --- a/modules/juce_dsp/processors/juce_FIRFilter_test.cpp +++ b/modules/juce_dsp/processors/juce_FIRFilter_test.cpp @@ -121,7 +121,7 @@ class FIRFilterTest : public UnitTest template static void run (FIR::Filter& filter, FloatType* src, FloatType* dst, size_t n) { - AudioBlock input (&src, 1, n); + AudioBlock input (&src, 1, n); AudioBlock output (&dst, 1, n); ProcessContextNonReplacing context (input, output); @@ -151,7 +151,7 @@ class FIRFilterTest : public UnitTest auto* src = input + i; auto* dst = output + i; - AudioBlock inBlock (&src, 1, len); + AudioBlock inBlock (&src, 1, len); AudioBlock outBlock (&dst, 1, len); ProcessContextNonReplacing context (inBlock, outBlock); diff --git a/modules/juce_dsp/processors/juce_ProcessContext.h b/modules/juce_dsp/processors/juce_ProcessContext.h index 9964d8eafc..63101b8471 100644 --- a/modules/juce_dsp/processors/juce_ProcessContext.h +++ b/modules/juce_dsp/processors/juce_ProcessContext.h @@ -83,6 +83,7 @@ public: using SampleType = ContextSampleType; /** The type of audio block that this context handles. */ using AudioBlockType = AudioBlock; + using ConstAudioBlockType = AudioBlock; /** Creates a ProcessContextReplacing that uses the given audio block. Note that the caller must not delete the block while it is still in use by this object! @@ -93,10 +94,10 @@ public: ProcessContextReplacing (ProcessContextReplacing&&) = default; /** Returns the audio block to use as the input to a process function. */ - const AudioBlockType& getInputBlock() const noexcept { return ioBlock; } + const ConstAudioBlockType& getInputBlock() const noexcept { return constBlock; } /** Returns the audio block to use as the output to a process function. */ - AudioBlockType& getOutputBlock() const noexcept { return const_cast (ioBlock); } + AudioBlockType& getOutputBlock() const noexcept { return ioBlock; } /** All process context classes will define this constant method so that templated code can determine whether the input and output blocks refer to the same buffer, @@ -111,6 +112,7 @@ public: private: AudioBlockType& ioBlock; + ConstAudioBlockType constBlock { ioBlock }; }; //============================================================================== @@ -134,11 +136,12 @@ public: using SampleType = ContextSampleType; /** The type of audio block that this context handles. */ using AudioBlockType = AudioBlock; + using ConstAudioBlockType = AudioBlock; /** Creates a ProcessContextReplacing that uses the given input and output blocks. Note that the caller must not delete these blocks while they are still in use by this object! */ - ProcessContextNonReplacing (const AudioBlockType& input, AudioBlockType& output) noexcept + ProcessContextNonReplacing (const ConstAudioBlockType& input, AudioBlockType& output) noexcept : inputBlock (input), outputBlock (output) { // If the input and output blocks are the same then you should use @@ -150,10 +153,10 @@ public: ProcessContextNonReplacing (ProcessContextNonReplacing&&) = default; /** Returns the audio block to use as the input to a process function. */ - const AudioBlockType& getInputBlock() const noexcept { return inputBlock; } + const ConstAudioBlockType& getInputBlock() const noexcept { return inputBlock; } /** Returns the audio block to use as the output to a process function. */ - AudioBlockType& getOutputBlock() const noexcept { return const_cast (outputBlock); } + AudioBlockType& getOutputBlock() const noexcept { return outputBlock; } /** All process context classes will define this constant method so that templated code can determine whether the input and output blocks refer to the same buffer, @@ -167,7 +170,7 @@ public: bool isBypassed = false; private: - const AudioBlockType& inputBlock; + const ConstAudioBlockType& inputBlock; AudioBlockType& outputBlock; }; diff --git a/modules/juce_dsp/processors/juce_ProcessorDuplicator.h b/modules/juce_dsp/processors/juce_ProcessorDuplicator.h index 725a3c349c..fe69366696 100644 --- a/modules/juce_dsp/processors/juce_ProcessorDuplicator.h +++ b/modules/juce_dsp/processors/juce_ProcessorDuplicator.h @@ -89,8 +89,8 @@ private: size_t channel; - typename ProcessContext::AudioBlockType getInputBlock() const noexcept { return ProcessContext::getInputBlock().getSingleChannelBlock (channel); } - typename ProcessContext::AudioBlockType getOutputBlock() const noexcept { return ProcessContext::getOutputBlock().getSingleChannelBlock (channel); } + typename ProcessContext::ConstAudioBlockType getInputBlock() const noexcept { return ProcessContext::getInputBlock() .getSingleChannelBlock (channel); } + typename ProcessContext::AudioBlockType getOutputBlock() const noexcept { return ProcessContext::getOutputBlock().getSingleChannelBlock (channel); } }; juce::OwnedArray processors;