mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Improve AudioData interleaving/deinterleaving helper methods API and add docs
This commit is contained in:
parent
95b1dce49c
commit
d9a3a2605d
1 changed files with 108 additions and 29 deletions
|
|
@ -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…
Add table
Add a link
Reference in a new issue