OpenShot Library | libopenshot-audio  0.2.0
juce_FlacAudioFormat.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 
27 namespace juce
28 {
29 
30 #if JUCE_USE_FLAC
31 
32 }
33 
34 #if defined _WIN32 && !defined __CYGWIN__
35  #include <io.h>
36 #else
37  #include <unistd.h>
38 #endif
39 
40 #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
41  #include <sys/types.h> /* for off_t */
42 #endif
43 
44 #if HAVE_INTTYPES_H
45  #define __STDC_FORMAT_MACROS
46  #include <inttypes.h>
47 #endif
48 
49 #if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__
50  #include <io.h> /* for _setmode(), chmod() */
51  #include <fcntl.h> /* for _O_BINARY */
52 #else
53  #include <unistd.h> /* for chown(), unlink() */
54 #endif
55 
56 #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
57  #if defined __BORLANDC__
58  #include <utime.h> /* for utime() */
59  #else
60  #include <sys/utime.h> /* for utime() */
61  #endif
62 #else
63  #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
64  #include <utime.h> /* for utime() */
65 #endif
66 
67 #if defined _MSC_VER
68  #if _MSC_VER >= 1600
69  #include <stdint.h>
70  #else
71  #include <limits.h>
72  #endif
73 #endif
74 
75 #ifdef _WIN32
76  #include <stdio.h>
77  #include <sys/stat.h>
78  #include <stdarg.h>
79  #include <windows.h>
80 #endif
81 
82 #ifdef DEBUG
83  #include <assert.h>
84 #endif
85 
86 #include <stdlib.h>
87 #include <stdio.h>
88 
89 namespace juce
90 {
91 
92 namespace FlacNamespace
93 {
94 #if JUCE_INCLUDE_FLAC_CODE || ! defined (JUCE_INCLUDE_FLAC_CODE)
95 
96  #undef VERSION
97  #define VERSION "1.3.1"
98 
99  #define FLAC__NO_DLL 1
100 
101  #if JUCE_MSVC
102  #pragma warning (disable: 4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4312 4505 4365 4005 4334 181 111)
103  #else
104  #define HAVE_LROUND 1
105  #endif
106 
107  #if JUCE_MAC
108  #define FLAC__SYS_DARWIN 1
109  #endif
110 
111  #ifndef SIZE_MAX
112  #define SIZE_MAX 0xffffffff
113  #endif
114 
115  #if JUCE_CLANG
116  #pragma clang diagnostic push
117  #pragma clang diagnostic ignored "-Wconversion"
118  #pragma clang diagnostic ignored "-Wshadow"
119  #pragma clang diagnostic ignored "-Wdeprecated-register"
120  #if __has_warning("-Wzero-as-null-pointer-constant")
121  #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
122  #endif
123  #endif
124 
125  #if JUCE_INTEL
126  #if JUCE_32BIT
127  #define FLAC__CPU_IA32 1
128  #endif
129  #if JUCE_64BIT
130  #define FLAC__CPU_X86_64 1
131  #endif
132  #define FLAC__HAS_X86INTRIN 1
133  #endif
134 
135  #undef __STDC_LIMIT_MACROS
136  #define __STDC_LIMIT_MACROS 1
137  #define flac_max jmax
138  #define flac_min jmin
139  #undef DEBUG // (some flac code dumps debug trace if the app defines this macro)
140  #include "flac/all.h"
141  #include "flac/libFLAC/bitmath.c"
142  #include "flac/libFLAC/bitreader.c"
143  #include "flac/libFLAC/bitwriter.c"
144  #include "flac/libFLAC/cpu.c"
145  #include "flac/libFLAC/crc.c"
146  #include "flac/libFLAC/fixed.c"
147  #include "flac/libFLAC/float.c"
148  #include "flac/libFLAC/format.c"
149  #include "flac/libFLAC/lpc_flac.c"
150  #include "flac/libFLAC/md5.c"
151  #include "flac/libFLAC/memory.c"
152  #include "flac/libFLAC/stream_decoder.c"
153  #include "flac/libFLAC/stream_encoder.c"
154  #include "flac/libFLAC/stream_encoder_framing.c"
155  #include "flac/libFLAC/window_flac.c"
156  #undef VERSION
157 #else
158  #include <FLAC/all.h>
159 #endif
160 
161  #if JUCE_CLANG
162  #pragma clang diagnostic pop
163  #endif
164 }
165 
166 #undef max
167 #undef min
168 
169 //==============================================================================
170 static const char* const flacFormatName = "FLAC file";
171 
172 
173 //==============================================================================
174 class FlacReader : public AudioFormatReader
175 {
176 public:
177  FlacReader (InputStream* in) : AudioFormatReader (in, flacFormatName)
178  {
179  lengthInSamples = 0;
180  decoder = FlacNamespace::FLAC__stream_decoder_new();
181 
182  ok = FLAC__stream_decoder_init_stream (decoder,
183  readCallback_, seekCallback_, tellCallback_, lengthCallback_,
184  eofCallback_, writeCallback_, metadataCallback_, errorCallback_,
185  this) == FlacNamespace::FLAC__STREAM_DECODER_INIT_STATUS_OK;
186 
187  if (ok)
188  {
189  FLAC__stream_decoder_process_until_end_of_metadata (decoder);
190 
191  if (lengthInSamples == 0 && sampleRate > 0)
192  {
193  // the length hasn't been stored in the metadata, so we'll need to
194  // work it out the length the hard way, by scanning the whole file..
195  scanningForLength = true;
196  FLAC__stream_decoder_process_until_end_of_stream (decoder);
197  scanningForLength = false;
198  auto tempLength = lengthInSamples;
199 
200  FLAC__stream_decoder_reset (decoder);
201  FLAC__stream_decoder_process_until_end_of_metadata (decoder);
202  lengthInSamples = tempLength;
203  }
204  }
205  }
206 
207  ~FlacReader() override
208  {
209  FlacNamespace::FLAC__stream_decoder_delete (decoder);
210  }
211 
212  void useMetadata (const FlacNamespace::FLAC__StreamMetadata_StreamInfo& info)
213  {
214  sampleRate = info.sample_rate;
215  bitsPerSample = info.bits_per_sample;
216  lengthInSamples = (unsigned int) info.total_samples;
217  numChannels = info.channels;
218 
219  reservoir.setSize ((int) numChannels, 2 * (int) info.max_blocksize, false, false, true);
220  }
221 
222  // returns the number of samples read
223  bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer,
224  int64 startSampleInFile, int numSamples) override
225  {
226  if (! ok)
227  return false;
228 
229  while (numSamples > 0)
230  {
231  if (startSampleInFile >= reservoirStart
232  && startSampleInFile < reservoirStart + samplesInReservoir)
233  {
234  auto num = (int) jmin ((int64) numSamples,
235  reservoirStart + samplesInReservoir - startSampleInFile);
236 
237  jassert (num > 0);
238 
239  for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
240  if (destSamples[i] != nullptr)
241  memcpy (destSamples[i] + startOffsetInDestBuffer,
242  reservoir.getReadPointer (i, (int) (startSampleInFile - reservoirStart)),
243  sizeof (int) * (size_t) num);
244 
245  startOffsetInDestBuffer += num;
246  startSampleInFile += num;
247  numSamples -= num;
248  }
249  else
250  {
251  if (startSampleInFile >= lengthInSamples)
252  {
253  samplesInReservoir = 0;
254  }
255  else if (startSampleInFile < reservoirStart
256  || startSampleInFile > reservoirStart + jmax (samplesInReservoir, 511))
257  {
258  // had some problems with flac crashing if the read pos is aligned more
259  // accurately than this. Probably fixed in newer versions of the library, though.
260  reservoirStart = (int) (startSampleInFile & ~511);
261  samplesInReservoir = 0;
262  FLAC__stream_decoder_seek_absolute (decoder, (FlacNamespace::FLAC__uint64) reservoirStart);
263  }
264  else
265  {
266  reservoirStart += samplesInReservoir;
267  samplesInReservoir = 0;
268  FLAC__stream_decoder_process_single (decoder);
269  }
270 
271  if (samplesInReservoir == 0)
272  break;
273  }
274  }
275 
276  if (numSamples > 0)
277  {
278  for (int i = numDestChannels; --i >= 0;)
279  if (destSamples[i] != nullptr)
280  zeromem (destSamples[i] + startOffsetInDestBuffer, sizeof (int) * (size_t) numSamples);
281  }
282 
283  return true;
284  }
285 
286  void useSamples (const FlacNamespace::FLAC__int32* const buffer[], int numSamples)
287  {
288  if (scanningForLength)
289  {
290  lengthInSamples += numSamples;
291  }
292  else
293  {
294  if (numSamples > reservoir.getNumSamples())
295  reservoir.setSize ((int) numChannels, numSamples, false, false, true);
296 
297  auto bitsToShift = 32 - bitsPerSample;
298 
299  for (int i = 0; i < (int) numChannels; ++i)
300  {
301  auto* src = buffer[i];
302  int n = i;
303 
304  while (src == nullptr && n > 0)
305  src = buffer [--n];
306 
307  if (src != nullptr)
308  {
309  auto* dest = reinterpret_cast<int*> (reservoir.getWritePointer(i));
310 
311  for (int j = 0; j < numSamples; ++j)
312  dest[j] = src[j] << bitsToShift;
313  }
314  }
315 
316  samplesInReservoir = numSamples;
317  }
318  }
319 
320  //==============================================================================
321  static FlacNamespace::FLAC__StreamDecoderReadStatus readCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__byte buffer[], size_t* bytes, void* client_data)
322  {
323  *bytes = (size_t) static_cast<const FlacReader*> (client_data)->input->read (buffer, (int) *bytes);
324  return FlacNamespace::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
325  }
326 
327  static FlacNamespace::FLAC__StreamDecoderSeekStatus seekCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64 absolute_byte_offset, void* client_data)
328  {
329  static_cast<const FlacReader*> (client_data)->input->setPosition ((int) absolute_byte_offset);
330  return FlacNamespace::FLAC__STREAM_DECODER_SEEK_STATUS_OK;
331  }
332 
333  static FlacNamespace::FLAC__StreamDecoderTellStatus tellCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
334  {
335  *absolute_byte_offset = (uint64) static_cast<const FlacReader*> (client_data)->input->getPosition();
336  return FlacNamespace::FLAC__STREAM_DECODER_TELL_STATUS_OK;
337  }
338 
339  static FlacNamespace::FLAC__StreamDecoderLengthStatus lengthCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* stream_length, void* client_data)
340  {
341  *stream_length = (uint64) static_cast<const FlacReader*> (client_data)->input->getTotalLength();
342  return FlacNamespace::FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
343  }
344 
345  static FlacNamespace::FLAC__bool eofCallback_ (const FlacNamespace::FLAC__StreamDecoder*, void* client_data)
346  {
347  return static_cast<const FlacReader*> (client_data)->input->isExhausted();
348  }
349 
350  static FlacNamespace::FLAC__StreamDecoderWriteStatus writeCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
351  const FlacNamespace::FLAC__Frame* frame,
352  const FlacNamespace::FLAC__int32* const buffer[],
353  void* client_data)
354  {
355  static_cast<FlacReader*> (client_data)->useSamples (buffer, (int) frame->header.blocksize);
356  return FlacNamespace::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
357  }
358 
359  static void metadataCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
360  const FlacNamespace::FLAC__StreamMetadata* metadata,
361  void* client_data)
362  {
363  static_cast<FlacReader*> (client_data)->useMetadata (metadata->data.stream_info);
364  }
365 
366  static void errorCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__StreamDecoderErrorStatus, void*)
367  {
368  }
369 
370 private:
371  FlacNamespace::FLAC__StreamDecoder* decoder;
372  AudioBuffer<float> reservoir;
373  int reservoirStart = 0, samplesInReservoir = 0;
374  bool ok = false, scanningForLength = false;
375 
376  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacReader)
377 };
378 
379 
380 //==============================================================================
381 class FlacWriter : public AudioFormatWriter
382 {
383 public:
384  FlacWriter (OutputStream* out, double rate, uint32 numChans, uint32 bits, int qualityOptionIndex)
385  : AudioFormatWriter (out, flacFormatName, rate, numChans, bits),
386  streamStartPos (output != nullptr ? jmax (output->getPosition(), 0ll) : 0ll)
387  {
388  encoder = FlacNamespace::FLAC__stream_encoder_new();
389 
390  if (qualityOptionIndex > 0)
391  FLAC__stream_encoder_set_compression_level (encoder, (uint32) jmin (8, qualityOptionIndex));
392 
393  FLAC__stream_encoder_set_do_mid_side_stereo (encoder, numChannels == 2);
394  FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, numChannels == 2);
395  FLAC__stream_encoder_set_channels (encoder, numChannels);
396  FLAC__stream_encoder_set_bits_per_sample (encoder, jmin ((unsigned int) 24, bitsPerSample));
397  FLAC__stream_encoder_set_sample_rate (encoder, (unsigned int) sampleRate);
398  FLAC__stream_encoder_set_blocksize (encoder, 0);
399  FLAC__stream_encoder_set_do_escape_coding (encoder, true);
400 
401  ok = FLAC__stream_encoder_init_stream (encoder,
402  encodeWriteCallback, encodeSeekCallback,
403  encodeTellCallback, encodeMetadataCallback,
404  this) == FlacNamespace::FLAC__STREAM_ENCODER_INIT_STATUS_OK;
405  }
406 
407  ~FlacWriter() override
408  {
409  if (ok)
410  {
411  FlacNamespace::FLAC__stream_encoder_finish (encoder);
412  output->flush();
413  }
414  else
415  {
416  output = nullptr; // to stop the base class deleting this, as it needs to be returned
417  // to the caller of createWriter()
418  }
419 
420  FlacNamespace::FLAC__stream_encoder_delete (encoder);
421  }
422 
423  //==============================================================================
424  bool write (const int** samplesToWrite, int numSamples) override
425  {
426  if (! ok)
427  return false;
428 
429  HeapBlock<int*> channels;
430  HeapBlock<int> temp;
431  auto bitsToShift = 32 - (int) bitsPerSample;
432 
433  if (bitsToShift > 0)
434  {
435  temp.malloc (numChannels * (size_t) numSamples);
436  channels.calloc (numChannels + 1);
437 
438  for (unsigned int i = 0; i < numChannels; ++i)
439  {
440  if (samplesToWrite[i] == nullptr)
441  break;
442 
443  auto* destData = temp.get() + i * (size_t) numSamples;
444  channels[i] = destData;
445 
446  for (int j = 0; j < numSamples; ++j)
447  destData[j] = (samplesToWrite[i][j] >> bitsToShift);
448  }
449 
450  samplesToWrite = const_cast<const int**> (channels.get());
451  }
452 
453  return FLAC__stream_encoder_process (encoder, (const FlacNamespace::FLAC__int32**) samplesToWrite, (unsigned) numSamples) != 0;
454  }
455 
456  bool writeData (const void* const data, const int size) const
457  {
458  return output->write (data, (size_t) size);
459  }
460 
461  static void packUint32 (FlacNamespace::FLAC__uint32 val, FlacNamespace::FLAC__byte* b, const int bytes)
462  {
463  b += bytes;
464 
465  for (int i = 0; i < bytes; ++i)
466  {
467  *(--b) = (FlacNamespace::FLAC__byte) (val & 0xff);
468  val >>= 8;
469  }
470  }
471 
472  void writeMetaData (const FlacNamespace::FLAC__StreamMetadata* metadata)
473  {
474  using namespace FlacNamespace;
475  auto& info = metadata->data.stream_info;
476 
477  unsigned char buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
478  const unsigned int channelsMinus1 = info.channels - 1;
479  const unsigned int bitsMinus1 = info.bits_per_sample - 1;
480 
481  packUint32 (info.min_blocksize, buffer, 2);
482  packUint32 (info.max_blocksize, buffer + 2, 2);
483  packUint32 (info.min_framesize, buffer + 4, 3);
484  packUint32 (info.max_framesize, buffer + 7, 3);
485  buffer[10] = (uint8) ((info.sample_rate >> 12) & 0xff);
486  buffer[11] = (uint8) ((info.sample_rate >> 4) & 0xff);
487  buffer[12] = (uint8) (((info.sample_rate & 0x0f) << 4) | (channelsMinus1 << 1) | (bitsMinus1 >> 4));
488  buffer[13] = (FLAC__byte) (((bitsMinus1 & 0x0f) << 4) | (unsigned int) ((info.total_samples >> 32) & 0x0f));
489  packUint32 ((FLAC__uint32) info.total_samples, buffer + 14, 4);
490  memcpy (buffer + 18, info.md5sum, 16);
491 
492  const bool seekOk = output->setPosition (streamStartPos + 4);
493  ignoreUnused (seekOk);
494 
495  // if this fails, you've given it an output stream that can't seek! It needs
496  // to be able to seek back to write the header
497  jassert (seekOk);
498 
499  output->writeIntBigEndian (FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
500  output->write (buffer, FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
501  }
502 
503  //==============================================================================
504  static FlacNamespace::FLAC__StreamEncoderWriteStatus encodeWriteCallback (const FlacNamespace::FLAC__StreamEncoder*,
505  const FlacNamespace::FLAC__byte buffer[],
506  size_t bytes,
507  unsigned int /*samples*/,
508  unsigned int /*current_frame*/,
509  void* client_data)
510  {
511  return static_cast<FlacWriter*> (client_data)->writeData (buffer, (int) bytes)
512  ? FlacNamespace::FLAC__STREAM_ENCODER_WRITE_STATUS_OK
513  : FlacNamespace::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
514  }
515 
516  static FlacNamespace::FLAC__StreamEncoderSeekStatus encodeSeekCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64, void*)
517  {
518  return FlacNamespace::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
519  }
520 
521  static FlacNamespace::FLAC__StreamEncoderTellStatus encodeTellCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
522  {
523  if (client_data == nullptr)
524  return FlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
525 
526  *absolute_byte_offset = (FlacNamespace::FLAC__uint64) static_cast<FlacWriter*> (client_data)->output->getPosition();
527  return FlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_OK;
528  }
529 
530  static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder*, const FlacNamespace::FLAC__StreamMetadata* metadata, void* client_data)
531  {
532  static_cast<FlacWriter*> (client_data)->writeMetaData (metadata);
533  }
534 
535  bool ok = false;
536 
537 private:
538  FlacNamespace::FLAC__StreamEncoder* encoder;
539  int64 streamStartPos;
540 
541  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacWriter)
542 };
543 
544 
545 //==============================================================================
546 FlacAudioFormat::FlacAudioFormat() : AudioFormat (flacFormatName, ".flac") {}
547 FlacAudioFormat::~FlacAudioFormat() {}
548 
550 {
551  return { 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000,
552  88200, 96000, 176400, 192000, 352800, 384000 };
553 }
554 
556 {
557  return { 16, 24 };
558 }
559 
560 bool FlacAudioFormat::canDoStereo() { return true; }
561 bool FlacAudioFormat::canDoMono() { return true; }
562 bool FlacAudioFormat::isCompressed() { return true; }
563 
564 AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in, const bool deleteStreamIfOpeningFails)
565 {
566  std::unique_ptr<FlacReader> r (new FlacReader (in));
567 
568  if (r->sampleRate > 0)
569  return r.release();
570 
571  if (! deleteStreamIfOpeningFails)
572  r->input = nullptr;
573 
574  return nullptr;
575 }
576 
577 AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
578  double sampleRate,
579  unsigned int numberOfChannels,
580  int bitsPerSample,
581  const StringPairArray& /*metadataValues*/,
582  int qualityOptionIndex)
583 {
584  if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample))
585  {
586  std::unique_ptr<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels,
587  (uint32) bitsPerSample, qualityOptionIndex));
588  if (w->ok)
589  return w.release();
590  }
591 
592  return nullptr;
593 }
594 
596 {
597  return { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)" };
598 }
599 
600 #endif
601 
602 } // namespace juce
juce::FlacAudioFormat::getQualityOptions
StringArray getQualityOptions() override
Returns a list of different qualities that can be used when writing.
juce::FlacAudioFormat::isCompressed
bool isCompressed() override
Returns true if the format uses compressed data.
juce::FlacAudioFormat::getPossibleBitDepths
Array< int > getPossibleBitDepths() override
Returns a set of bit depths that the format can read and write.
juce::FlacAudioFormat::getPossibleSampleRates
Array< int > getPossibleSampleRates() override
Returns a set of sample rates that the format can read and write.
juce::FlacAudioFormat::createWriterFor
AudioFormatWriter * createWriterFor(OutputStream *streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray &metadataValues, int qualityOptionIndex) override
Tries to create an object that can write to a stream with this audio format.
juce::FlacAudioFormat::canDoMono
bool canDoMono() override
Returns true if the format can do 1-channel audio.
juce::FlacAudioFormat::createReaderFor
AudioFormatReader * createReaderFor(InputStream *sourceStream, bool deleteStreamIfOpeningFails) override
Tries to create an object that can read from a stream containing audio data in this format.
juce::FlacAudioFormat::canDoStereo
bool canDoStereo() override
Returns true if the format can do 2-channel audio.