46BufferingAudioReader::~BufferingAudioReader()
66 bool allSamplesRead =
true;
68 while (numSamples > 0)
82 FloatVectorOperations::copy (dest,
block->buffer.getReadPointer (
j, offset),
numToDo);
84 FloatVectorOperations::clear (dest,
numToDo);
92 allSamplesRead = allSamplesRead &&
block->allSamplesRead;
102 allSamplesRead =
false;
113 return allSamplesRead;
117 : range (pos, pos + numSamples),
118 buffer ((
int) reader.numChannels, numSamples),
119 allSamplesRead (reader.
read (&buffer, 0, numSamples, pos,
true,
true))
123BufferingAudioReader::BufferedBlock* BufferingAudioReader::getBlockContaining (
int64 pos)
const noexcept
125 for (
auto* b : blocks)
126 if (b->range.contains (pos))
132int BufferingAudioReader::useTimeSlice()
134 return readNextBufferChunk() ? 1 : 100;
137bool BufferingAudioReader::readNextBufferChunk()
139 auto pos = (nextReadPosition.
load() / samplesPerBlock) * samplesPerBlock;
144 for (
int i = blocks.
size(); --i >= 0;)
145 if (blocks.
getUnchecked (i)->range.intersects (Range<int64> (pos, endPos)))
154 for (
auto p = pos; p < endPos; p += samplesPerBlock)
156 if (getBlockContaining (p) ==
nullptr)
158 newBlocks.add (
new BufferedBlock (*source, p, samplesPerBlock));
168 for (
int i = blocks.
size(); --i >= 0;)
179static bool isSilent (
const AudioBuffer<float>& b)
181 for (
int channel = 0; channel < b.getNumChannels(); ++channel)
182 if (b.findMinMax (channel, 0, b.getNumSamples()) != Range<float>{})
191 : AudioFormatReader (
nullptr, {}),
195 sampleRate = 44100.0f;
197 usesFloatingPointData =
true;
198 lengthInSamples = buffer->getNumSamples();
199 numChannels = (
unsigned int) buffer->getNumChannels();
213 static_assert (
sizeof (
int) ==
sizeof (
float),
214 "Int and float size must match in order for pointer arithmetic to work correctly");
216 if (
auto* dest =
reinterpret_cast<float*
> (destChannels[
j]))
220 if (
j < (
int) numChannels)
221 FloatVectorOperations::copy (dest, buffer->getReadPointer (
j, (
int)
startSampleInFile), numSamples);
223 FloatVectorOperations::clear (dest, numSamples);
230 const AudioBuffer<float>* buffer;
235 AudioBuffer<float> buffer { 2, bufferSize };
237 for (
int channel = 0; channel < buffer.getNumChannels(); ++channel)
238 for (
int sample = 0;
sample < buffer.getNumSamples(); ++
sample)
239 buffer.setSample (channel, sample,
random.nextFloat());
249 void runTest()
override
251 TimeSliceThread thread (
"TestBackgroundThread");
254 beginTest (
"Reading samples from a blocked reader should produce silence");
258 explicit BlockingReader (
const AudioBuffer<float>* b)
259 : TestAudioFormatReader (b)
263 bool readSamples (
int*
const* destChannels,
265 int startOffsetInDestBuffer,
266 int64 startSampleInFile,
267 int numSamples)
override
270 return TestAudioFormatReader::readSamples (destChannels, numDestChannels, startOffsetInDestBuffer, startSampleInFile, numSamples);
273 WaitableEvent unblock;
276 Random
random { getRandom() };
277 constexpr auto bufferSize = 1024;
288 read (reader, destination);
294 beginTest (
"Reading samples from a reader should produce the same samples as its source");
296 Random
random { getRandom() };
298 for (
auto i = 4; i < 18; ++i)
300 const auto bufferSize = 1 << i;
305 reader.setReadTimeout (-1);
309 expect (source != destination);
311 read (reader, destination);
312 expect (source == destination);
318 void read (BufferingAudioReader& reader, AudioBuffer<float>&
readBuffer)
320 constexpr int blockSize = 1024;
322 const auto numSamples =
readBuffer.getNumSamples();
327 reader.read (&
readBuffer, readPos,
jmin (blockSize, numSamples - readPos), readPos,
true,
true);
329 readPos += blockSize;
331 if (readPos >= numSamples)
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...
bool readSamples(int *const *destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) override
Subclasses must implement this method to perform the low-level read operation.
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(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).
CriticalSection::ScopedLockType ScopedLock
Automatically locks and unlocks a CriticalSection object.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.