I need to read multichannel WAVs and AIFFs. It seemed all the buffering and source classes were ready but the second read member in juce_AudioFormatReader.cpp needed to be extended.
I used a similar approach seen here http://www.juce.com/forum/topic/audiosamplebufferreadfromaudioreader-multichannel-support and did it this way:
void AudioFormatReader::read (AudioSampleBuffer* buffer,
int startSample,
int numSamples,
int64 readerStartSample,
bool useReaderLeftChan,
bool useReaderRightChan)
{
jassert (buffer != nullptr);
jassert (startSample >= 0 && startSample + numSamples <= buffer->getNumSamples());
if (numSamples > 0)
{
const int numTargetChannels = buffer->getNumChannels();
HeapBlock<int*> chans(jmax (3, numTargetChannels + 1));
if (numTargetChannels < 3)
{
if (useReaderLeftChan == useReaderRightChan)
{
chans[0] = reinterpret_cast<int*> (buffer->getSampleData (0, startSample));
chans[1] = (numChannels > 1 && numTargetChannels > 1) ? reinterpret_cast<int*> (buffer->getSampleData (1, startSample)) : nullptr;
}
else if (useReaderLeftChan || (numChannels == 1))
{
chans[0] = reinterpret_cast<int*> (buffer->getSampleData (0, startSample));
chans[1] = nullptr;
}
else if (useReaderRightChan)
{
chans[0] = nullptr;
chans[1] = reinterpret_cast<int*> (buffer->getSampleData (0, startSample));
}
chans[2] = nullptr;
read (chans, 2, readerStartSample, numSamples, true);
}
else
{
for (int j = 0; j < numTargetChannels; ++j)
{
chans[j] = reinterpret_cast<int*> (buffer->getSampleData (j, startSample));
}
chans[numTargetChannels] = nullptr;
read (chans, numTargetChannels, readerStartSample, numSamples, true);
}
if (! usesFloatingPointData)
{
for (int j = 0; j < numTargetChannels; ++j)
{
if (float* const d = reinterpret_cast <float*> (chans[j]))
{
const float multiplier = 1.0f / 0x7fffffff;
for (int i = 0; i < numSamples; ++i)
d[i] = *reinterpret_cast<int*> (d + i) * multiplier;
}
}
}
if (numTargetChannels == 2 && (chans[0] == nullptr || chans[1] == nullptr))
{
// if this is a stereo buffer and the source was mono, dupe the first channel..
memcpy (buffer->getSampleData (1, startSample),
buffer->getSampleData (0, startSample),
sizeof (float) * (size_t) numSamples);
}
}
}
I've attached a diff against yesterday's tip if this is suitable for inclusion.
I'm not sure if the cost of making a HeapBlock on every call is too high. Perhaps an Array of int* as a private member of the class, grown if getNumChannels() changes?
