LMMS
Loading...
Searching...
No Matches
juce_BufferingAudioFormatReader.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
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 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30 TimeSliceThread& timeSliceThread,
31 int samplesToBuffer)
32 : AudioFormatReader (nullptr, sourceReader->getFormatName()),
33 source (sourceReader), thread (timeSliceThread),
34 numBlocks (1 + (samplesToBuffer / samplesPerBlock))
35{
36 sampleRate = source->sampleRate;
37 lengthInSamples = source->lengthInSamples;
38 numChannels = source->numChannels;
39 metadataValues = source->metadataValues;
40 bitsPerSample = 32;
42
43 timeSliceThread.addTimeSliceClient (this);
44}
45
47{
48 thread.removeTimeSliceClient (this);
49}
50
51void BufferingAudioReader::setReadTimeout (int timeoutMilliseconds) noexcept
52{
53 timeoutMs = timeoutMilliseconds;
54}
55
56bool BufferingAudioReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
57 int64 startSampleInFile, int numSamples)
58{
59 auto startTime = Time::getMillisecondCounter();
60 clearSamplesBeyondAvailableLength (destSamples, numDestChannels, startOffsetInDestBuffer,
61 startSampleInFile, numSamples, lengthInSamples);
62
63 const ScopedLock sl (lock);
64 nextReadPosition = startSampleInFile;
65
66 bool allSamplesRead = true;
67
68 while (numSamples > 0)
69 {
70 if (auto block = getBlockContaining (startSampleInFile))
71 {
72 auto offset = (int) (startSampleInFile - block->range.getStart());
73 auto numToDo = jmin (numSamples, (int) (block->range.getEnd() - startSampleInFile));
74
75 for (int j = 0; j < numDestChannels; ++j)
76 {
77 if (auto* dest = (float*) destSamples[j])
78 {
79 dest += startOffsetInDestBuffer;
80
81 if (j < (int) numChannels)
82 FloatVectorOperations::copy (dest, block->buffer.getReadPointer (j, offset), numToDo);
83 else
84 FloatVectorOperations::clear (dest, numToDo);
85 }
86 }
87
88 startOffsetInDestBuffer += numToDo;
89 startSampleInFile += numToDo;
90 numSamples -= numToDo;
91
92 allSamplesRead = allSamplesRead && block->allSamplesRead;
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 allSamplesRead = false;
103 break;
104 }
105 else
106 {
107 ScopedUnlock ul (lock);
109 }
110 }
111 }
112
113 return allSamplesRead;
114}
115
117 : range (pos, pos + numSamples),
118 buffer ((int) reader.numChannels, numSamples),
119 allSamplesRead (reader.read (&buffer, 0, numSamples, pos, true, true))
120{
121}
122
124{
125 for (auto* b : blocks)
126 if (b->range.contains (pos))
127 return b;
128
129 return nullptr;
130}
131
133{
134 return readNextBufferChunk() ? 1 : 100;
135}
136
138{
139 auto pos = (nextReadPosition.load() / samplesPerBlock) * samplesPerBlock;
140 auto endPos = jmin (lengthInSamples, pos + numBlocks * samplesPerBlock);
141
143
144 for (int i = blocks.size(); --i >= 0;)
145 if (blocks.getUnchecked (i)->range.intersects (Range<int64> (pos, 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 = pos; 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
175//==============================================================================
176//==============================================================================
177#if JUCE_UNIT_TESTS
178
179static bool operator== (const AudioBuffer<float>& a, const AudioBuffer<float>& b)
180{
181 if (a.getNumChannels() != b.getNumChannels() || a.getNumSamples() != b.getNumSamples())
182 return false;
183
184 for (int channel = 0; channel < a.getNumChannels(); ++channel)
185 {
186 auto* aPtr = a.getReadPointer (channel);
187 auto* bPtr = b.getReadPointer (channel);
188
189 if (std::vector<float> (aPtr, aPtr + a.getNumSamples())
190 != std::vector<float> (bPtr, bPtr + b.getNumSamples()))
191 {
192 return false;
193 }
194 }
195
196 return true;
197}
198
199static bool isSilent (const AudioBuffer<float>& b)
200{
201 for (int channel = 0; channel < b.getNumChannels(); ++channel)
202 if (b.findMinMax (channel, 0, b.getNumSamples()) != Range<float>{})
203 return false;
204
205 return true;
206}
207
208struct TestAudioFormatReader : public AudioFormatReader
209{
210 explicit TestAudioFormatReader (AudioBuffer<float>& b)
211 : AudioFormatReader (nullptr, {}),
212 buffer (b)
213 {
214 sampleRate = 44100.0f;
215 bitsPerSample = 32;
216 usesFloatingPointData = true;
217 lengthInSamples = buffer.getNumSamples();
218 numChannels = (unsigned int) buffer.getNumChannels();
219 }
220
221 bool readSamples (int** destChannels, int numDestChannels, int startOffsetInDestBuffer,
222 int64 startSampleInFile, int numSamples) override
223 {
224 clearSamplesBeyondAvailableLength (destChannels, numDestChannels, startOffsetInDestBuffer,
225 startSampleInFile, numSamples, lengthInSamples);
226
227 for (int j = 0; j < numDestChannels; ++j)
228 {
229 static_assert (sizeof (int) == sizeof (float),
230 "Int and float size must match in order for pointer arithmetic to work correctly");
231
232 if (auto* dest = reinterpret_cast<float*> (destChannels[j]))
233 {
234 dest += startOffsetInDestBuffer;
235
236 if (j < (int) numChannels)
237 FloatVectorOperations::copy (dest, buffer.getReadPointer (j, (int) startSampleInFile), numSamples);
238 else
239 FloatVectorOperations::clear (dest, numSamples);
240 }
241 }
242
243 return true;
244 }
245
246 const AudioBuffer<float>& buffer;
247};
248
249class BufferingAudioReaderTests : public UnitTest
250{
251public:
252 BufferingAudioReaderTests() : UnitTest ("BufferingAudioReader", UnitTestCategories::audio) {}
253
254 void runTest() override
255 {
256 TimeSliceThread timeSlice ("TestBackgroundThread");
257 timeSlice.startThread (5);
258
259 beginTest ("Timeout");
260 {
261 struct BlockingReader : public AudioFormatReader
262 {
263 BlockingReader()
264 : AudioFormatReader (nullptr, {})
265 {
266 sampleRate = 44100.0f;
267 bitsPerSample = 32;
268 usesFloatingPointData = true;
269 lengthInSamples = 1024;
270 numChannels = 2;
271 }
272
273 bool readSamples (int**, int, int, int64, int) override
274 {
275 Thread::sleep (100);
276 return true;
277 }
278 };
279
280 BufferingAudioReader bufferingReader (new BlockingReader(), timeSlice, 64);
281 bufferingReader.setReadTimeout (10);
282
283 AudioBuffer<float> readBuffer { 2, 1024 };
284
285 readBuffer.clear();
286 read (bufferingReader, readBuffer);
287
288 expect (isSilent (readBuffer));
289 }
290
291 beginTest ("Read samples");
292 {
293 for (auto i = 4; i < 18; ++i)
294 {
295 const auto backgroundBufferSize = 1 << i;
296 auto buffer = generateTestBuffer (backgroundBufferSize);
297
298 BufferingAudioReader bufferingReader (new TestAudioFormatReader (buffer), timeSlice, backgroundBufferSize);
299 bufferingReader.setReadTimeout (-1);
300
301 AudioBuffer<float> readBuffer { buffer.getNumChannels(), buffer.getNumSamples() };
302 read (bufferingReader, readBuffer);
303
304 expect (buffer == readBuffer);
305 }
306 }
307 }
308
309private:
310 AudioBuffer<float> generateTestBuffer (int bufferSize) const
311 {
312 auto random = getRandom();
313
314 AudioBuffer<float> buffer { 2, random.nextInt ({ bufferSize, bufferSize * 10 }) };
315
316 for (int channel = 0; channel < buffer.getNumChannels(); ++channel)
317 for (int sample = 0; sample < buffer.getNumSamples(); ++sample)
318 buffer.setSample (channel, sample, random.nextFloat());
319
320 return buffer;
321 }
322
323 void read (BufferingAudioReader& reader, AudioBuffer<float>& readBuffer)
324 {
325 constexpr int blockSize = 1024;
326
327 const auto numSamples = readBuffer.getNumSamples();
328 int readPos = 0;
329
330 for (;;)
331 {
332 reader.read (&readBuffer, readPos, jmin (blockSize, numSamples - readPos), readPos, true, true);
333
334 readPos += blockSize;
335
336 if (readPos >= numSamples)
337 break;
338 }
339 }
340};
341
342static BufferingAudioReaderTests bufferingAudioReaderTests;
343
344#endif
345
346} // namespace juce
Type jmin(const Type a, const Type b)
Definition MathsFunctions.h:60
#define nullptr
Definition DistrhoDefines.h:75
uint8_t a
Definition Spc_Cpu.h:141
int64_t int64
Definition basics.h:91
Definition juce_AudioSampleBuffer.h:34
bool usesFloatingPointData
Definition juce_AudioFormatReader.h:237
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Definition juce_AudioFormatReader.cpp:48
StringPairArray metadataValues
Definition juce_AudioFormatReader.h:245
const String & getFormatName() const noexcept
Definition juce_AudioFormatReader.h:68
static void clearSamplesBeyondAvailableLength(int **destChannels, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int &numSamples, int64 fileLengthInSamples)
Definition juce_AudioFormatReader.h:309
int64 lengthInSamples
Definition juce_AudioFormatReader.h:231
double sampleRate
Definition juce_AudioFormatReader.h:225
AudioFormatReader(InputStream *sourceStream, const String &formatName)
Definition juce_AudioFormatReader.cpp:29
unsigned int bitsPerSample
Definition juce_AudioFormatReader.h:228
unsigned int numChannels
Definition juce_AudioFormatReader.h:234
bool readSamples(int **destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) override
Definition juce_BufferingAudioFormatReader.cpp:56
CriticalSection lock
Definition juce_BufferingAudioFormatReader.h:91
static constexpr int samplesPerBlock
Definition juce_BufferingAudioFormatReader.h:83
BufferingAudioReader(AudioFormatReader *sourceReader, TimeSliceThread &timeSliceThread, int samplesToBuffer)
Definition juce_BufferingAudioFormatReader.cpp:29
TimeSliceThread & thread
Definition juce_BufferingAudioFormatReader.h:86
std::atomic< int64 > nextReadPosition
Definition juce_BufferingAudioFormatReader.h:87
OwnedArray< BufferedBlock > blocks
Definition juce_BufferingAudioFormatReader.h:92
int timeoutMs
Definition juce_BufferingAudioFormatReader.h:89
BufferedBlock * getBlockContaining(int64 pos) const noexcept
Definition juce_BufferingAudioFormatReader.cpp:123
void setReadTimeout(int timeoutMilliseconds) noexcept
Definition juce_BufferingAudioFormatReader.cpp:51
const int numBlocks
Definition juce_BufferingAudioFormatReader.h:88
std::unique_ptr< AudioFormatReader > source
Definition juce_BufferingAudioFormatReader.h:85
bool readNextBufferChunk()
Definition juce_BufferingAudioFormatReader.cpp:137
int useTimeSlice() override
Definition juce_BufferingAudioFormatReader.cpp:132
~BufferingAudioReader() override
Definition juce_BufferingAudioFormatReader.cpp:46
Definition juce_OwnedArray.h:51
int size() const noexcept
Definition juce_OwnedArray.h:130
void swapWith(OtherArrayType &otherArray) noexcept
Definition juce_OwnedArray.h:762
void clear(bool deleteObjects=true)
Definition juce_OwnedArray.h:107
ObjectClass * add(ObjectClass *newObject)
Definition juce_OwnedArray.h:294
void removeObject(const ObjectClass *objectToRemove, bool deleteObject=true)
Definition juce_OwnedArray.h:655
Definition juce_Range.h:40
static void JUCE_CALLTYPE yield()
Definition juce_posix_SharedCode.h:1033
static uint32 getMillisecondCounter() noexcept
Definition juce_Time.cpp:241
friend class TimeSliceThread
Definition juce_TimeSliceThread.h:68
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
Definition juce_TimeSliceThread.cpp:36
register unsigned j
Definition inflate.c:1576
register unsigned i
Definition inflate.c:1575
JOCTET * buffer
Definition juce_JPEGLoader.cpp:302
Definition carla_juce.cpp:31
CriticalSection::ScopedLockType ScopedLock
Definition juce_CriticalSection.h:186
unsigned int uint32
Definition juce_MathsFunctions.h:45
long long int64
Definition juce_MathsFunctions.h:54
CriticalSection::ScopedUnlockType ScopedUnlock
Definition juce_CriticalSection.h:226
bool isSilent(const SampleFrame *src, int frames)
Definition MixHelpers.cpp:72
#define true
Definition ordinals.h:82
Definition juce_BufferingAudioFormatReader.h:71
BufferedBlock(AudioFormatReader &reader, int64 pos, int numSamples)
Definition juce_BufferingAudioFormatReader.cpp:116
AudioBuffer< float > buffer
Definition juce_BufferingAudioFormatReader.h:75
Range< int64 > range
Definition juce_BufferingAudioFormatReader.h:74
bool allSamplesRead
Definition juce_BufferingAudioFormatReader.h:76
signed int sample
Definition tap_dynamics_m.c:41
uch * p
Definition crypt.c:594
b
Definition crypt.c:628
read(f, &c, 1)
typedef int(UZ_EXP MsgFn)()