mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Reservoir: Factor out reservoir management code
This commit is contained in:
parent
abd5fe4a69
commit
930a3299f2
7 changed files with 347 additions and 217 deletions
|
|
@ -167,6 +167,8 @@ namespace FlacNamespace
|
|||
//==============================================================================
|
||||
static const char* const flacFormatName = "FLAC file";
|
||||
|
||||
template <typename Item>
|
||||
auto emptyRange (Item item) { return Range<Item>::emptyRange (item); }
|
||||
|
||||
//==============================================================================
|
||||
class FlacReader : public AudioFormatReader
|
||||
|
|
@ -217,66 +219,61 @@ public:
|
|||
reservoir.setSize ((int) numChannels, 2 * (int) info.max_blocksize, false, false, true);
|
||||
}
|
||||
|
||||
// returns the number of samples read
|
||||
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
|
||||
int64 startSampleInFile, int numSamples) override
|
||||
{
|
||||
if (! ok)
|
||||
return false;
|
||||
|
||||
while (numSamples > 0)
|
||||
const auto getBufferedRange = [this] { return bufferedRange; };
|
||||
|
||||
const auto readFromReservoir = [this, &destSamples, &numDestChannels, &startOffsetInDestBuffer, &startSampleInFile] (const Range<int64> rangeToRead)
|
||||
{
|
||||
if (startSampleInFile >= reservoirStart
|
||||
&& startSampleInFile < reservoirStart + samplesInReservoir)
|
||||
const auto bufferIndices = rangeToRead - bufferedRange.getStart();
|
||||
const auto writePos = (int64) startOffsetInDestBuffer + (rangeToRead.getStart() - startSampleInFile);
|
||||
|
||||
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
|
||||
{
|
||||
auto num = (int) jmin ((int64) numSamples,
|
||||
reservoirStart + samplesInReservoir - startSampleInFile);
|
||||
|
||||
jassert (num > 0);
|
||||
|
||||
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
|
||||
if (destSamples[i] != nullptr)
|
||||
memcpy (destSamples[i] + startOffsetInDestBuffer,
|
||||
reservoir.getReadPointer (i, (int) (startSampleInFile - reservoirStart)),
|
||||
(size_t) num * sizeof (int));
|
||||
|
||||
startOffsetInDestBuffer += num;
|
||||
startSampleInFile += num;
|
||||
numSamples -= num;
|
||||
if (destSamples[i] != nullptr)
|
||||
{
|
||||
memcpy (destSamples[i] + writePos,
|
||||
reservoir.getReadPointer (i) + bufferIndices.getStart(),
|
||||
(size_t) bufferIndices.getLength() * sizeof (int));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startSampleInFile >= lengthInSamples)
|
||||
{
|
||||
samplesInReservoir = 0;
|
||||
}
|
||||
else if (startSampleInFile < reservoirStart
|
||||
|| startSampleInFile > reservoirStart + jmax (samplesInReservoir, (int64) 511))
|
||||
{
|
||||
// had some problems with flac crashing if the read pos is aligned more
|
||||
// accurately than this. Probably fixed in newer versions of the library, though.
|
||||
reservoirStart = (int) (startSampleInFile & ~511);
|
||||
samplesInReservoir = 0;
|
||||
FLAC__stream_decoder_seek_absolute (decoder, (FlacNamespace::FLAC__uint64) reservoirStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
reservoirStart += samplesInReservoir;
|
||||
samplesInReservoir = 0;
|
||||
FLAC__stream_decoder_process_single (decoder);
|
||||
}
|
||||
};
|
||||
|
||||
if (samplesInReservoir == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (numSamples > 0)
|
||||
const auto fillReservoir = [this] (const int64 requestedStart)
|
||||
{
|
||||
if (requestedStart >= lengthInSamples)
|
||||
{
|
||||
bufferedRange = emptyRange (requestedStart);
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestedStart < bufferedRange.getStart()
|
||||
|| jmax (bufferedRange.getEnd(), bufferedRange.getStart() + (int64) 511) < requestedStart)
|
||||
{
|
||||
// had some problems with flac crashing if the read pos is aligned more
|
||||
// accurately than this. Probably fixed in newer versions of the library, though.
|
||||
bufferedRange = emptyRange (requestedStart & ~511);
|
||||
FLAC__stream_decoder_seek_absolute (decoder, (FlacNamespace::FLAC__uint64) bufferedRange.getStart());
|
||||
return;
|
||||
}
|
||||
|
||||
bufferedRange = emptyRange (bufferedRange.getEnd());
|
||||
FLAC__stream_decoder_process_single (decoder);
|
||||
};
|
||||
|
||||
const auto remainingSamples = Reservoir::doBufferedRead (Range<int64> { startSampleInFile, startSampleInFile + numSamples },
|
||||
getBufferedRange,
|
||||
readFromReservoir,
|
||||
fillReservoir);
|
||||
|
||||
if (! remainingSamples.isEmpty())
|
||||
for (int i = numDestChannels; --i >= 0;)
|
||||
if (destSamples[i] != nullptr)
|
||||
zeromem (destSamples[i] + startOffsetInDestBuffer, (size_t) numSamples * sizeof (int));
|
||||
}
|
||||
zeromem (destSamples[i] + startOffsetInDestBuffer, (size_t) remainingSamples.getLength() * sizeof (int));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -304,14 +301,14 @@ public:
|
|||
|
||||
if (src != nullptr)
|
||||
{
|
||||
auto* dest = reinterpret_cast<int*> (reservoir.getWritePointer(i));
|
||||
auto* dest = reinterpret_cast<int*> (reservoir.getWritePointer (i));
|
||||
|
||||
for (int j = 0; j < numSamples; ++j)
|
||||
dest[j] = src[j] << bitsToShift;
|
||||
}
|
||||
}
|
||||
|
||||
samplesInReservoir = numSamples;
|
||||
bufferedRange.setLength (numSamples);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -368,7 +365,7 @@ public:
|
|||
private:
|
||||
FlacNamespace::FLAC__StreamDecoder* decoder;
|
||||
AudioBuffer<float> reservoir;
|
||||
int64 reservoirStart = 0, samplesInReservoir = 0;
|
||||
Range<int64> bufferedRange;
|
||||
bool ok = false, scanningForLength = false;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacReader)
|
||||
|
|
|
|||
|
|
@ -158,72 +158,62 @@ public:
|
|||
bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
|
||||
int64 startSampleInFile, int numSamples) override
|
||||
{
|
||||
while (numSamples > 0)
|
||||
const auto getBufferedRange = [this] { return bufferedRange; };
|
||||
|
||||
const auto readFromReservoir = [this, &destSamples, &numDestChannels, &startOffsetInDestBuffer, &startSampleInFile] (const Range<int64> rangeToRead)
|
||||
{
|
||||
auto numAvailable = (reservoirStart + samplesInReservoir - startSampleInFile);
|
||||
const auto bufferIndices = rangeToRead - bufferedRange.getStart();
|
||||
const auto writePos = (int64) startOffsetInDestBuffer + (rangeToRead.getStart() - startSampleInFile);
|
||||
|
||||
if (startSampleInFile >= reservoirStart && numAvailable > 0)
|
||||
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
|
||||
if (destSamples[i] != nullptr)
|
||||
memcpy (destSamples[i] + writePos,
|
||||
reservoir.getReadPointer (i) + bufferIndices.getStart(),
|
||||
(size_t) bufferIndices.getLength() * sizeof (float));
|
||||
};
|
||||
|
||||
const auto fillReservoir = [this] (int64 requestedStart)
|
||||
{
|
||||
const auto newStart = jmax ((int64) 0, requestedStart);
|
||||
bufferedRange = Range<int64> { newStart, newStart + reservoir.getNumSamples() };
|
||||
|
||||
if (bufferedRange.getStart() != ov_pcm_tell (&ovFile))
|
||||
ov_pcm_seek (&ovFile, bufferedRange.getStart());
|
||||
|
||||
int bitStream = 0;
|
||||
int offset = 0;
|
||||
int numToRead = (int) bufferedRange.getLength();
|
||||
|
||||
while (numToRead > 0)
|
||||
{
|
||||
// got a few samples overlapping, so use them before seeking..
|
||||
float** dataIn = nullptr;
|
||||
auto samps = static_cast<int> (ov_read_float (&ovFile, &dataIn, numToRead, &bitStream));
|
||||
|
||||
auto numToUse = jmin ((int64) numSamples, numAvailable);
|
||||
|
||||
for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
|
||||
if (destSamples[i] != nullptr)
|
||||
memcpy (destSamples[i] + startOffsetInDestBuffer,
|
||||
reservoir.getReadPointer (i, (int) (startSampleInFile - reservoirStart)),
|
||||
(size_t) numToUse * sizeof (float));
|
||||
|
||||
startSampleInFile += numToUse;
|
||||
numSamples -= (int) numToUse;
|
||||
startOffsetInDestBuffer += (int) numToUse;
|
||||
|
||||
if (numSamples == 0)
|
||||
if (samps <= 0)
|
||||
break;
|
||||
|
||||
jassert (samps <= numToRead);
|
||||
|
||||
for (int i = jmin ((int) numChannels, reservoir.getNumChannels()); --i >= 0;)
|
||||
memcpy (reservoir.getWritePointer (i, offset), dataIn[i], (size_t) samps * sizeof (float));
|
||||
|
||||
numToRead -= samps;
|
||||
offset += samps;
|
||||
}
|
||||
|
||||
if (startSampleInFile < reservoirStart
|
||||
|| startSampleInFile + numSamples > reservoirStart + samplesInReservoir)
|
||||
{
|
||||
// buffer miss, so refill the reservoir
|
||||
reservoirStart = jmax (0, (int) startSampleInFile);
|
||||
samplesInReservoir = reservoir.getNumSamples();
|
||||
if (numToRead > 0)
|
||||
reservoir.clear (offset, numToRead);
|
||||
};
|
||||
|
||||
if (reservoirStart != (int) ov_pcm_tell (&ovFile))
|
||||
ov_pcm_seek (&ovFile, reservoirStart);
|
||||
const auto remainingSamples = Reservoir::doBufferedRead (Range<int64> { startSampleInFile, startSampleInFile + numSamples },
|
||||
getBufferedRange,
|
||||
readFromReservoir,
|
||||
fillReservoir);
|
||||
|
||||
int bitStream = 0;
|
||||
int offset = 0;
|
||||
int numToRead = (int) samplesInReservoir;
|
||||
|
||||
while (numToRead > 0)
|
||||
{
|
||||
float** dataIn = nullptr;
|
||||
auto samps = static_cast<int> (ov_read_float (&ovFile, &dataIn, numToRead, &bitStream));
|
||||
|
||||
if (samps <= 0)
|
||||
break;
|
||||
|
||||
jassert (samps <= numToRead);
|
||||
|
||||
for (int i = jmin ((int) numChannels, reservoir.getNumChannels()); --i >= 0;)
|
||||
memcpy (reservoir.getWritePointer (i, offset), dataIn[i], (size_t) samps * sizeof (float));
|
||||
|
||||
numToRead -= samps;
|
||||
offset += samps;
|
||||
}
|
||||
|
||||
if (numToRead > 0)
|
||||
reservoir.clear (offset, numToRead);
|
||||
}
|
||||
}
|
||||
|
||||
if (numSamples > 0)
|
||||
{
|
||||
if (! remainingSamples.isEmpty())
|
||||
for (int i = numDestChannels; --i >= 0;)
|
||||
if (destSamples[i] != nullptr)
|
||||
zeromem (destSamples[i] + startOffsetInDestBuffer, (size_t) numSamples * sizeof (int));
|
||||
}
|
||||
zeromem (destSamples[i] + startOffsetInDestBuffer, (size_t) remainingSamples.getLength() * sizeof (int));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -261,7 +251,7 @@ private:
|
|||
OggVorbisNamespace::OggVorbis_File ovFile;
|
||||
OggVorbisNamespace::ov_callbacks callbacks;
|
||||
AudioBuffer<float> reservoir;
|
||||
int64 reservoirStart = 0, samplesInReservoir = 0;
|
||||
Range<int64> bufferedRange;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OggReader)
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue