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