mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
AudioData: Add helper methods for interleaving/deinterleaving samples
This commit is contained in:
parent
bb9b24d048
commit
52025f9756
2 changed files with 109 additions and 24 deletions
|
|
@ -434,32 +434,14 @@ void AudioDataConverters::convertFormatToFloat (DataFormat sourceFormat, const v
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
|
void AudioDataConverters::interleaveSamples (const float** source, float* dest, int numSamples, int numChannels)
|
||||||
{
|
{
|
||||||
for (int chan = 0; chan < numChannels; ++chan)
|
AudioData::interleaveSamples<AudioData::Float32, AudioData::NativeEndian,
|
||||||
{
|
AudioData::Float32, AudioData::NativeEndian> (source, numChannels, dest, numChannels, numSamples);
|
||||||
auto i = chan;
|
|
||||||
auto src = source [chan];
|
|
||||||
|
|
||||||
for (int j = 0; j < numSamples; ++j)
|
|
||||||
{
|
|
||||||
dest [i] = src [j];
|
|
||||||
i += numChannels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
|
void AudioDataConverters::deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels)
|
||||||
{
|
{
|
||||||
for (int chan = 0; chan < numChannels; ++chan)
|
AudioData::deinterleaveSamples<AudioData::Float32, AudioData::NativeEndian,
|
||||||
{
|
AudioData::Float32, AudioData::NativeEndian> (source, numChannels, dest, numChannels, numSamples);
|
||||||
auto i = chan;
|
|
||||||
auto dst = dest [chan];
|
|
||||||
|
|
||||||
for (int j = 0; j < numSamples; ++j)
|
|
||||||
{
|
|
||||||
dst [j] = source [i];
|
|
||||||
i += numChannels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -591,6 +573,50 @@ public:
|
||||||
Test1 <AudioData::Int32>::test (*this, r);
|
Test1 <AudioData::Int32>::test (*this, r);
|
||||||
beginTest ("Round-trip conversion: Float32");
|
beginTest ("Round-trip conversion: Float32");
|
||||||
Test1 <AudioData::Float32>::test (*this, r);
|
Test1 <AudioData::Float32>::test (*this, r);
|
||||||
|
|
||||||
|
beginTest ("Interleaving");
|
||||||
|
{
|
||||||
|
constexpr auto numChannels = 4;
|
||||||
|
constexpr auto numSamples = 512;
|
||||||
|
|
||||||
|
AudioBuffer<float> sourceBuffer { numChannels, numSamples },
|
||||||
|
destBuffer { 1, numChannels * numSamples };
|
||||||
|
|
||||||
|
for (int ch = 0; ch < numChannels; ++ch)
|
||||||
|
for (int i = 0; i < numSamples; ++i)
|
||||||
|
sourceBuffer.setSample (ch, i, r.nextFloat());
|
||||||
|
|
||||||
|
AudioData::interleaveSamples<AudioData::Float32, AudioData::NativeEndian,
|
||||||
|
AudioData::Float32, AudioData::NativeEndian> (sourceBuffer.getArrayOfReadPointers(), numChannels,
|
||||||
|
destBuffer.getWritePointer (0), numChannels,
|
||||||
|
numSamples);
|
||||||
|
|
||||||
|
for (int ch = 0; ch < numChannels; ++ch)
|
||||||
|
for (int i = 0; i < numSamples; ++i)
|
||||||
|
expect (destBuffer.getSample (0, ch + (i * numChannels)) == sourceBuffer.getSample (ch, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
beginTest ("Deinterleaving");
|
||||||
|
{
|
||||||
|
constexpr auto numChannels = 4;
|
||||||
|
constexpr auto numSamples = 512;
|
||||||
|
|
||||||
|
AudioBuffer<float> sourceBuffer { 1, numChannels * numSamples },
|
||||||
|
destBuffer { numChannels, numSamples };
|
||||||
|
|
||||||
|
for (int ch = 0; ch < numChannels; ++ch)
|
||||||
|
for (int i = 0; i < numSamples; ++i)
|
||||||
|
sourceBuffer.setSample (0, ch + (i * numChannels), r.nextFloat());
|
||||||
|
|
||||||
|
AudioData::deinterleaveSamples<AudioData::Float32, AudioData::NativeEndian,
|
||||||
|
AudioData::Float32, AudioData::NativeEndian> (sourceBuffer.getReadPointer (0), numChannels,
|
||||||
|
destBuffer.getArrayOfWritePointers(), numChannels,
|
||||||
|
numSamples);
|
||||||
|
|
||||||
|
for (int ch = 0; ch < numChannels; ++ch)
|
||||||
|
for (int i = 0; i < numSamples; ++i)
|
||||||
|
expect (sourceBuffer.getSample (0, ch + (i * numChannels)) == destBuffer.getSample (ch, i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -639,10 +639,69 @@ public:
|
||||||
|
|
||||||
const int sourceChannels, destChannels;
|
const int sourceChannels, destChannels;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename T>
|
||||||
|
using SourceDataPointerType = const typename std::remove_pointer<decltype (T::data)>::type*;
|
||||||
|
|
||||||
|
/** A helper function for converting a sequence of samples from a non-interleaved source
|
||||||
|
to an interleaved destination.
|
||||||
|
*/
|
||||||
|
template <typename SourceSampleFormat, typename SourceEndianness,
|
||||||
|
typename DestSampleFormat, typename DestEndianness>
|
||||||
|
static void interleaveSamples (SourceDataPointerType<SourceSampleFormat>* sourceData, int numSourceChannels,
|
||||||
|
decltype (DestSampleFormat::data) destData, int numDestChannels,
|
||||||
|
int numSamples)
|
||||||
|
{
|
||||||
|
using SourceType = Pointer <SourceSampleFormat, SourceEndianness, NonInterleaved, Const>;
|
||||||
|
using DestType = Pointer <DestSampleFormat, DestEndianness, Interleaved, NonConst>;
|
||||||
|
|
||||||
|
for (int i = 0; i < numDestChannels; ++i)
|
||||||
|
{
|
||||||
|
const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels);
|
||||||
|
|
||||||
|
if (i < numSourceChannels)
|
||||||
|
{
|
||||||
|
if (*sourceData != nullptr)
|
||||||
|
{
|
||||||
|
dest.convertSamples (SourceType (*sourceData), numSamples);
|
||||||
|
++sourceData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest.clearSamples (numSamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A helper function for converting a sequence of samples from an interleaved source
|
||||||
|
to a non-interleaved destination.
|
||||||
|
*/
|
||||||
|
template <typename SourceSampleFormat, typename SourceEndianness,
|
||||||
|
typename DestSampleFormat, typename DestEndianness>
|
||||||
|
static void deinterleaveSamples (SourceDataPointerType<SourceSampleFormat> sourceData, int numSourceChannels,
|
||||||
|
decltype (DestSampleFormat::data)* destData, int numDestChannels,
|
||||||
|
int numSamples)
|
||||||
|
{
|
||||||
|
using SourceType = Pointer <SourceSampleFormat, SourceEndianness, Interleaved, Const>;
|
||||||
|
using DestType = Pointer <DestSampleFormat, DestEndianness, NonInterleaved, NonConst>;
|
||||||
|
|
||||||
|
for (int i = 0; i < numDestChannels; ++i)
|
||||||
|
{
|
||||||
|
if (auto* targetChan = destData[i])
|
||||||
|
{
|
||||||
|
const DestType dest (targetChan);
|
||||||
|
|
||||||
|
if (i < numSourceChannels)
|
||||||
|
dest.convertSamples (SourceType (addBytesToPointer (sourceData, i * SourceType::getBytesPerSample()), numSourceChannels), numSamples);
|
||||||
|
else
|
||||||
|
dest.clearSamples (numSamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
#ifndef DOXYGEN
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue