OpenShot Audio Library | OpenShotAudio  0.6.0
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 
26 namespace juce
27 {
28 
30  : input (in), formatName (name)
31 {
32 }
33 
35 {
36  delete input;
37 }
38 
39 static 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 
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 
125 static 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 
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 
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 
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 
283 int64 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 
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 
399 {
400  return AudioChannelSet::canonicalChannelSet (static_cast<int> (numChannels));
401 }
402 
403 //==============================================================================
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;
412  numChannels = reader.numChannels;
415 }
416 
418 {
420 }
421 
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 
443 static 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
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
Type *const * 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 bool readSamples(int *const *destChannels, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples)=0
virtual void readMaxLevels(int64 startSample, int64 numSamples, Range< float > *results, int numChannelsToRead)
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
constexpr ValueType getStart() const noexcept
Definition: juce_Range.h:80
constexpr ValueType getEnd() const noexcept
Definition: juce_Range.h:86
constexpr Range getUnionWith(Range other) const noexcept
Definition: juce_Range.h:246
static Range findMinAndMax(const ValueType *values, Integral numValues) noexcept
Definition: juce_Range.h:279