The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

620 lines
23KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. #if JUCE_USE_FLAC
  21. }
  22. #if defined _WIN32 && !defined __CYGWIN__
  23. #include <io.h>
  24. #else
  25. #include <unistd.h>
  26. #endif
  27. #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
  28. #include <sys/types.h> /* for off_t */
  29. #endif
  30. #if HAVE_INTTYPES_H
  31. #define __STDC_FORMAT_MACROS
  32. #include <inttypes.h>
  33. #endif
  34. #if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__
  35. #include <io.h> /* for _setmode(), chmod() */
  36. #include <fcntl.h> /* for _O_BINARY */
  37. #else
  38. #include <unistd.h> /* for chown(), unlink() */
  39. #endif
  40. #if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
  41. #if defined __BORLANDC__
  42. #include <utime.h> /* for utime() */
  43. #else
  44. #include <sys/utime.h> /* for utime() */
  45. #endif
  46. #else
  47. #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
  48. #include <utime.h> /* for utime() */
  49. #endif
  50. #if defined _MSC_VER
  51. #if _MSC_VER >= 1600
  52. #include <stdint.h>
  53. #else
  54. #include <limits.h>
  55. #endif
  56. #endif
  57. #ifdef _WIN32
  58. #include <stdio.h>
  59. #include <sys/stat.h>
  60. #include <stdarg.h>
  61. #include <windows.h>
  62. #endif
  63. #ifdef DEBUG
  64. #include <assert.h>
  65. #endif
  66. #include <stdlib.h>
  67. #include <stdio.h>
  68. namespace juce
  69. {
  70. namespace FlacNamespace
  71. {
  72. #if JUCE_INCLUDE_FLAC_CODE || ! defined (JUCE_INCLUDE_FLAC_CODE)
  73. #undef PACKAGE_VERSION
  74. #define PACKAGE_VERSION "1.4.3"
  75. #define FLAC__NO_DLL 1
  76. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4312 4505 4365 4005 4334 181 111 6340 6308 6297 6001 6320)
  77. #if ! JUCE_MSVC
  78. #define HAVE_LROUND 1
  79. #endif
  80. #if JUCE_MAC
  81. #define FLAC__SYS_DARWIN 1
  82. #endif
  83. #ifndef SIZE_MAX
  84. #define SIZE_MAX 0xffffffff
  85. #endif
  86. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion",
  87. "-Wdeprecated-register",
  88. "-Wfloat-equal",
  89. "-Wimplicit-fallthrough",
  90. "-Wlanguage-extension-token",
  91. "-Wredundant-decls",
  92. "-Wshadow",
  93. "-Wsign-conversion",
  94. "-Wswitch-default",
  95. "-Wswitch-enum",
  96. "-Wzero-as-null-pointer-constant")
  97. #if JUCE_INTEL
  98. #if JUCE_32BIT
  99. #define FLAC__CPU_IA32 1
  100. #endif
  101. #if JUCE_64BIT
  102. #define FLAC__CPU_X86_64 1
  103. #endif
  104. #define FLAC__HAS_X86INTRIN 1
  105. #endif
  106. #if JUCE_ARM && JUCE_64BIT
  107. #define FLAC__CPU_ARM64 1
  108. #if JUCE_USE_ARM_NEON
  109. #define FLAC__HAS_NEONINTRIN 1
  110. #define FLAC__HAS_A64NEONINTRIN 1
  111. #endif
  112. #endif
  113. #define flac_max jmax
  114. #define flac_min jmin
  115. #pragma push_macro ("DEBUG")
  116. #pragma push_macro ("NDEBUG")
  117. #undef DEBUG // (some flac code dumps debug trace if the app defines this macro)
  118. #ifndef NDEBUG
  119. #define NDEBUG // (some flac code prints cpu info if this isn't defined)
  120. #endif
  121. #include "flac/all.h"
  122. #include "flac/libFLAC/bitmath.c"
  123. #include "flac/libFLAC/bitreader.c"
  124. #include "flac/libFLAC/bitwriter.c"
  125. #include "flac/libFLAC/cpu.c"
  126. #include "flac/libFLAC/crc.c"
  127. #include "flac/libFLAC/fixed.c"
  128. #include "flac/libFLAC/float.c"
  129. #include "flac/libFLAC/format.c"
  130. #include "flac/libFLAC/lpc_flac.c"
  131. #include "flac/libFLAC/lpc_intrin_neon.c"
  132. #include "flac/libFLAC/md5.c"
  133. #include "flac/libFLAC/memory.c"
  134. #include "flac/libFLAC/stream_decoder.c"
  135. #include "flac/libFLAC/stream_encoder.c"
  136. #include "flac/libFLAC/stream_encoder_framing.c"
  137. #include "flac/libFLAC/window_flac.c"
  138. #pragma pop_macro ("DEBUG")
  139. #pragma pop_macro ("NDEBUG")
  140. #undef PACKAGE_VERSION
  141. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  142. JUCE_END_IGNORE_WARNINGS_MSVC
  143. #else
  144. #include <FLAC/all.h>
  145. #endif
  146. }
  147. #undef max
  148. #undef min
  149. //==============================================================================
  150. static const char* const flacFormatName = "FLAC file";
  151. template <typename Item>
  152. auto emptyRange (Item item) { return Range<Item>::emptyRange (item); }
  153. //==============================================================================
  154. class FlacReader final : public AudioFormatReader
  155. {
  156. public:
  157. FlacReader (InputStream* in) : AudioFormatReader (in, flacFormatName)
  158. {
  159. lengthInSamples = 0;
  160. decoder = FlacNamespace::FLAC__stream_decoder_new();
  161. ok = FLAC__stream_decoder_init_stream (decoder,
  162. readCallback_, seekCallback_, tellCallback_, lengthCallback_,
  163. eofCallback_, writeCallback_, metadataCallback_, errorCallback_,
  164. this) == FlacNamespace::FLAC__STREAM_DECODER_INIT_STATUS_OK;
  165. if (ok)
  166. {
  167. FLAC__stream_decoder_process_until_end_of_metadata (decoder);
  168. if (lengthInSamples == 0 && sampleRate > 0)
  169. {
  170. // the length hasn't been stored in the metadata, so we'll need to
  171. // work it out the length the hard way, by scanning the whole file..
  172. scanningForLength = true;
  173. FLAC__stream_decoder_process_until_end_of_stream (decoder);
  174. scanningForLength = false;
  175. auto tempLength = lengthInSamples;
  176. FLAC__stream_decoder_reset (decoder);
  177. FLAC__stream_decoder_process_until_end_of_metadata (decoder);
  178. lengthInSamples = tempLength;
  179. }
  180. }
  181. }
  182. ~FlacReader() override
  183. {
  184. FlacNamespace::FLAC__stream_decoder_delete (decoder);
  185. }
  186. void useMetadata (const FlacNamespace::FLAC__StreamMetadata_StreamInfo& info)
  187. {
  188. sampleRate = info.sample_rate;
  189. bitsPerSample = info.bits_per_sample;
  190. lengthInSamples = (unsigned int) info.total_samples;
  191. numChannels = info.channels;
  192. reservoir.setSize ((int) numChannels, 2 * (int) info.max_blocksize, false, false, true);
  193. }
  194. bool readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
  195. int64 startSampleInFile, int numSamples) override
  196. {
  197. if (! ok)
  198. return false;
  199. const auto getBufferedRange = [this] { return bufferedRange; };
  200. const auto readFromReservoir = [this, &destSamples, &numDestChannels, &startOffsetInDestBuffer, &startSampleInFile] (const Range<int64> rangeToRead)
  201. {
  202. const auto bufferIndices = rangeToRead - bufferedRange.getStart();
  203. const auto writePos = (int64) startOffsetInDestBuffer + (rangeToRead.getStart() - startSampleInFile);
  204. for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
  205. {
  206. if (destSamples[i] != nullptr)
  207. {
  208. memcpy (destSamples[i] + writePos,
  209. reservoir.getReadPointer (i) + bufferIndices.getStart(),
  210. (size_t) bufferIndices.getLength() * sizeof (int));
  211. }
  212. }
  213. };
  214. const auto fillReservoir = [this] (const int64 requestedStart)
  215. {
  216. if (requestedStart >= lengthInSamples)
  217. {
  218. bufferedRange = emptyRange (requestedStart);
  219. return;
  220. }
  221. if (requestedStart < bufferedRange.getStart()
  222. || jmax (bufferedRange.getEnd(), bufferedRange.getStart() + (int64) 511) < requestedStart)
  223. {
  224. // had some problems with flac crashing if the read pos is aligned more
  225. // accurately than this. Probably fixed in newer versions of the library, though.
  226. bufferedRange = emptyRange (requestedStart & ~511);
  227. FLAC__stream_decoder_seek_absolute (decoder, (FlacNamespace::FLAC__uint64) bufferedRange.getStart());
  228. return;
  229. }
  230. bufferedRange = emptyRange (bufferedRange.getEnd());
  231. FLAC__stream_decoder_process_single (decoder);
  232. };
  233. const auto remainingSamples = Reservoir::doBufferedRead (Range<int64> { startSampleInFile, startSampleInFile + numSamples },
  234. getBufferedRange,
  235. readFromReservoir,
  236. fillReservoir);
  237. if (! remainingSamples.isEmpty())
  238. for (int i = numDestChannels; --i >= 0;)
  239. if (destSamples[i] != nullptr)
  240. zeromem (destSamples[i] + startOffsetInDestBuffer + (remainingSamples.getStart() - startSampleInFile),
  241. (size_t) remainingSamples.getLength() * sizeof (int));
  242. return true;
  243. }
  244. void useSamples (const FlacNamespace::FLAC__int32* const buffer[], int numSamples)
  245. {
  246. if (scanningForLength)
  247. {
  248. lengthInSamples += numSamples;
  249. }
  250. else
  251. {
  252. if (numSamples > reservoir.getNumSamples())
  253. reservoir.setSize ((int) numChannels, numSamples, false, false, true);
  254. auto bitsToShift = 32 - bitsPerSample;
  255. for (int i = 0; i < (int) numChannels; ++i)
  256. {
  257. auto* src = buffer[i];
  258. int n = i;
  259. while (src == nullptr && n > 0)
  260. src = buffer [--n];
  261. if (src != nullptr)
  262. {
  263. auto* dest = reinterpret_cast<int*> (reservoir.getWritePointer (i));
  264. for (int j = 0; j < numSamples; ++j)
  265. dest[j] = src[j] << bitsToShift;
  266. }
  267. }
  268. bufferedRange.setLength (numSamples);
  269. }
  270. }
  271. //==============================================================================
  272. static FlacNamespace::FLAC__StreamDecoderReadStatus readCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__byte buffer[], size_t* bytes, void* client_data)
  273. {
  274. *bytes = (size_t) static_cast<const FlacReader*> (client_data)->input->read (buffer, (int) *bytes);
  275. return FlacNamespace::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
  276. }
  277. static FlacNamespace::FLAC__StreamDecoderSeekStatus seekCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64 absolute_byte_offset, void* client_data)
  278. {
  279. static_cast<const FlacReader*> (client_data)->input->setPosition ((int) absolute_byte_offset);
  280. return FlacNamespace::FLAC__STREAM_DECODER_SEEK_STATUS_OK;
  281. }
  282. static FlacNamespace::FLAC__StreamDecoderTellStatus tellCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
  283. {
  284. *absolute_byte_offset = (uint64) static_cast<const FlacReader*> (client_data)->input->getPosition();
  285. return FlacNamespace::FLAC__STREAM_DECODER_TELL_STATUS_OK;
  286. }
  287. static FlacNamespace::FLAC__StreamDecoderLengthStatus lengthCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* stream_length, void* client_data)
  288. {
  289. *stream_length = (uint64) static_cast<const FlacReader*> (client_data)->input->getTotalLength();
  290. return FlacNamespace::FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
  291. }
  292. static FlacNamespace::FLAC__bool eofCallback_ (const FlacNamespace::FLAC__StreamDecoder*, void* client_data)
  293. {
  294. return static_cast<const FlacReader*> (client_data)->input->isExhausted();
  295. }
  296. static FlacNamespace::FLAC__StreamDecoderWriteStatus writeCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
  297. const FlacNamespace::FLAC__Frame* frame,
  298. const FlacNamespace::FLAC__int32* const buffer[],
  299. void* client_data)
  300. {
  301. static_cast<FlacReader*> (client_data)->useSamples (buffer, (int) frame->header.blocksize);
  302. return FlacNamespace::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
  303. }
  304. static void metadataCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
  305. const FlacNamespace::FLAC__StreamMetadata* metadata,
  306. void* client_data)
  307. {
  308. static_cast<FlacReader*> (client_data)->useMetadata (metadata->data.stream_info);
  309. }
  310. static void errorCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__StreamDecoderErrorStatus, void*)
  311. {
  312. }
  313. private:
  314. FlacNamespace::FLAC__StreamDecoder* decoder;
  315. AudioBuffer<float> reservoir;
  316. Range<int64> bufferedRange;
  317. bool ok = false, scanningForLength = false;
  318. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacReader)
  319. };
  320. //==============================================================================
  321. class FlacWriter final : public AudioFormatWriter
  322. {
  323. public:
  324. FlacWriter (OutputStream* out, double rate, uint32 numChans, uint32 bits, int qualityOptionIndex)
  325. : AudioFormatWriter (out, flacFormatName, rate, numChans, bits),
  326. streamStartPos (output != nullptr ? jmax (output->getPosition(), 0ll) : 0ll)
  327. {
  328. encoder = FlacNamespace::FLAC__stream_encoder_new();
  329. if (qualityOptionIndex > 0)
  330. FLAC__stream_encoder_set_compression_level (encoder, (uint32) jmin (8, qualityOptionIndex));
  331. FLAC__stream_encoder_set_do_mid_side_stereo (encoder, numChannels == 2);
  332. FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, numChannels == 2);
  333. FLAC__stream_encoder_set_channels (encoder, numChannels);
  334. FLAC__stream_encoder_set_bits_per_sample (encoder, jmin ((unsigned int) 24, bitsPerSample));
  335. FLAC__stream_encoder_set_sample_rate (encoder, (unsigned int) sampleRate);
  336. FLAC__stream_encoder_set_blocksize (encoder, 0);
  337. FLAC__stream_encoder_set_do_escape_coding (encoder, true);
  338. ok = FLAC__stream_encoder_init_stream (encoder,
  339. encodeWriteCallback, encodeSeekCallback,
  340. encodeTellCallback, encodeMetadataCallback,
  341. this) == FlacNamespace::FLAC__STREAM_ENCODER_INIT_STATUS_OK;
  342. }
  343. ~FlacWriter() override
  344. {
  345. if (ok)
  346. {
  347. FlacNamespace::FLAC__stream_encoder_finish (encoder);
  348. output->flush();
  349. }
  350. else
  351. {
  352. output = nullptr; // to stop the base class deleting this, as it needs to be returned
  353. // to the caller of createWriter()
  354. }
  355. FlacNamespace::FLAC__stream_encoder_delete (encoder);
  356. }
  357. //==============================================================================
  358. bool write (const int** samplesToWrite, int numSamples) override
  359. {
  360. if (! ok)
  361. return false;
  362. HeapBlock<int*> channels;
  363. HeapBlock<int> temp;
  364. auto bitsToShift = 32 - (int) bitsPerSample;
  365. if (bitsToShift > 0)
  366. {
  367. temp.malloc (numChannels * (size_t) numSamples);
  368. channels.calloc (numChannels + 1);
  369. for (unsigned int i = 0; i < numChannels; ++i)
  370. {
  371. if (samplesToWrite[i] == nullptr)
  372. break;
  373. auto* destData = temp.get() + i * (size_t) numSamples;
  374. channels[i] = destData;
  375. for (int j = 0; j < numSamples; ++j)
  376. destData[j] = (samplesToWrite[i][j] >> bitsToShift);
  377. }
  378. samplesToWrite = const_cast<const int**> (channels.get());
  379. }
  380. return FLAC__stream_encoder_process (encoder, (const FlacNamespace::FLAC__int32**) samplesToWrite, (unsigned) numSamples) != 0;
  381. }
  382. bool writeData (const void* const data, const int size) const
  383. {
  384. return output->write (data, (size_t) size);
  385. }
  386. static void packUint32 (FlacNamespace::FLAC__uint32 val, FlacNamespace::FLAC__byte* b, const int bytes)
  387. {
  388. b += bytes;
  389. for (int i = 0; i < bytes; ++i)
  390. {
  391. *(--b) = (FlacNamespace::FLAC__byte) (val & 0xff);
  392. val >>= 8;
  393. }
  394. }
  395. void writeMetaData (const FlacNamespace::FLAC__StreamMetadata* metadata)
  396. {
  397. using namespace FlacNamespace;
  398. auto& info = metadata->data.stream_info;
  399. unsigned char buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
  400. const unsigned int channelsMinus1 = info.channels - 1;
  401. const unsigned int bitsMinus1 = info.bits_per_sample - 1;
  402. packUint32 (info.min_blocksize, buffer, 2);
  403. packUint32 (info.max_blocksize, buffer + 2, 2);
  404. packUint32 (info.min_framesize, buffer + 4, 3);
  405. packUint32 (info.max_framesize, buffer + 7, 3);
  406. buffer[10] = (uint8) ((info.sample_rate >> 12) & 0xff);
  407. buffer[11] = (uint8) ((info.sample_rate >> 4) & 0xff);
  408. buffer[12] = (uint8) (((info.sample_rate & 0x0f) << 4) | (channelsMinus1 << 1) | (bitsMinus1 >> 4));
  409. buffer[13] = (FLAC__byte) (((bitsMinus1 & 0x0f) << 4) | (unsigned int) ((info.total_samples >> 32) & 0x0f));
  410. packUint32 ((FLAC__uint32) info.total_samples, buffer + 14, 4);
  411. memcpy (buffer + 18, info.md5sum, 16);
  412. [[maybe_unused]] const bool seekOk = output->setPosition (streamStartPos + 4);
  413. // if this fails, you've given it an output stream that can't seek! It needs
  414. // to be able to seek back to write the header
  415. jassert (seekOk);
  416. output->writeIntBigEndian (FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
  417. output->write (buffer, FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
  418. }
  419. //==============================================================================
  420. static FlacNamespace::FLAC__StreamEncoderWriteStatus encodeWriteCallback (const FlacNamespace::FLAC__StreamEncoder*,
  421. const FlacNamespace::FLAC__byte buffer[],
  422. size_t bytes,
  423. unsigned int /*samples*/,
  424. unsigned int /*current_frame*/,
  425. void* client_data)
  426. {
  427. return static_cast<FlacWriter*> (client_data)->writeData (buffer, (int) bytes)
  428. ? FlacNamespace::FLAC__STREAM_ENCODER_WRITE_STATUS_OK
  429. : FlacNamespace::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
  430. }
  431. static FlacNamespace::FLAC__StreamEncoderSeekStatus encodeSeekCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64, void*)
  432. {
  433. return FlacNamespace::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
  434. }
  435. static FlacNamespace::FLAC__StreamEncoderTellStatus encodeTellCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
  436. {
  437. if (client_data == nullptr)
  438. return FlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
  439. *absolute_byte_offset = (FlacNamespace::FLAC__uint64) static_cast<FlacWriter*> (client_data)->output->getPosition();
  440. return FlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_OK;
  441. }
  442. static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder*, const FlacNamespace::FLAC__StreamMetadata* metadata, void* client_data)
  443. {
  444. static_cast<FlacWriter*> (client_data)->writeMetaData (metadata);
  445. }
  446. bool ok = false;
  447. private:
  448. FlacNamespace::FLAC__StreamEncoder* encoder;
  449. int64 streamStartPos;
  450. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacWriter)
  451. };
  452. //==============================================================================
  453. FlacAudioFormat::FlacAudioFormat() : AudioFormat (flacFormatName, ".flac") {}
  454. FlacAudioFormat::~FlacAudioFormat() {}
  455. Array<int> FlacAudioFormat::getPossibleSampleRates()
  456. {
  457. return { 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000,
  458. 88200, 96000, 176400, 192000, 352800, 384000 };
  459. }
  460. Array<int> FlacAudioFormat::getPossibleBitDepths()
  461. {
  462. return { 16, 24 };
  463. }
  464. bool FlacAudioFormat::canDoStereo() { return true; }
  465. bool FlacAudioFormat::canDoMono() { return true; }
  466. bool FlacAudioFormat::isCompressed() { return true; }
  467. AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in, const bool deleteStreamIfOpeningFails)
  468. {
  469. std::unique_ptr<FlacReader> r (new FlacReader (in));
  470. if (r->sampleRate > 0)
  471. return r.release();
  472. if (! deleteStreamIfOpeningFails)
  473. r->input = nullptr;
  474. return nullptr;
  475. }
  476. AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
  477. double sampleRate,
  478. unsigned int numberOfChannels,
  479. int bitsPerSample,
  480. const StringPairArray& /*metadataValues*/,
  481. int qualityOptionIndex)
  482. {
  483. if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample))
  484. {
  485. std::unique_ptr<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels,
  486. (uint32) bitsPerSample, qualityOptionIndex));
  487. if (w->ok)
  488. return w.release();
  489. }
  490. return nullptr;
  491. }
  492. StringArray FlacAudioFormat::getQualityOptions()
  493. {
  494. return { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)" };
  495. }
  496. #endif
  497. } // namespace juce