diff --git a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h index 15a16094a2..fa694081d9 100644 --- a/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h +++ b/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h @@ -641,62 +641,143 @@ public: }; //============================================================================== - template - using SourceDataPointerType = const typename std::remove_pointer::type*; + /** A struct that contains a SampleFormat and Endianness to be used with the source and + destination types when calling the interleaveSamples() and deinterleaveSamples() helpers. + + @see interleaveSamples, deinterleaveSamples + */ + template + struct Format + { + using DataFormat = DataFormatIn; + using Endianness = EndiannessIn; + }; + +private: + template + struct ChannelDataSubtypes; + + template + struct ChannelDataSubtypes + { + using ElementType = std::remove_pointer_t; + using ChannelType = std::conditional_t; + using DataType = std::conditional_t; + using PointerType = Pointer, + std::conditional_t>; + }; + + template + struct ChannelDataSubtypes> + { + using Subtypes = ChannelDataSubtypes; + using DataType = typename Subtypes::DataType; + using PointerType = typename Subtypes::PointerType; + }; + + template + struct ChannelData + { + using Subtypes = ChannelDataSubtypes; + using DataType = typename Subtypes::DataType; + using PointerType = typename Subtypes::PointerType; + + DataType data; + int channels; + }; + +public: + //============================================================================== + /** A sequence of interleaved samples used as the source for the deinterleaveSamples() method. */ + template using InterleavedSource = ChannelData; + /** A sequence of interleaved samples used as the destination for the interleaveSamples() method. */ + template using InterleavedDest = ChannelData; + /** A sequence of non-interleaved samples used as the source for the interleaveSamples() method. */ + template using NonInterleavedSource = ChannelData; + /** A sequence of non-interleaved samples used as the destination for the deinterleaveSamples() method. */ + template using NonInterleavedDest = ChannelData; /** A helper function for converting a sequence of samples from a non-interleaved source to an interleaved destination. + + When calling this method you need to specify the source and destination data format and endianness + from the AudioData SampleFormat and Endianness types and provide the data and number of channels + for each. For example, to convert a floating-point stream of big endian samples to an interleaved, + native endian stream of 16-bit integer samples you would do the following: + + @code + using SourceFormat = AudioData::Format; + using DestFormat = AudioData::Format; + + AudioData::interleaveSamples (AudioData::NonInterleavedSource { sourceData, numSourceChannels }, + AudioData::InterleavedDest { destData, numDestChannels }, + numSamples); + @endcode */ - template - static void interleaveSamples (SourceDataPointerType* sourceData, int numSourceChannels, - decltype (DestSampleFormat::data) destData, int numDestChannels, + template + static void interleaveSamples (NonInterleavedSource source, + InterleavedDest dest, int numSamples) { - using SourceType = Pointer ; - using DestType = Pointer ; + using SourceType = typename decltype (source)::PointerType; + using DestType = typename decltype (dest) ::PointerType; - for (int i = 0; i < numDestChannels; ++i) + for (int i = 0; i < dest.channels; ++i) { - const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels); + const DestType destType (addBytesToPointer (dest.data, i * DestType::getBytesPerSample()), dest.channels); - if (i < numSourceChannels) + if (i < source.channels) { - if (*sourceData != nullptr) + if (*source.data != nullptr) { - dest.convertSamples (SourceType (*sourceData), numSamples); - ++sourceData; + destType.convertSamples (SourceType { *source.data }, numSamples); + ++source.data; } } else { - dest.clearSamples (numSamples); + destType.clearSamples (numSamples); } } } /** A helper function for converting a sequence of samples from an interleaved source to a non-interleaved destination. + + When calling this method you need to specify the source and destination data format and endianness + from the AudioData SampleFormat and Endianness types and provide the data and number of channels + for each. For example, to convert a floating-point stream of big endian samples to an non-interleaved, + native endian stream of 16-bit integer samples you would do the following: + + @code + using SourceFormat = AudioData::Format; + using DestFormat = AudioData::Format; + + AudioData::deinterleaveSamples (AudioData::InterleavedSource { sourceData, numSourceChannels }, + AudioData::NonInterleavedDest { destData, numDestChannels }, + numSamples); + @endcode */ - template - static void deinterleaveSamples (SourceDataPointerType sourceData, int numSourceChannels, - decltype (DestSampleFormat::data)* destData, int numDestChannels, + template + static void deinterleaveSamples (InterleavedSource source, + NonInterleavedDest dest, int numSamples) { - using SourceType = Pointer ; - using DestType = Pointer ; + using SourceType = typename decltype (source)::PointerType; + using DestType = typename decltype (dest) ::PointerType; - for (int i = 0; i < numDestChannels; ++i) + for (int i = 0; i < dest.channels; ++i) { - if (auto* targetChan = destData[i]) + if (auto* targetChan = dest.data[i]) { - const DestType dest (targetChan); + const DestType destType (targetChan); - if (i < numSourceChannels) - dest.convertSamples (SourceType (addBytesToPointer (sourceData, i * SourceType::getBytesPerSample()), numSourceChannels), numSamples); + if (i < source.channels) + destType.convertSamples (SourceType (addBytesToPointer (source.data, i * SourceType::getBytesPerSample()), source.channels), numSamples); else - dest.clearSamples (numSamples); + destType.clearSamples (numSamples); } } } @@ -704,7 +785,6 @@ public: //============================================================================== #ifndef DOXYGEN - /** A set of routines to convert buffers of 32-bit floating point data to and from various integer formats. @@ -772,7 +852,6 @@ public: private: AudioDataConverters(); }; - #endif } // namespace juce