| @@ -641,62 +641,143 @@ public: | |||
| }; | |||
| //============================================================================== | |||
| template <typename T> | |||
| using SourceDataPointerType = const typename std::remove_pointer<decltype (T::data)>::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 <typename DataFormatIn, typename EndiannessIn> | |||
| struct Format | |||
| { | |||
| using DataFormat = DataFormatIn; | |||
| using Endianness = EndiannessIn; | |||
| }; | |||
| private: | |||
| template <bool IsInterleaved, bool IsConst, typename...> | |||
| struct ChannelDataSubtypes; | |||
| template <bool IsInterleaved, bool IsConst, typename DataFormat, typename Endianness> | |||
| struct ChannelDataSubtypes<IsInterleaved, IsConst, DataFormat, Endianness> | |||
| { | |||
| using ElementType = std::remove_pointer_t<decltype (DataFormat::data)>; | |||
| using ChannelType = std::conditional_t<IsConst, const ElementType*, ElementType*>; | |||
| using DataType = std::conditional_t<IsInterleaved, ChannelType, ChannelType*>; | |||
| using PointerType = Pointer<DataFormat, | |||
| Endianness, | |||
| std::conditional_t<IsInterleaved, Interleaved, NonInterleaved>, | |||
| std::conditional_t<IsConst, Const, NonConst>>; | |||
| }; | |||
| template <bool IsInterleaved, bool IsConst, typename DataFormat, typename Endianness> | |||
| struct ChannelDataSubtypes<IsInterleaved, IsConst, Format<DataFormat, Endianness>> | |||
| { | |||
| using Subtypes = ChannelDataSubtypes<IsInterleaved, IsConst, DataFormat, Endianness>; | |||
| using DataType = typename Subtypes::DataType; | |||
| using PointerType = typename Subtypes::PointerType; | |||
| }; | |||
| template <bool IsInterleaved, bool IsConst, typename... Format> | |||
| struct ChannelData | |||
| { | |||
| using Subtypes = ChannelDataSubtypes<IsInterleaved, IsConst, Format...>; | |||
| 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 <typename... Format> using InterleavedSource = ChannelData<true, true, Format...>; | |||
| /** A sequence of interleaved samples used as the destination for the interleaveSamples() method. */ | |||
| template <typename... Format> using InterleavedDest = ChannelData<true, false, Format...>; | |||
| /** A sequence of non-interleaved samples used as the source for the interleaveSamples() method. */ | |||
| template <typename... Format> using NonInterleavedSource = ChannelData<false, true, Format...>; | |||
| /** A sequence of non-interleaved samples used as the destination for the deinterleaveSamples() method. */ | |||
| template <typename... Format> using NonInterleavedDest = ChannelData<false, false, Format...>; | |||
| /** 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<AudioData::Float32, AudioData::BigEndian>; | |||
| using DestFormat = AudioData::Format<AudioData::Int16, AudioData::NativeEndian>; | |||
| AudioData::interleaveSamples (AudioData::NonInterleavedSource<SourceFormat> { sourceData, numSourceChannels }, | |||
| AudioData::InterleavedDest<DestFormat> { destData, numDestChannels }, | |||
| numSamples); | |||
| @endcode | |||
| */ | |||
| template <typename SourceSampleFormat, typename SourceEndianness, | |||
| typename DestSampleFormat, typename DestEndianness> | |||
| static void interleaveSamples (SourceDataPointerType<SourceSampleFormat>* sourceData, int numSourceChannels, | |||
| decltype (DestSampleFormat::data) destData, int numDestChannels, | |||
| template <typename... SourceFormat, typename... DestFormat> | |||
| static void interleaveSamples (NonInterleavedSource<SourceFormat...> source, | |||
| InterleavedDest<DestFormat...> dest, | |||
| int numSamples) | |||
| { | |||
| using SourceType = Pointer <SourceSampleFormat, SourceEndianness, NonInterleaved, Const>; | |||
| using DestType = Pointer <DestSampleFormat, DestEndianness, Interleaved, NonConst>; | |||
| 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<AudioData::Float32, AudioData::BigEndian>; | |||
| using DestFormat = AudioData::Format<AudioData::Int16, AudioData::NativeEndian>; | |||
| AudioData::deinterleaveSamples (AudioData::InterleavedSource<SourceFormat> { sourceData, numSourceChannels }, | |||
| AudioData::NonInterleavedDest<DestFormat> { destData, numDestChannels }, | |||
| numSamples); | |||
| @endcode | |||
| */ | |||
| template <typename SourceSampleFormat, typename SourceEndianness, | |||
| typename DestSampleFormat, typename DestEndianness> | |||
| static void deinterleaveSamples (SourceDataPointerType<SourceSampleFormat> sourceData, int numSourceChannels, | |||
| decltype (DestSampleFormat::data)* destData, int numDestChannels, | |||
| template <typename... SourceFormat, typename... DestFormat> | |||
| static void deinterleaveSamples (InterleavedSource<SourceFormat...> source, | |||
| NonInterleavedDest<DestFormat...> dest, | |||
| int numSamples) | |||
| { | |||
| using SourceType = Pointer <SourceSampleFormat, SourceEndianness, Interleaved, Const>; | |||
| using DestType = Pointer <DestSampleFormat, DestEndianness, NonInterleaved, NonConst>; | |||
| 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 | |||