diff --git a/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp b/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp index 126b2fe57b..e05f21e65e 100644 --- a/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp +++ b/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp @@ -37,24 +37,45 @@ AudioFormatReader::~AudioFormatReader() delete input; } +static void convertFixedToFloat (int* const* channels, int numChannels, int numSamples) +{ + for (int i = 0; i < numChannels; ++i) + if (auto d = channels[i]) + FloatVectorOperations::convertFixedToFloat (reinterpret_cast (d), d, 1.0f / 0x7fffffff, numSamples); +} + +bool AudioFormatReader::read (float* const* destChannels, int numDestChannels, + int64 startSampleInSource, int numSamplesToRead) +{ + auto channelsAsInt = reinterpret_cast (destChannels); + + if (! read (channelsAsInt, numDestChannels, startSampleInSource, numSamplesToRead, false)) + return false; + + if (! usesFloatingPointData) + convertFixedToFloat (channelsAsInt, numDestChannels, numSamplesToRead); + + return true; +} + bool AudioFormatReader::read (int* const* destSamples, int numDestChannels, int64 startSampleInSource, int numSamplesToRead, - const bool fillLeftoverChannelsWithCopies) + bool fillLeftoverChannelsWithCopies) { jassert (numDestChannels > 0); // you have to actually give this some channels to work with! - const size_t originalNumSamplesToRead = (size_t) numSamplesToRead; + auto originalNumSamplesToRead = (size_t) numSamplesToRead; int startOffsetInDestBuffer = 0; if (startSampleInSource < 0) { - const int silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead); + auto silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead); for (int i = numDestChannels; --i >= 0;) - if (destSamples[i] != nullptr) - zeromem (destSamples[i], sizeof (int) * (size_t) silence); + if (auto d = destSamples[i]) + zeromem (d, sizeof (int) * (size_t) silence); startOffsetInDestBuffer += silence; numSamplesToRead -= silence; @@ -73,7 +94,7 @@ bool AudioFormatReader::read (int* const* destSamples, { if (fillLeftoverChannelsWithCopies) { - int* lastFullChannel = destSamples[0]; + auto lastFullChannel = destSamples[0]; for (int i = (int) numChannels; --i > 0;) { @@ -86,14 +107,14 @@ bool AudioFormatReader::read (int* const* destSamples, if (lastFullChannel != nullptr) for (int i = (int) numChannels; i < numDestChannels; ++i) - if (destSamples[i] != nullptr) - memcpy (destSamples[i], lastFullChannel, sizeof (int) * originalNumSamplesToRead); + if (auto d = destSamples[i]) + memcpy (d, lastFullChannel, sizeof (int) * originalNumSamplesToRead); } else { for (int i = (int) numChannels; i < numDestChannels; ++i) - if (destSamples[i] != nullptr) - zeromem (destSamples[i], sizeof (int) * originalNumSamplesToRead); + if (auto d = destSamples[i]) + zeromem (d, sizeof (int) * originalNumSamplesToRead); } } @@ -101,13 +122,17 @@ bool AudioFormatReader::read (int* const* destSamples, } static void readChannels (AudioFormatReader& reader, int** chans, AudioBuffer* buffer, - int startSample, int numSamples, int64 readerStartSample, int numTargetChannels) + int startSample, int numSamples, int64 readerStartSample, int numTargetChannels, + bool convertToFloat) { for (int j = 0; j < numTargetChannels; ++j) chans[j] = reinterpret_cast (buffer->getWritePointer (j, startSample)); chans[numTargetChannels] = nullptr; reader.read (chans, numTargetChannels, readerStartSample, numSamples, true); + + if (convertToFloat) + convertFixedToFloat (chans, numTargetChannels, numSamples); } void AudioFormatReader::read (AudioBuffer* buffer, @@ -122,52 +147,51 @@ void AudioFormatReader::read (AudioBuffer* buffer, if (numSamples > 0) { - const int numTargetChannels = buffer->getNumChannels(); + auto numTargetChannels = buffer->getNumChannels(); if (numTargetChannels <= 2) { - int* const dest0 = reinterpret_cast (buffer->getWritePointer (0, startSample)); - int* const dest1 = reinterpret_cast (numTargetChannels > 1 ? buffer->getWritePointer (1, startSample) : nullptr); - int* chans[3]; + int* dests[2] = { reinterpret_cast (buffer->getWritePointer (0, startSample)), + reinterpret_cast (numTargetChannels > 1 ? buffer->getWritePointer (1, startSample) : nullptr) }; + int* chans[3] = {}; if (useReaderLeftChan == useReaderRightChan) { - chans[0] = dest0; - chans[1] = numChannels > 1 ? dest1 : nullptr; + chans[0] = dests[0]; + + if (numChannels > 1) + chans[1] = dests[1]; } else if (useReaderLeftChan || (numChannels == 1)) { - chans[0] = dest0; - chans[1] = nullptr; + chans[0] = dests[0]; } else if (useReaderRightChan) { - chans[0] = nullptr; - chans[1] = dest0; + chans[1] = dests[0]; } - chans[2] = nullptr; read (chans, 2, readerStartSample, numSamples, true); // if the target's stereo and the source is mono, dupe the first channel.. if (numTargetChannels > 1 && (chans[0] == nullptr || chans[1] == nullptr)) - memcpy (dest1, dest0, sizeof (float) * (size_t) numSamples); + memcpy (dests[1], dests[0], sizeof (float) * (size_t) numSamples); + + if (! usesFloatingPointData) + convertFixedToFloat (dests, 2, numSamples); } else if (numTargetChannels <= 64) { int* chans[65]; - readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); + readChannels (*this, chans, buffer, startSample, numSamples, + readerStartSample, numTargetChannels, ! usesFloatingPointData); } else { HeapBlock chans (numTargetChannels + 1); - readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); + readChannels (*this, chans, buffer, startSample, numSamples, + readerStartSample, numTargetChannels, ! usesFloatingPointData); } - - if (! usesFloatingPointData) - for (int j = 0; j < numTargetChannels; ++j) - if (float* const d = buffer->getWritePointer (j, startSample)) - FloatVectorOperations::convertFixedToFloat (d, reinterpret_cast (d), 1.0f / 0x7fffffff, numSamples); } } diff --git a/modules/juce_audio_formats/format/juce_AudioFormatReader.h b/modules/juce_audio_formats/format/juce_AudioFormatReader.h index 34a981b54a..da14d670a4 100644 --- a/modules/juce_audio_formats/format/juce_AudioFormatReader.h +++ b/modules/juce_audio_formats/format/juce_AudioFormatReader.h @@ -69,6 +69,27 @@ public: const String& getFormatName() const noexcept { return formatName; } //============================================================================== + /** Reads samples from the stream. + + @param destSamples an array of float buffers into which the sample data for each + channel will be written. Channels that aren't needed can be null + @param numDestChannels the number of array elements in the destChannels array + @param startSampleInSource the position in the audio file or stream at which the samples + should be read, as a number of samples from the start of the + stream. It's ok for this to be beyond the start or end of the + available data - any samples that are out-of-range will be returned + as zeros. + @param numSamplesToRead the number of samples to read. If this is greater than the number + of samples that the file or stream contains. the result will be padded + with zeros + @returns true if the operation succeeded, false if there was an error. Note + that reading sections of data beyond the extent of the stream isn't an + error - the reader should just return zeros for these regions + @see readMaxLevels + */ + bool read (float* const* destChannels, int numDestChannels, + int64 startSampleInSource, int numSamplesToRead); + /** Reads samples from the stream. @param destSamples an array of buffers into which the sample data for each