OpenShot Audio Library | OpenShotAudio: juce_AudioFormatReader.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0

Loading...
Searching...
No Matches
juce_AudioFormatReader.cpp
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
29AudioFormatReader::AudioFormatReader (InputStream* in, const String& name)
30 : input (in), formatName (name)
31{
32}
33
34AudioFormatReader::~AudioFormatReader()
35{
36 delete input;
37}
38
39static void convertFixedToFloat (int* const* channels, int numChannels, int numSamples)
40{
41 constexpr auto scaleFactor = 1.0f / static_cast<float> (0x7fffffff);
42
43 for (int i = 0; i < numChannels; ++i)
44 if (auto d = channels[i])
45 FloatVectorOperations::convertFixedToFloat (reinterpret_cast<float*> (d), d, scaleFactor, numSamples);
46}
47
48 bool AudioFormatReader::read (float* const* destChannels, int numDestChannels,
49 int64 startSampleInSource, int numSamplesToRead)
50{
51 auto channelsAsInt = reinterpret_cast<int* const*> (destChannels);
52
53 if (! read (channelsAsInt, numDestChannels, startSampleInSource, numSamplesToRead, false))
54 return false;
55
56 if (! usesFloatingPointData)
57 convertFixedToFloat (channelsAsInt, numDestChannels, numSamplesToRead);
58
59 return true;
60}
61
62 bool AudioFormatReader::read (int* const* destChannels,
63 int numDestChannels,
64 int64 startSampleInSource,
65 int numSamplesToRead,
66 bool fillLeftoverChannelsWithCopies)
67{
68 jassert (numDestChannels > 0); // you have to actually give this some channels to work with!
69
70 auto originalNumSamplesToRead = (size_t) numSamplesToRead;
71 int startOffsetInDestBuffer = 0;
72
73 if (startSampleInSource < 0)
74 {
75 auto silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead);
76
77 for (int i = numDestChannels; --i >= 0;)
78 if (auto d = destChannels[i])
79 zeromem (d, (size_t) silence * sizeof (int));
80
81 startOffsetInDestBuffer += silence;
82 numSamplesToRead -= silence;
83 startSampleInSource = 0;
84 }
85
86 if (numSamplesToRead <= 0)
87 return true;
88
89 if (! readSamples (destChannels,
90 jmin ((int) numChannels, numDestChannels), startOffsetInDestBuffer,
91 startSampleInSource, numSamplesToRead))
92 return false;
93
94 if (numDestChannels > (int) numChannels)
95 {
96 if (fillLeftoverChannelsWithCopies)
97 {
98 auto lastFullChannel = destChannels[0];
99
100 for (int i = (int) numChannels; --i > 0;)
101 {
102 if (destChannels[i] != nullptr)
103 {
104 lastFullChannel = destChannels[i];
105 break;
106 }
107 }
108
109 if (lastFullChannel != nullptr)
110 for (int i = (int) numChannels; i < numDestChannels; ++i)
111 if (auto d = destChannels[i])
112 memcpy (d, lastFullChannel, sizeof (int) * originalNumSamplesToRead);
113 }
114 else
115 {
116 for (int i = (int) numChannels; i < numDestChannels; ++i)
117 if (auto d = destChannels[i])
118 zeromem (d, sizeof (int) * originalNumSamplesToRead);
119 }
120 }
121
122 return true;
123}
124
125static bool readChannels (AudioFormatReader& reader, int** chans, AudioBuffer<float>* buffer,
126 int startSample, int numSamples, int64 readerStartSample, int numTargetChannels,
127 bool convertToFloat)
128{
129 for (int j = 0; j < numTargetChannels; ++j)
130 chans[j] = reinterpret_cast<int*> (buffer->getWritePointer (j, startSample));
131
132 chans[numTargetChannels] = nullptr;
133
134 const bool success = reader.read (chans, numTargetChannels, readerStartSample, numSamples, true);
135
136 if (convertToFloat)
137 convertFixedToFloat (chans, numTargetChannels, numSamples);
138
139 return success;
140}
141
142 bool AudioFormatReader::read (AudioBuffer<float>* buffer,
143 int startSample,
144 int numSamples,
145 int64 readerStartSample,
146 bool useReaderLeftChan,
147 bool useReaderRightChan)
148{
149 jassert (buffer != nullptr);
150 jassert (startSample >= 0 && startSample + numSamples <= buffer->getNumSamples());
151
152 if (numSamples <= 0)
153 return true;
154
155 auto numTargetChannels = buffer->getNumChannels();
156
157 if (numTargetChannels <= 2)
158 {
159 int* dests[2] = { reinterpret_cast<int*> (buffer->getWritePointer (0, startSample)),
160 reinterpret_cast<int*> (numTargetChannels > 1 ? buffer->getWritePointer (1, startSample) : nullptr) };
161 int* chans[3] = {};
162
163 if (useReaderLeftChan == useReaderRightChan)
164 {
165 chans[0] = dests[0];
166
167 if (numChannels > 1)
168 chans[1] = dests[1];
169 }
170 else if (useReaderLeftChan || (numChannels == 1))
171 {
172 chans[0] = dests[0];
173 }
174 else if (useReaderRightChan)
175 {
176 chans[1] = dests[0];
177 }
178
179 if (! read (chans, 2, readerStartSample, numSamples, true))
180 return false;
181
182 // if the target's stereo and the source is mono, dupe the first channel..
183 if (numTargetChannels > 1
184 && (chans[0] == nullptr || chans[1] == nullptr)
185 && (dests[0] != nullptr && dests[1] != nullptr))
186 {
187 memcpy (dests[1], dests[0], (size_t) numSamples * sizeof (float));
188 }
189
190 if (! usesFloatingPointData)
191 convertFixedToFloat (dests, 2, numSamples);
192
193 return true;
194 }
195
196 if (numTargetChannels <= 64)
197 {
198 int* chans[65];
199 return readChannels (*this, chans, buffer, startSample, numSamples,
200 readerStartSample, numTargetChannels, ! usesFloatingPointData);
201 }
202
203 HeapBlock<int*> chans (numTargetChannels + 1);
204
205 return readChannels (*this, chans, buffer, startSample, numSamples,
206 readerStartSample, numTargetChannels, ! usesFloatingPointData);
207}
208
209 void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
210 Range<float>* const results, const int channelsToRead)
211{
212 jassert (channelsToRead > 0 && channelsToRead <= (int) numChannels);
213
214 if (numSamples <= 0)
215 {
216 for (int i = 0; i < channelsToRead; ++i)
217 results[i] = Range<float>();
218
219 return;
220 }
221
222 auto bufferSize = (int) jmin (numSamples, (int64) 4096);
223 AudioBuffer<float> tempSampleBuffer ((int) channelsToRead, bufferSize);
224
225 auto floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
226 auto intBuffer = reinterpret_cast<int* const*> (floatBuffer);
227 bool isFirstBlock = true;
228
229 while (numSamples > 0)
230 {
231 auto numToDo = (int) jmin (numSamples, (int64) bufferSize);
232
233 if (! read (intBuffer, channelsToRead, startSampleInFile, numToDo, false))
234 break;
235
236 for (int i = 0; i < channelsToRead; ++i)
237 {
238 Range<float> r;
239
240 if (usesFloatingPointData)
241 {
242 r = FloatVectorOperations::findMinAndMax (floatBuffer[i], numToDo);
243 }
244 else
245 {
246 auto intRange = Range<int>::findMinAndMax (intBuffer[i], numToDo);
247
248 r = Range<float> ((float) intRange.getStart() / (float) std::numeric_limits<int>::max(),
249 (float) intRange.getEnd() / (float) std::numeric_limits<int>::max());
250 }
251
252 results[i] = isFirstBlock ? r : results[i].getUnionWith (r);
253 }
254
255 isFirstBlock = false;
256 numSamples -= numToDo;
257 startSampleInFile += numToDo;
258 }
259}
260
261 void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
262 float& lowestLeft, float& highestLeft,
263 float& lowestRight, float& highestRight)
264{
265 Range<float> levels[2];
266
267 if (numChannels < 2)
268 {
269 readMaxLevels (startSampleInFile, numSamples, levels, (int) numChannels);
270 levels[1] = levels[0];
271 }
272 else
273 {
274 readMaxLevels (startSampleInFile, numSamples, levels, 2);
275 }
276
277 lowestLeft = levels[0].getStart();
278 highestLeft = levels[0].getEnd();
279 lowestRight = levels[1].getStart();
280 highestRight = levels[1].getEnd();
281}
282
283int64 AudioFormatReader::searchForLevel (int64 startSample,
284 int64 numSamplesToSearch,
285 double magnitudeRangeMinimum,
286 double magnitudeRangeMaximum,
287 int minimumConsecutiveSamples)
288{
289 if (numSamplesToSearch == 0)
290 return -1;
291
292 const int bufferSize = 4096;
293 HeapBlock<int> tempSpace (bufferSize * 2 + 64);
294
295 int* tempBuffer[3] = { tempSpace.get(),
296 tempSpace.get() + bufferSize,
297 nullptr };
298
299 int consecutive = 0;
300 int64 firstMatchPos = -1;
301
302 jassert (magnitudeRangeMaximum > magnitudeRangeMinimum);
303
304 auto doubleMin = jlimit (0.0, (double) std::numeric_limits<int>::max(), magnitudeRangeMinimum * std::numeric_limits<int>::max());
305 auto doubleMax = jlimit (doubleMin, (double) std::numeric_limits<int>::max(), magnitudeRangeMaximum * std::numeric_limits<int>::max());
306 auto intMagnitudeRangeMinimum = roundToInt (doubleMin);
307 auto intMagnitudeRangeMaximum = roundToInt (doubleMax);
308
309 while (numSamplesToSearch != 0)
310 {
311 auto numThisTime = (int) jmin (std::abs (numSamplesToSearch), (int64) bufferSize);
312 int64 bufferStart = startSample;
313
314 if (numSamplesToSearch < 0)
315 bufferStart -= numThisTime;
316
317 if (bufferStart >= lengthInSamples)
318 break;
319
320 read (tempBuffer, 2, bufferStart, numThisTime, false);
321 auto num = numThisTime;
322
323 while (--num >= 0)
324 {
325 if (numSamplesToSearch < 0)
326 --startSample;
327
328 bool matches = false;
329 auto index = (int) (startSample - bufferStart);
330
331 if (usesFloatingPointData)
332 {
333 const float sample1 = std::abs (((float*) tempBuffer[0]) [index]);
334
335 if (sample1 >= magnitudeRangeMinimum
336 && sample1 <= magnitudeRangeMaximum)
337 {
338 matches = true;
339 }
340 else if (numChannels > 1)
341 {
342 const float sample2 = std::abs (((float*) tempBuffer[1]) [index]);
343
344 matches = (sample2 >= magnitudeRangeMinimum
345 && sample2 <= magnitudeRangeMaximum);
346 }
347 }
348 else
349 {
350 const int sample1 = std::abs (tempBuffer[0] [index]);
351
352 if (sample1 >= intMagnitudeRangeMinimum
353 && sample1 <= intMagnitudeRangeMaximum)
354 {
355 matches = true;
356 }
357 else if (numChannels > 1)
358 {
359 const int sample2 = std::abs (tempBuffer[1][index]);
360
361 matches = (sample2 >= intMagnitudeRangeMinimum
362 && sample2 <= intMagnitudeRangeMaximum);
363 }
364 }
365
366 if (matches)
367 {
368 if (firstMatchPos < 0)
369 firstMatchPos = startSample;
370
371 if (++consecutive >= minimumConsecutiveSamples)
372 {
373 if (firstMatchPos < 0 || firstMatchPos >= lengthInSamples)
374 return -1;
375
376 return firstMatchPos;
377 }
378 }
379 else
380 {
381 consecutive = 0;
382 firstMatchPos = -1;
383 }
384
385 if (numSamplesToSearch > 0)
386 ++startSample;
387 }
388
389 if (numSamplesToSearch > 0)
390 numSamplesToSearch -= numThisTime;
391 else
392 numSamplesToSearch += numThisTime;
393 }
394
395 return -1;
396}
397
398 AudioChannelSet AudioFormatReader::getChannelLayout()
399{
400 return AudioChannelSet::canonicalChannelSet (static_cast<int> (numChannels));
401}
402
403//==============================================================================
404MemoryMappedAudioFormatReader::MemoryMappedAudioFormatReader (const File& f, const AudioFormatReader& reader,
405 int64 start, int64 length, int frameSize)
406 : AudioFormatReader (nullptr, reader.getFormatName()), file (f),
407 dataChunkStart (start), dataLength (length), bytesPerFrame (frameSize)
408{
409 sampleRate = reader.sampleRate;
410 bitsPerSample = reader.bitsPerSample;
411 lengthInSamples = reader.lengthInSamples;
412 numChannels = reader.numChannels;
413 metadataValues = reader.metadataValues;
414 usesFloatingPointData = reader.usesFloatingPointData;
415}
416
417 bool MemoryMappedAudioFormatReader::mapEntireFile()
418{
419 return mapSectionOfFile (Range<int64> (0, lengthInSamples));
420}
421
422 bool MemoryMappedAudioFormatReader::mapSectionOfFile (Range<int64> samplesToMap)
423{
424 if (map == nullptr || samplesToMap != mappedSection)
425 {
426 map.reset();
427
428 const Range<int64> fileRange (sampleToFilePos (samplesToMap.getStart()),
429 sampleToFilePos (samplesToMap.getEnd()));
430
431 map.reset (new MemoryMappedFile (file, fileRange, MemoryMappedFile::readOnly));
432
433 if (map->getData() == nullptr)
434 map.reset();
435 else
436 mappedSection = Range<int64> (jmax ((int64) 0, filePosToSample (map->getRange().getStart() + (bytesPerFrame - 1))),
437 jmin (lengthInSamples, filePosToSample (map->getRange().getEnd())));
438 }
439
440 return map != nullptr;
441}
442
443static int memoryReadDummyVariable; // used to force the compiler not to optimise-away the read operation
444
445 void MemoryMappedAudioFormatReader::touchSample (int64 sample) const noexcept
446{
447 if (map != nullptr && mappedSection.contains (sample))
448 memoryReadDummyVariable += *(char*) sampleToPointer (sample);
449 else
450 jassertfalse; // you must make sure that the window contains all the samples you're going to attempt to read.
451}
452
453} // namespace juce
juce::AudioBuffer
Definition juce_AudioSampleBuffer.h:34
juce::AudioBuffer::getWritePointer
Type * getWritePointer(int channelNumber) noexcept
Definition juce_AudioSampleBuffer.h:291
juce::AudioBuffer::getNumChannels
int getNumChannels() const noexcept
Definition juce_AudioSampleBuffer.h:236
juce::AudioBuffer::getArrayOfWritePointers
Type *const * getArrayOfWritePointers() noexcept
Definition juce_AudioSampleBuffer.h:342
juce::AudioChannelSet
Definition juce_AudioChannelSet.h:47
juce::AudioChannelSet::canonicalChannelSet
static AudioChannelSet JUCE_CALLTYPE canonicalChannelSet(int numChannels)
Definition juce_AudioChannelSet.cpp:616
juce::AudioFormatReader
Definition juce_AudioFormatReader.h:44
juce::AudioFormatReader::input
InputStream * input
Definition juce_AudioFormatReader.h:248
juce::AudioFormatReader::usesFloatingPointData
bool usesFloatingPointData
Definition juce_AudioFormatReader.h:237
juce::AudioFormatReader::read
bool read(float *const *destChannels, int numDestChannels, int64 startSampleInSource, int numSamplesToRead)
Definition juce_AudioFormatReader.cpp:48
juce::AudioFormatReader::searchForLevel
int64 searchForLevel(int64 startSample, int64 numSamplesToSearch, double magnitudeRangeMinimum, double magnitudeRangeMaximum, int minimumConsecutiveSamples)
Definition juce_AudioFormatReader.cpp:283
juce::AudioFormatReader::metadataValues
StringPairArray metadataValues
Definition juce_AudioFormatReader.h:245
juce::AudioFormatReader::~AudioFormatReader
virtual ~AudioFormatReader()
Definition juce_AudioFormatReader.cpp:34
juce::AudioFormatReader::lengthInSamples
int64 lengthInSamples
Definition juce_AudioFormatReader.h:231
juce::AudioFormatReader::sampleRate
double sampleRate
Definition juce_AudioFormatReader.h:225
juce::AudioFormatReader::getChannelLayout
virtual AudioChannelSet getChannelLayout()
Definition juce_AudioFormatReader.cpp:398
juce::AudioFormatReader::AudioFormatReader
AudioFormatReader(InputStream *sourceStream, const String &formatName)
Definition juce_AudioFormatReader.cpp:29
juce::AudioFormatReader::readSamples
virtual bool readSamples(int *const *destChannels, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples)=0
juce::AudioFormatReader::bitsPerSample
unsigned int bitsPerSample
Definition juce_AudioFormatReader.h:228
juce::AudioFormatReader::readMaxLevels
virtual void readMaxLevels(int64 startSample, int64 numSamples, Range< float > *results, int numChannelsToRead)
Definition juce_AudioFormatReader.cpp:209
juce::AudioFormatReader::numChannels
unsigned int numChannels
Definition juce_AudioFormatReader.h:234
juce::File
Definition juce_File.h:45
juce::HeapBlock
Definition juce_HeapBlock.h:87
juce::HeapBlock::get
ElementType * get() const noexcept
Definition juce_HeapBlock.h:185
juce::InputStream
Definition juce_InputStream.h:37
juce::MemoryMappedAudioFormatReader::MemoryMappedAudioFormatReader
MemoryMappedAudioFormatReader(const File &file, const AudioFormatReader &details, int64 dataChunkStart, int64 dataChunkLength, int bytesPerFrame)
Definition juce_AudioFormatReader.cpp:404
juce::MemoryMappedAudioFormatReader::touchSample
void touchSample(int64 sample) const noexcept
Definition juce_AudioFormatReader.cpp:445
juce::MemoryMappedAudioFormatReader::mapEntireFile
bool mapEntireFile()
Definition juce_AudioFormatReader.cpp:417
juce::MemoryMappedAudioFormatReader::sampleToFilePos
int64 sampleToFilePos(int64 sample) const noexcept
Definition juce_MemoryMappedAudioFormatReader.h:92
juce::MemoryMappedAudioFormatReader::mapSectionOfFile
virtual bool mapSectionOfFile(Range< int64 > samplesToMap)
Definition juce_AudioFormatReader.cpp:422
juce::MemoryMappedAudioFormatReader::filePosToSample
int64 filePosToSample(int64 filePos) const noexcept
Definition juce_MemoryMappedAudioFormatReader.h:95
juce::MemoryMappedFile
Definition juce_MemoryMappedFile.h:33
juce::MemoryMappedFile::readOnly
@ readOnly
Definition juce_MemoryMappedFile.h:38
juce::Range
Definition juce_Range.h:40
juce::Range::getStart
constexpr ValueType getStart() const noexcept
Definition juce_Range.h:80
juce::Range::getEnd
constexpr ValueType getEnd() const noexcept
Definition juce_Range.h:86
juce::Range::getUnionWith
constexpr Range getUnionWith(Range other) const noexcept
Definition juce_Range.h:246
juce::Range::findMinAndMax
static Range findMinAndMax(const ValueType *values, Integral numValues) noexcept
Definition juce_Range.h:279
juce::String
Definition juce_String.h:53