From 7b5b6cbd710a567b935295e71bdd2d09593b2822 Mon Sep 17 00:00:00 2001 From: jules Date: Thu, 28 Aug 2014 22:02:17 +0100 Subject: [PATCH] Added a version of AudioFormatReader::readMaxLevels() which takes any number of channels. --- .../format/juce_AudioFormatReader.cpp | 133 +++++++----------- .../format/juce_AudioFormatReader.h | 28 +++- 2 files changed, 75 insertions(+), 86 deletions(-) diff --git a/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp b/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp index 071f825089..2c644e947b 100644 --- a/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp +++ b/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp @@ -173,35 +173,54 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, } } -template -static Range getChannelMinAndMax (SampleType* channel, int numSamples) noexcept +void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples, + Range* const results, const int channelsToRead) { - return Range::findMinAndMax (channel, numSamples); -} + jassert (channelsToRead > 0 && channelsToRead <= numChannels); -static Range getChannelMinAndMax (float* channel, int numSamples) noexcept -{ - return FloatVectorOperations::findMinAndMax (channel, numSamples); -} - -template -static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples, - SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax) -{ - Range range (getChannelMinAndMax (channels[0], numSamples)); - lmax = jmax (lmax, range.getEnd()); - lmin = jmin (lmin, range.getStart()); - - if (numChannels > 1) + if (numSamples <= 0) { - range = getChannelMinAndMax (channels[1], numSamples); - rmax = jmax (rmax, range.getEnd()); - rmin = jmin (rmin, range.getStart()); + for (int i = 0; i < channelsToRead; ++i) + results[i] = Range(); + + return; } - else + + const int bufferSize = (int) jmin (numSamples, (int64) 4096); + AudioSampleBuffer tempSampleBuffer ((int) channelsToRead, bufferSize); + + float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers(); + int* const* intBuffer = reinterpret_cast (floatBuffer); + bool isFirstBlock = true; + + while (numSamples > 0) { - rmax = lmax; - rmin = lmin; + const int numToDo = (int) jmin (numSamples, (int64) bufferSize); + if (! read (intBuffer, channelsToRead, startSampleInFile, numToDo, false)) + break; + + for (int i = 0; i < channelsToRead; ++i) + { + Range r; + + if (usesFloatingPointData) + { + r = FloatVectorOperations::findMinAndMax (floatBuffer[i], numToDo); + } + else + { + Range intRange (Range::findMinAndMax (intBuffer[i], numToDo)); + + r = Range (intRange.getStart() / (float) std::numeric_limits::max(), + intRange.getEnd() / (float) std::numeric_limits::max()); + } + + results[i] = isFirstBlock ? r : results[i].getUnionWith (r); + } + + isFirstBlock = false; + numSamples -= numToDo; + startSampleInFile += numToDo; } } @@ -209,66 +228,20 @@ void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples float& lowestLeft, float& highestLeft, float& lowestRight, float& highestRight) { - if (numSamples <= 0) + Range levels[2]; + readMaxLevels (startSampleInFile, numSamples, levels, jmin (2, (int) numChannels)); + lowestLeft = levels[0].getStart(); + highestLeft = levels[0].getEnd(); + + if (numChannels > 1) { - lowestLeft = 0; - lowestRight = 0; - highestLeft = 0; - highestRight = 0; - return; - } - - const int bufferSize = (int) jmin (numSamples, (int64) 4096); - AudioSampleBuffer tempSampleBuffer ((int) numChannels, bufferSize); - - float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers(); - int* const* intBuffer = reinterpret_cast (floatBuffer); - - if (usesFloatingPointData) - { - float lmin = 1.0e6f; - float lmax = -lmin; - float rmin = lmin; - float rmax = lmax; - - while (numSamples > 0) - { - const int numToDo = (int) jmin (numSamples, (int64) bufferSize); - if (! read (intBuffer, 2, startSampleInFile, numToDo, false)) - break; - - numSamples -= numToDo; - startSampleInFile += numToDo; - getStereoMinAndMax (floatBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax); - } - - lowestLeft = lmin; - highestLeft = lmax; - lowestRight = rmin; - highestRight = rmax; + lowestRight = levels[1].getStart(); + highestRight = levels[1].getEnd(); } else { - int lmax = std::numeric_limits::min(); - int lmin = std::numeric_limits::max(); - int rmax = std::numeric_limits::min(); - int rmin = std::numeric_limits::max(); - - while (numSamples > 0) - { - const int numToDo = (int) jmin (numSamples, (int64) bufferSize); - if (! read (intBuffer, 2, startSampleInFile, numToDo, false)) - break; - - numSamples -= numToDo; - startSampleInFile += numToDo; - getStereoMinAndMax (intBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax); - } - - lowestLeft = lmin / (float) std::numeric_limits::max(); - highestLeft = lmax / (float) std::numeric_limits::max(); - lowestRight = rmin / (float) std::numeric_limits::max(); - highestRight = rmax / (float) std::numeric_limits::max(); + lowestRight = lowestLeft; + highestRight = highestLeft; } } diff --git a/modules/juce_audio_formats/format/juce_AudioFormatReader.h b/modules/juce_audio_formats/format/juce_AudioFormatReader.h index d7cdd9c867..065388a77b 100644 --- a/modules/juce_audio_formats/format/juce_AudioFormatReader.h +++ b/modules/juce_audio_formats/format/juce_AudioFormatReader.h @@ -121,6 +121,25 @@ public: bool useReaderLeftChan, bool useReaderRightChan); + /** Finds the highest and lowest sample levels from a section of the audio stream. + + This will read a block of samples from the stream, and measure the + highest and lowest sample levels from the channels in that section, returning + these as normalised floating-point levels. + + @param startSample the offset into the audio stream to start reading from. It's + ok for this to be beyond the start or end of the stream. + @param numSamples how many samples to read + @param results this array will be filled with Range values for each channel. + The array must contain numChannels elements. + @param numChannelsToRead the number of channels of data to scan. This must be + more than zero, but not more than the total number of channels + that the reader contains + @see read + */ + virtual void readMaxLevels (int64 startSample, int64 numSamples, + Range* results, int numChannelsToRead); + /** Finds the highest and lowest sample levels from a section of the audio stream. This will read a block of samples from the stream, and measure the @@ -138,12 +157,9 @@ public: channel (if there is one) @see read */ - virtual void readMaxLevels (int64 startSample, - int64 numSamples, - float& lowestLeft, - float& highestLeft, - float& lowestRight, - float& highestRight); + virtual void readMaxLevels (int64 startSample, int64 numSamples, + float& lowestLeft, float& highestLeft, + float& lowestRight, float& highestRight); /** Scans the source looking for a sample whose magnitude is in a specified range.