JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_FlacAudioFormat.cpp
Go to the documentation of this file.
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
26namespace juce
27{
28
29#if JUCE_USE_FLAC
30
31}
32
33#if defined _WIN32 && !defined __CYGWIN__
34 #include <io.h>
35#else
36 #include <unistd.h>
37#endif
38
39#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
40 #include <sys/types.h> /* for off_t */
41#endif
42
43#if HAVE_INTTYPES_H
44 #define __STDC_FORMAT_MACROS
45 #include <inttypes.h>
46#endif
47
48#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || defined __EMX__
49 #include <io.h> /* for _setmode(), chmod() */
50 #include <fcntl.h> /* for _O_BINARY */
51#else
52 #include <unistd.h> /* for chown(), unlink() */
53#endif
54
55#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
56 #if defined __BORLANDC__
57 #include <utime.h> /* for utime() */
58 #else
59 #include <sys/utime.h> /* for utime() */
60 #endif
61#else
62 #include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
63 #include <utime.h> /* for utime() */
64#endif
65
66#if defined _MSC_VER
67 #if _MSC_VER >= 1600
68 #include <stdint.h>
69 #else
70 #include <limits.h>
71 #endif
72#endif
73
74#ifdef _WIN32
75 #include <stdio.h>
76 #include <sys/stat.h>
77 #include <stdarg.h>
78 #include <windows.h>
79#endif
80
81#ifdef DEBUG
82 #include <assert.h>
83#endif
84
85#include <stdlib.h>
86#include <stdio.h>
87
88namespace juce
89{
90
91namespace FlacNamespace
92{
93#if JUCE_INCLUDE_FLAC_CODE || ! defined (JUCE_INCLUDE_FLAC_CODE)
94
95 #undef PACKAGE_VERSION
96 #define PACKAGE_VERSION "1.4.3"
97
98 #define FLAC__NO_DLL 1
99
100 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)
101 #if ! JUCE_MSVC
102 #define HAVE_LROUND 1
103 #endif
104
105 #if JUCE_MAC
106 #define FLAC__SYS_DARWIN 1
107 #endif
108
109 #ifndef SIZE_MAX
110 #define SIZE_MAX 0xffffffff
111 #endif
112
113 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wconversion",
114 "-Wdeprecated-register",
115 "-Wfloat-equal",
116 "-Wimplicit-fallthrough",
117 "-Wlanguage-extension-token",
118 "-Wredundant-decls",
119 "-Wshadow",
120 "-Wsign-conversion",
121 "-Wswitch-default",
122 "-Wswitch-enum",
123 "-Wzero-as-null-pointer-constant")
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 #if JUCE_ARM && JUCE_64BIT
136 #define FLAC__CPU_ARM64 1
137
138 #if JUCE_USE_ARM_NEON
139 #define FLAC__HAS_NEONINTRIN 1
140 #define FLAC__HAS_A64NEONINTRIN 1
141 #endif
142 #endif
143
144 #define flac_max jmax
145 #define flac_min jmin
146
147 #pragma push_macro ("DEBUG")
148 #pragma push_macro ("NDEBUG")
149 #undef DEBUG // (some flac code dumps debug trace if the app defines this macro)
150
151 #ifndef NDEBUG
152 #define NDEBUG // (some flac code prints cpu info if this isn't defined)
153 #endif
154
155#include <FLAC/all.h>
156#if 0
157 #include "flac/all.h"
158 #include "flac/libFLAC/bitmath.c"
159 #include "flac/libFLAC/bitreader.c"
160 #include "flac/libFLAC/bitwriter.c"
161 #include "flac/libFLAC/cpu.c"
162 #include "flac/libFLAC/crc.c"
163 #include "flac/libFLAC/fixed.c"
164 #include "flac/libFLAC/float.c"
165 #include "flac/libFLAC/format.c"
166 #include "flac/libFLAC/lpc_flac.c"
167 #include "flac/libFLAC/lpc_intrin_neon.c"
168 #include "flac/libFLAC/md5.c"
169 #include "flac/libFLAC/memory.c"
170 #include "flac/libFLAC/stream_decoder.c"
171 #include "flac/libFLAC/stream_encoder.c"
172 #include "flac/libFLAC/stream_encoder_framing.c"
173 #include "flac/libFLAC/window_flac.c"
174#endif
175
176 #pragma pop_macro ("DEBUG")
177 #pragma pop_macro ("NDEBUG")
178
179 #undef PACKAGE_VERSION
180
181 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
182 JUCE_END_IGNORE_WARNINGS_MSVC
183
184#else
185 #include <FLAC/all.h>
186#endif
187}
188
189#undef max
190#undef min
191
192//==============================================================================
193static const char* const flacFormatName = "FLAC file";
194
195template <typename Item>
196auto emptyRange (Item item) { return Range<Item>::emptyRange (item); }
197
198//==============================================================================
199class FlacReader final : public AudioFormatReader
200{
201public:
202 FlacReader (InputStream* in) : AudioFormatReader (in, flacFormatName)
203 {
204 lengthInSamples = 0;
205 decoder = FlacNamespace::FLAC__stream_decoder_new();
206
210 this) == FlacNamespace::FLAC__STREAM_DECODER_INIT_STATUS_OK;
211
212 if (ok)
213 {
215
216 if (lengthInSamples == 0 && sampleRate > 0)
217 {
218 // the length hasn't been stored in the metadata, so we'll need to
219 // work it out the length the hard way, by scanning the whole file..
220 scanningForLength = true;
222 scanningForLength = false;
223 auto tempLength = lengthInSamples;
224
227 lengthInSamples = tempLength;
228 }
229 }
230 }
231
232 ~FlacReader() override
233 {
234 FlacNamespace::FLAC__stream_decoder_delete (decoder);
235 }
236
237 void useMetadata (const FlacNamespace::FLAC__StreamMetadata_StreamInfo& info)
238 {
239 sampleRate = info.sample_rate;
240 bitsPerSample = info.bits_per_sample;
241 lengthInSamples = (unsigned int) info.total_samples;
242 numChannels = info.channels;
243
244 reservoir.setSize ((int) numChannels, 2 * (int) info.max_blocksize, false, false, true);
245 }
246
247 bool readSamples (int* const* destSamples, int numDestChannels, int startOffsetInDestBuffer,
248 int64 startSampleInFile, int numSamples) override
249 {
250 if (! ok)
251 return false;
252
253 const auto getBufferedRange = [this] { return bufferedRange; };
254
256 {
257 const auto bufferIndices = rangeToRead - bufferedRange.getStart();
258 const auto writePos = (int64) startOffsetInDestBuffer + (rangeToRead.getStart() - startSampleInFile);
259
260 for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;)
261 {
262 if (destSamples[i] != nullptr)
263 {
264 memcpy (destSamples[i] + writePos,
265 reservoir.getReadPointer (i) + bufferIndices.getStart(),
266 (size_t) bufferIndices.getLength() * sizeof (int));
267 }
268 }
269 };
270
271 const auto fillReservoir = [this] (const int64 requestedStart)
272 {
273 if (requestedStart >= lengthInSamples)
274 {
275 bufferedRange = emptyRange (requestedStart);
276 return;
277 }
278
279 if (requestedStart < bufferedRange.getStart()
280 || jmax (bufferedRange.getEnd(), bufferedRange.getStart() + (int64) 511) < requestedStart)
281 {
282 // had some problems with flac crashing if the read pos is aligned more
283 // accurately than this. Probably fixed in newer versions of the library, though.
284 bufferedRange = emptyRange (requestedStart & ~511);
285 FLAC__stream_decoder_seek_absolute (decoder, (FlacNamespace::FLAC__uint64) bufferedRange.getStart());
286 return;
287 }
288
289 bufferedRange = emptyRange (bufferedRange.getEnd());
291 };
292
293 const auto remainingSamples = Reservoir::doBufferedRead (Range<int64> { startSampleInFile, startSampleInFile + numSamples },
297
298 if (! remainingSamples.isEmpty())
299 for (int i = numDestChannels; --i >= 0;)
300 if (destSamples[i] != nullptr)
302 (size_t) remainingSamples.getLength() * sizeof (int));
303
304 return true;
305 }
306
307 void useSamples (const FlacNamespace::FLAC__int32* const buffer[], int numSamples)
308 {
310 {
311 lengthInSamples += numSamples;
312 }
313 else
314 {
315 if (numSamples > reservoir.getNumSamples())
316 reservoir.setSize ((int) numChannels, numSamples, false, false, true);
317
318 auto bitsToShift = 32 - bitsPerSample;
319
320 for (int i = 0; i < (int) numChannels; ++i)
321 {
322 auto* src = buffer[i];
323 int n = i;
324
325 while (src == nullptr && n > 0)
326 src = buffer [--n];
327
328 if (src != nullptr)
329 {
330 auto* dest = reinterpret_cast<int*> (reservoir.getWritePointer (i));
331
332 for (int j = 0; j < numSamples; ++j)
333 dest[j] = src[j] << bitsToShift;
334 }
335 }
336
337 bufferedRange.setLength (numSamples);
338 }
339 }
340
341 //==============================================================================
342 static FlacNamespace::FLAC__StreamDecoderReadStatus readCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__byte buffer[], size_t* bytes, void* client_data)
343 {
344 *bytes = (size_t) static_cast<const FlacReader*> (client_data)->input->read (buffer, (int) *bytes);
345 return FlacNamespace::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
346 }
347
348 static FlacNamespace::FLAC__StreamDecoderSeekStatus seekCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64 absolute_byte_offset, void* client_data)
349 {
350 static_cast<const FlacReader*> (client_data)->input->setPosition ((int) absolute_byte_offset);
351 return FlacNamespace::FLAC__STREAM_DECODER_SEEK_STATUS_OK;
352 }
353
354 static FlacNamespace::FLAC__StreamDecoderTellStatus tellCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
355 {
356 *absolute_byte_offset = (uint64) static_cast<const FlacReader*> (client_data)->input->getPosition();
357 return FlacNamespace::FLAC__STREAM_DECODER_TELL_STATUS_OK;
358 }
359
360 static FlacNamespace::FLAC__StreamDecoderLengthStatus lengthCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* stream_length, void* client_data)
361 {
362 *stream_length = (uint64) static_cast<const FlacReader*> (client_data)->input->getTotalLength();
363 return FlacNamespace::FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
364 }
365
366 static FlacNamespace::FLAC__bool eofCallback_ (const FlacNamespace::FLAC__StreamDecoder*, void* client_data)
367 {
368 return static_cast<const FlacReader*> (client_data)->input->isExhausted();
369 }
370
371 static FlacNamespace::FLAC__StreamDecoderWriteStatus writeCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
372 const FlacNamespace::FLAC__Frame* frame,
373 const FlacNamespace::FLAC__int32* const buffer[],
374 void* client_data)
375 {
376 static_cast<FlacReader*> (client_data)->useSamples (buffer, (int) frame->header.blocksize);
377 return FlacNamespace::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
378 }
379
380 static void metadataCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
381 const FlacNamespace::FLAC__StreamMetadata* metadata,
382 void* client_data)
383 {
384 static_cast<FlacReader*> (client_data)->useMetadata (metadata->data.stream_info);
385 }
386
387 static void errorCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__StreamDecoderErrorStatus, void*)
388 {
389 }
390
391private:
392 FlacNamespace::FLAC__StreamDecoder* decoder;
393 AudioBuffer<float> reservoir;
394 Range<int64> bufferedRange;
395 bool ok = false, scanningForLength = false;
396
398};
399
400
401//==============================================================================
402class FlacWriter final : public AudioFormatWriter
403{
404public:
405 FlacWriter (OutputStream* out, double rate, uint32 numChans, uint32 bits, int qualityOptionIndex)
406 : AudioFormatWriter (out, flacFormatName, rate, numChans, bits),
407 streamStartPos (output != nullptr ? jmax (output->getPosition(), 0ll) : 0ll)
408 {
409 encoder = FlacNamespace::FLAC__stream_encoder_new();
410
411 if (qualityOptionIndex > 0)
413
417 FLAC__stream_encoder_set_bits_per_sample (encoder, jmin ((unsigned int) 24, bitsPerSample));
418 FLAC__stream_encoder_set_sample_rate (encoder, (unsigned int) sampleRate);
421
425 this) == FlacNamespace::FLAC__STREAM_ENCODER_INIT_STATUS_OK;
426 }
427
428 ~FlacWriter() override
429 {
430 if (ok)
431 {
432 FlacNamespace::FLAC__stream_encoder_finish (encoder);
433 output->flush();
434 }
435 else
436 {
437 output = nullptr; // to stop the base class deleting this, as it needs to be returned
438 // to the caller of createWriter()
439 }
440
441 FlacNamespace::FLAC__stream_encoder_delete (encoder);
442 }
443
444 //==============================================================================
445 bool write (const int** samplesToWrite, int numSamples) override
446 {
447 if (! ok)
448 return false;
449
450 HeapBlock<int*> channels;
451 HeapBlock<int> temp;
452 auto bitsToShift = 32 - (int) bitsPerSample;
453
454 if (bitsToShift > 0)
455 {
456 temp.malloc (numChannels * (size_t) numSamples);
457 channels.calloc (numChannels + 1);
458
459 for (unsigned int i = 0; i < numChannels; ++i)
460 {
461 if (samplesToWrite[i] == nullptr)
462 break;
463
464 auto* destData = temp.get() + i * (size_t) numSamples;
465 channels[i] = destData;
466
467 for (int j = 0; j < numSamples; ++j)
468 destData[j] = (samplesToWrite[i][j] >> bitsToShift);
469 }
470
471 samplesToWrite = const_cast<const int**> (channels.get());
472 }
473
474 return FLAC__stream_encoder_process (encoder, (const FlacNamespace::FLAC__int32**) samplesToWrite, (unsigned) numSamples) != 0;
475 }
476
477 bool writeData (const void* const data, const int size) const
478 {
479 return output->write (data, (size_t) size);
480 }
481
482 static void packUint32 (FlacNamespace::FLAC__uint32 val, FlacNamespace::FLAC__byte* b, const int bytes)
483 {
484 b += bytes;
485
486 for (int i = 0; i < bytes; ++i)
487 {
488 *(--b) = (FlacNamespace::FLAC__byte) (val & 0xff);
489 val >>= 8;
490 }
491 }
492
493 void writeMetaData (const FlacNamespace::FLAC__StreamMetadata* metadata)
494 {
495 using namespace FlacNamespace;
496 auto& info = metadata->data.stream_info;
497
498 unsigned char buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
499 const unsigned int channelsMinus1 = info.channels - 1;
500 const unsigned int bitsMinus1 = info.bits_per_sample - 1;
501
502 packUint32 (info.min_blocksize, buffer, 2);
503 packUint32 (info.max_blocksize, buffer + 2, 2);
504 packUint32 (info.min_framesize, buffer + 4, 3);
505 packUint32 (info.max_framesize, buffer + 7, 3);
506 buffer[10] = (uint8) ((info.sample_rate >> 12) & 0xff);
507 buffer[11] = (uint8) ((info.sample_rate >> 4) & 0xff);
508 buffer[12] = (uint8) (((info.sample_rate & 0x0f) << 4) | (channelsMinus1 << 1) | (bitsMinus1 >> 4));
509 buffer[13] = (FLAC__byte) (((bitsMinus1 & 0x0f) << 4) | (unsigned int) ((info.total_samples >> 32) & 0x0f));
510 packUint32 ((FLAC__uint32) info.total_samples, buffer + 14, 4);
511 memcpy (buffer + 18, info.md5sum, 16);
512
513 [[maybe_unused]] const bool seekOk = output->setPosition (streamStartPos + 4);
514
515 // if this fails, you've given it an output stream that can't seek! It needs
516 // to be able to seek back to write the header
517 jassert (seekOk);
518
519 output->writeIntBigEndian (FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
520 output->write (buffer, FLAC__STREAM_METADATA_STREAMINFO_LENGTH);
521 }
522
523 //==============================================================================
524 static FlacNamespace::FLAC__StreamEncoderWriteStatus encodeWriteCallback (const FlacNamespace::FLAC__StreamEncoder*,
525 const FlacNamespace::FLAC__byte buffer[],
526 size_t bytes,
527 unsigned int /*samples*/,
528 unsigned int /*current_frame*/,
529 void* client_data)
530 {
531 return static_cast<FlacWriter*> (client_data)->writeData (buffer, (int) bytes)
532 ? FlacNamespace::FLAC__STREAM_ENCODER_WRITE_STATUS_OK
534 }
535
536 static FlacNamespace::FLAC__StreamEncoderSeekStatus encodeSeekCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64, void*)
537 {
538 return FlacNamespace::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
539 }
540
541 static FlacNamespace::FLAC__StreamEncoderTellStatus encodeTellCallback (const FlacNamespace::FLAC__StreamEncoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
542 {
543 if (client_data == nullptr)
544 return FlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
545
546 *absolute_byte_offset = (FlacNamespace::FLAC__uint64) static_cast<FlacWriter*> (client_data)->output->getPosition();
547 return FlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_OK;
548 }
549
550 static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder*, const FlacNamespace::FLAC__StreamMetadata* metadata, void* client_data)
551 {
552 static_cast<FlacWriter*> (client_data)->writeMetaData (metadata);
553 }
554
555 bool ok = false;
556
557private:
558 FlacNamespace::FLAC__StreamEncoder* encoder;
560
562};
563
564
565//==============================================================================
566FlacAudioFormat::FlacAudioFormat() : AudioFormat (flacFormatName, ".flac") {}
567FlacAudioFormat::~FlacAudioFormat() {}
568
569Array<int> FlacAudioFormat::getPossibleSampleRates()
570{
571 return { 8000, 11025, 12000, 16000, 22050, 32000, 44100, 48000,
572 88200, 96000, 176400, 192000, 352800, 384000 };
573}
574
575Array<int> FlacAudioFormat::getPossibleBitDepths()
576{
577 return { 16, 24 };
578}
579
580bool FlacAudioFormat::canDoStereo() { return true; }
581bool FlacAudioFormat::canDoMono() { return true; }
582bool FlacAudioFormat::isCompressed() { return true; }
583
584AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in, const bool deleteStreamIfOpeningFails)
585{
586 std::unique_ptr<FlacReader> r (new FlacReader (in));
587
588 if (r->sampleRate > 0)
589 return r.release();
590
591 if (! deleteStreamIfOpeningFails)
592 r->input = nullptr;
593
594 return nullptr;
595}
596
597AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
598 double sampleRate,
599 unsigned int numberOfChannels,
600 int bitsPerSample,
601 const StringPairArray& /*metadataValues*/,
602 int qualityOptionIndex)
603{
604 if (out != nullptr && getPossibleBitDepths().contains (bitsPerSample))
605 {
606 std::unique_ptr<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels,
607 (uint32) bitsPerSample, qualityOptionIndex));
608 if (w->ok)
609 return w.release();
610 }
611
612 return nullptr;
613}
614
615StringArray FlacAudioFormat::getQualityOptions()
616{
617 return { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)" };
618}
619
620#endif
621
622} // namespace juce
static constexpr Range emptyRange(const ValueType start) noexcept
Returns a range with the specified start position and a length of zero.
Definition juce_Range.h:73
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
typedef int
memcpy
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
unsigned long long uint64
A platform-independent 64-bit unsigned integer type.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
unsigned int uint32
A platform-independent 32-bit unsigned integer type.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.
long long int64
A platform-independent 64-bit integer type.
void zeromem(void *memory, size_t numBytes) noexcept
Fills a block of memory with zeros.
Definition juce_Memory.h:28
write
static Range< Index > doBufferedRead(Range< Index > rangeToRead, GetBufferedRange &&getBufferedRange, ReadFromReservoir &&readFromReservoir, FillReservoir &&fillReservoir)
Attempts to read the requested range from some kind of input stream, with intermediate buffering in a...
typedef size_t