OpenShot Library | libopenshot-audio 0.2.0
juce_BufferingAudioFormatReader.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11 Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12 27th April 2017).
13
14 End User License Agreement: www.juce.com/juce-5-licence
15 Privacy Policy: www.juce.com/juce-5-privacy-policy
16
17 Or: You may also use this code under the terms of the GPL v3 (see
18 www.gnu.org/licenses).
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
31 TimeSliceThread& timeSliceThread,
32 int samplesToBuffer)
33 : AudioFormatReader (nullptr, sourceReader->getFormatName()),
34 source (sourceReader), thread (timeSliceThread),
35 numBlocks (1 + (samplesToBuffer / samplesPerBlock))
36{
37 sampleRate = source->sampleRate;
38 lengthInSamples = source->lengthInSamples;
39 numChannels = source->numChannels;
40 metadataValues = source->metadataValues;
41 bitsPerSample = 32;
43
44 for (int i = 3; --i >= 0;)
45 readNextBufferChunk();
46
47 timeSliceThread.addTimeSliceClient (this);
48}
49
50BufferingAudioReader::~BufferingAudioReader()
51{
52 thread.removeTimeSliceClient (this);
53}
54
55void BufferingAudioReader::setReadTimeout (int timeoutMilliseconds) noexcept
56{
57 timeoutMs = timeoutMilliseconds;
58}
59
60bool BufferingAudioReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
61 int64 startSampleInFile, int numSamples)
62{
63 auto startTime = Time::getMillisecondCounter();
64 clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
65 startSampleInFile, numSamples, lengthInSamples);
66
67 const ScopedLock sl (lock);
68 nextReadPosition = startSampleInFile;
69
70 while (numSamples > 0)
71 {
72 if (auto block = getBlockContaining (startSampleInFile))
73 {
74 auto offset = (int) (startSampleInFile - block->range.getStart());
75 auto numToDo = jmin (numSamples, (int) (block->range.getEnd() - startSampleInFile));
76
77 for (int j = 0; j < numDestChannels; ++j)
78 {
79 if (auto dest = (float*) destSamples[j])
80 {
81 dest += startOffsetInDestBuffer;
82
83 if (j < (int) numChannels)
84 FloatVectorOperations::copy (dest, block->buffer.getReadPointer (j, offset), numToDo);
85 else
86 FloatVectorOperations::clear (dest, numToDo);
87 }
88 }
89
90 startOffsetInDestBuffer += numToDo;
91 startSampleInFile += numToDo;
92 numSamples -= numToDo;
93 }
94 else
95 {
96 if (timeoutMs >= 0 && Time::getMillisecondCounter() >= startTime + (uint32) timeoutMs)
97 {
98 for (int j = 0; j < numDestChannels; ++j)
99 if (auto dest = (float*) destSamples[j])
100 FloatVectorOperations::clear (dest + startOffsetInDestBuffer, numSamples);
101
102 break;
103 }
104 else
105 {
106 ScopedUnlock ul (lock);
108 }
109 }
110 }
111
112 return true;
113}
114
115BufferingAudioReader::BufferedBlock::BufferedBlock (AudioFormatReader& reader, int64 pos, int numSamples)
116 : range (pos, pos + numSamples),
117 buffer ((int) reader.numChannels, numSamples)
118{
119 reader.read (&buffer, 0, numSamples, pos, true, true);
120}
121
122BufferingAudioReader::BufferedBlock* BufferingAudioReader::getBlockContaining (int64 pos) const noexcept
123{
124 for (auto* b : blocks)
125 if (b->range.contains (pos))
126 return b;
127
128 return nullptr;
129}
130
131int BufferingAudioReader::useTimeSlice()
132{
133 return readNextBufferChunk() ? 1 : 100;
134}
135
136bool BufferingAudioReader::readNextBufferChunk()
137{
138 auto pos = nextReadPosition.load();
139 auto startPos = ((pos - 1024) / samplesPerBlock) * samplesPerBlock;
140 auto endPos = startPos + numBlocks * samplesPerBlock;
141
142 OwnedArray<BufferedBlock> newBlocks;
143
144 for (int i = blocks.size(); --i >= 0;)
145 if (blocks.getUnchecked(i)->range.intersects (Range<int64> (startPos, endPos)))
146 newBlocks.add (blocks.getUnchecked(i));
147
148 if (newBlocks.size() == numBlocks)
149 {
150 newBlocks.clear (false);
151 return false;
152 }
153
154 for (auto p = startPos; p < endPos; p += samplesPerBlock)
155 {
156 if (getBlockContaining (p) == nullptr)
157 {
158 newBlocks.add (new BufferedBlock (*source, p, samplesPerBlock));
159 break; // just do one block
160 }
161 }
162
163 {
164 const ScopedLock sl (lock);
165 newBlocks.swapWith (blocks);
166 }
167
168 for (int i = blocks.size(); --i >= 0;)
169 newBlocks.removeObject (blocks.getUnchecked(i), false);
170
171 return true;
172}
173
174} // namespace juce
Reads samples from an audio file stream.
bool usesFloatingPointData
Indicates whether the data is floating-point or fixed.
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Reads samples from the stream.
StringPairArray metadataValues
A set of metadata values that the reader has pulled out of the stream.
static void clearSamplesBeyondAvailableLength(int **destChannels, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int &numSamples, int64 fileLengthInSamples)
Used by AudioFormatReader subclasses to clear any parts of the data blocks that lie beyond the end of...
int64 lengthInSamples
The total number of samples in the audio stream.
double sampleRate
The sample-rate of the stream.
unsigned int bitsPerSample
The number of bits per sample, e.g.
unsigned int numChannels
The total number of channels in the audio stream.
bool readSamples(int **destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) override
Subclasses must implement this method to perform the low-level read operation.
BufferingAudioReader(AudioFormatReader *sourceReader, TimeSliceThread &timeSliceThread, int samplesToBuffer)
Creates a reader.
void setReadTimeout(int timeoutMilliseconds) noexcept
Sets a number of milliseconds that the reader can block for in its readSamples() method before giving...
static void JUCE_CALLTYPE clear(float *dest, int numValues) noexcept
Clears a vector of floats.
static void JUCE_CALLTYPE copy(float *dest, const float *src, int numValues) noexcept
Copies a vector of floats.
Automatically locks and unlocks a mutex object.
Automatically unlocks and re-locks a mutex object.
int size() const noexcept
Returns the number of items currently in the array.
ObjectClass * getUnchecked(const int index) const noexcept
Returns a pointer to the object at this index in the array, without checking whether the index is in-...
static void JUCE_CALLTYPE yield()
Yields the current thread's CPU time-slot and allows a new thread to run.
A thread that keeps a list of clients, and calls each one in turn, giving them all a chance to run so...
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
Removes a client from the list.
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
Adds a client to the list.
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).