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?