Browse Source

Improve AudioData interleaving/deinterleaving helper methods API and add docs

v6.1.6
ed 4 years ago
parent
commit
d9a3a2605d
1 changed files with 108 additions and 29 deletions
  1. +108
    -29
      modules/juce_audio_basics/buffers/juce_AudioDataConverters.h

+ 108
- 29
modules/juce_audio_basics/buffers/juce_AudioDataConverters.h View File

@@ -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

Loading…
Cancel
Save