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