2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_TargetPlatform.h"
27 #include "../../../juce_Config.h"
35 #include "../../core/juce_StandardHeader.h"
39 namespace FlacNamespace
41 #if JUCE_INCLUDE_FLAC_CODE
43 #pragma warning (disable: 4505 181 111)
46 #define FLAC__NO_DLL 1
48 #if ! defined (SIZE_MAX)
49 #define SIZE_MAX 0xffffffff
52 #define __STDC_LIMIT_MACROS 1
54 #include "flac/libFLAC/bitmath.c"
55 #include "flac/libFLAC/bitreader.c"
56 #include "flac/libFLAC/bitwriter.c"
57 #include "flac/libFLAC/cpu.c"
58 #include "flac/libFLAC/crc.c"
59 #include "flac/libFLAC/fixed.c"
60 #include "flac/libFLAC/float.c"
61 #include "flac/libFLAC/format.c"
62 #include "flac/libFLAC/lpc_flac.c"
63 #include "flac/libFLAC/md5.c"
64 #include "flac/libFLAC/memory.c"
65 #include "flac/libFLAC/stream_decoder.c"
66 #include "flac/libFLAC/stream_encoder.c"
67 #include "flac/libFLAC/stream_encoder_framing.c"
68 #include "flac/libFLAC/window_flac.c"
77 #include "juce_FlacAudioFormat.h"
78 #include "../../text/juce_LocalisedStrings.h"
79 #include "../../memory/juce_ScopedPointer.h"
82 //==============================================================================
83 static const char* const flacFormatName
= "FLAC file";
84 static const char* const flacExtensions
[] = { ".flac", 0 };
87 //==============================================================================
88 class FlacReader
: public AudioFormatReader
91 //==============================================================================
92 FlacReader (InputStream
* const in
)
93 : AudioFormatReader (in
, TRANS (flacFormatName
)),
96 samplesInReservoir (0),
97 scanningForLength (false)
99 using namespace FlacNamespace
;
102 decoder
= FLAC__stream_decoder_new();
104 ok
= FLAC__stream_decoder_init_stream (decoder
,
105 readCallback_
, seekCallback_
, tellCallback_
, lengthCallback_
,
106 eofCallback_
, writeCallback_
, metadataCallback_
, errorCallback_
,
107 this) == FLAC__STREAM_DECODER_INIT_STATUS_OK
;
111 FLAC__stream_decoder_process_until_end_of_metadata (decoder
);
113 if (lengthInSamples
== 0 && sampleRate
> 0)
115 // the length hasn't been stored in the metadata, so we'll need to
116 // work it out the length the hard way, by scanning the whole file..
117 scanningForLength
= true;
118 FLAC__stream_decoder_process_until_end_of_stream (decoder
);
119 scanningForLength
= false;
120 const int64 tempLength
= lengthInSamples
;
122 FLAC__stream_decoder_reset (decoder
);
123 FLAC__stream_decoder_process_until_end_of_metadata (decoder
);
124 lengthInSamples
= tempLength
;
131 FlacNamespace::FLAC__stream_decoder_delete (decoder
);
134 void useMetadata (const FlacNamespace::FLAC__StreamMetadata_StreamInfo
& info
)
136 sampleRate
= info
.sample_rate
;
137 bitsPerSample
= info
.bits_per_sample
;
138 lengthInSamples
= (unsigned int) info
.total_samples
;
139 numChannels
= info
.channels
;
141 reservoir
.setSize (numChannels
, 2 * info
.max_blocksize
, false, false, true);
144 // returns the number of samples read
145 bool readSamples (int** destSamples
, int numDestChannels
, int startOffsetInDestBuffer
,
146 int64 startSampleInFile
, int numSamples
)
148 using namespace FlacNamespace
;
153 while (numSamples
> 0)
155 if (startSampleInFile
>= reservoirStart
156 && startSampleInFile
< reservoirStart
+ samplesInReservoir
)
158 const int num
= (int) jmin ((int64
) numSamples
,
159 reservoirStart
+ samplesInReservoir
- startSampleInFile
);
163 for (int i
= jmin (numDestChannels
, reservoir
.getNumChannels()); --i
>= 0;)
164 if (destSamples
[i
] != nullptr)
165 memcpy (destSamples
[i
] + startOffsetInDestBuffer
,
166 reservoir
.getSampleData (i
, (int) (startSampleInFile
- reservoirStart
)),
169 startOffsetInDestBuffer
+= num
;
170 startSampleInFile
+= num
;
175 if (startSampleInFile
>= (int) lengthInSamples
)
177 samplesInReservoir
= 0;
179 else if (startSampleInFile
< reservoirStart
180 || startSampleInFile
> reservoirStart
+ jmax (samplesInReservoir
, 511))
182 // had some problems with flac crashing if the read pos is aligned more
183 // accurately than this. Probably fixed in newer versions of the library, though.
184 reservoirStart
= (int) (startSampleInFile
& ~511);
185 samplesInReservoir
= 0;
186 FLAC__stream_decoder_seek_absolute (decoder
, (FLAC__uint64
) reservoirStart
);
190 reservoirStart
+= samplesInReservoir
;
191 samplesInReservoir
= 0;
192 FLAC__stream_decoder_process_single (decoder
);
195 if (samplesInReservoir
== 0)
202 for (int i
= numDestChannels
; --i
>= 0;)
203 if (destSamples
[i
] != nullptr)
204 zeromem (destSamples
[i
] + startOffsetInDestBuffer
,
205 sizeof (int) * numSamples
);
211 void useSamples (const FlacNamespace::FLAC__int32
* const buffer
[], int numSamples
)
213 if (scanningForLength
)
215 lengthInSamples
+= numSamples
;
219 if (numSamples
> reservoir
.getNumSamples())
220 reservoir
.setSize (numChannels
, numSamples
, false, false, true);
222 const int bitsToShift
= 32 - bitsPerSample
;
224 for (int i
= 0; i
< (int) numChannels
; ++i
)
226 const FlacNamespace::FLAC__int32
* src
= buffer
[i
];
229 while (src
== 0 && n
> 0)
234 int* dest
= reinterpret_cast<int*> (reservoir
.getSampleData(i
));
236 for (int j
= 0; j
< numSamples
; ++j
)
237 dest
[j
] = src
[j
] << bitsToShift
;
241 samplesInReservoir
= numSamples
;
245 //==============================================================================
246 static FlacNamespace::FLAC__StreamDecoderReadStatus
readCallback_ (const FlacNamespace::FLAC__StreamDecoder
*, FlacNamespace::FLAC__byte buffer
[], size_t* bytes
, void* client_data
)
248 using namespace FlacNamespace
;
249 *bytes
= (size_t) static_cast <const FlacReader
*> (client_data
)->input
->read (buffer
, (int) *bytes
);
250 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
;
253 static FlacNamespace::FLAC__StreamDecoderSeekStatus
seekCallback_ (const FlacNamespace::FLAC__StreamDecoder
*, FlacNamespace::FLAC__uint64 absolute_byte_offset
, void* client_data
)
255 using namespace FlacNamespace
;
256 static_cast <const FlacReader
*> (client_data
)->input
->setPosition ((int) absolute_byte_offset
);
257 return FLAC__STREAM_DECODER_SEEK_STATUS_OK
;
260 static FlacNamespace::FLAC__StreamDecoderTellStatus
tellCallback_ (const FlacNamespace::FLAC__StreamDecoder
*, FlacNamespace::FLAC__uint64
* absolute_byte_offset
, void* client_data
)
262 using namespace FlacNamespace
;
263 *absolute_byte_offset
= static_cast <const FlacReader
*> (client_data
)->input
->getPosition();
264 return FLAC__STREAM_DECODER_TELL_STATUS_OK
;
267 static FlacNamespace::FLAC__StreamDecoderLengthStatus
lengthCallback_ (const FlacNamespace::FLAC__StreamDecoder
*, FlacNamespace::FLAC__uint64
* stream_length
, void* client_data
)
269 using namespace FlacNamespace
;
270 *stream_length
= static_cast <const FlacReader
*> (client_data
)->input
->getTotalLength();
271 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK
;
274 static FlacNamespace::FLAC__bool
eofCallback_ (const FlacNamespace::FLAC__StreamDecoder
*, void* client_data
)
276 return static_cast <const FlacReader
*> (client_data
)->input
->isExhausted();
279 static FlacNamespace::FLAC__StreamDecoderWriteStatus
writeCallback_ (const FlacNamespace::FLAC__StreamDecoder
*,
280 const FlacNamespace::FLAC__Frame
* frame
,
281 const FlacNamespace::FLAC__int32
* const buffer
[],
284 using namespace FlacNamespace
;
285 static_cast <FlacReader
*> (client_data
)->useSamples (buffer
, frame
->header
.blocksize
);
286 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
289 static void metadataCallback_ (const FlacNamespace::FLAC__StreamDecoder
*,
290 const FlacNamespace::FLAC__StreamMetadata
* metadata
,
293 static_cast <FlacReader
*> (client_data
)->useMetadata (metadata
->data
.stream_info
);
296 static void errorCallback_ (const FlacNamespace::FLAC__StreamDecoder
*, FlacNamespace::FLAC__StreamDecoderErrorStatus
, void*)
301 FlacNamespace::FLAC__StreamDecoder
* decoder
;
302 AudioSampleBuffer reservoir
;
303 int reservoirStart
, samplesInReservoir
;
304 bool ok
, scanningForLength
;
306 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacReader
);
310 //==============================================================================
311 class FlacWriter
: public AudioFormatWriter
314 //==============================================================================
315 FlacWriter (OutputStream
* const out
, double sampleRate_
,
316 int numChannels_
, int bitsPerSample_
, int qualityOptionIndex
)
317 : AudioFormatWriter (out
, TRANS (flacFormatName
),
318 sampleRate_
, numChannels_
, bitsPerSample_
)
320 using namespace FlacNamespace
;
321 encoder
= FLAC__stream_encoder_new();
323 if (qualityOptionIndex
> 0)
324 FLAC__stream_encoder_set_compression_level (encoder
, jmin (8, qualityOptionIndex
));
326 FLAC__stream_encoder_set_do_mid_side_stereo (encoder
, numChannels
== 2);
327 FLAC__stream_encoder_set_loose_mid_side_stereo (encoder
, numChannels
== 2);
328 FLAC__stream_encoder_set_channels (encoder
, numChannels
);
329 FLAC__stream_encoder_set_bits_per_sample (encoder
, jmin ((unsigned int) 24, bitsPerSample
));
330 FLAC__stream_encoder_set_sample_rate (encoder
, (unsigned int) sampleRate
);
331 FLAC__stream_encoder_set_blocksize (encoder
, 0);
332 FLAC__stream_encoder_set_do_escape_coding (encoder
, true);
334 ok
= FLAC__stream_encoder_init_stream (encoder
,
335 encodeWriteCallback
, encodeSeekCallback
,
336 encodeTellCallback
, encodeMetadataCallback
,
337 this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK
;
344 FlacNamespace::FLAC__stream_encoder_finish (encoder
);
349 output
= 0; // to stop the base class deleting this, as it needs to be returned
350 // to the caller of createWriter()
353 FlacNamespace::FLAC__stream_encoder_delete (encoder
);
356 //==============================================================================
357 bool write (const int** samplesToWrite
, int numSamples
)
359 using namespace FlacNamespace
;
363 HeapBlock
<int*> channels
;
365 const int bitsToShift
= 32 - bitsPerSample
;
369 temp
.malloc (numSamples
* numChannels
);
370 channels
.calloc (numChannels
+ 1);
372 for (unsigned int i
= 0; i
< numChannels
; ++i
)
374 if (samplesToWrite
[i
] == nullptr)
377 int* const destData
= temp
.getData() + i
* numSamples
;
378 channels
[i
] = destData
;
380 for (int j
= 0; j
< numSamples
; ++j
)
381 destData
[j
] = (samplesToWrite
[i
][j
] >> bitsToShift
);
384 samplesToWrite
= const_cast<const int**> (channels
.getData());
387 return FLAC__stream_encoder_process (encoder
, (const FLAC__int32
**) samplesToWrite
, numSamples
) != 0;
390 bool writeData (const void* const data
, const int size
) const
392 return output
->write (data
, size
);
395 static void packUint32 (FlacNamespace::FLAC__uint32 val
, FlacNamespace::FLAC__byte
* b
, const int bytes
)
399 for (int i
= 0; i
< bytes
; ++i
)
401 *(--b
) = (FlacNamespace::FLAC__byte
) (val
& 0xff);
406 void writeMetaData (const FlacNamespace::FLAC__StreamMetadata
* metadata
)
408 using namespace FlacNamespace
;
409 const FLAC__StreamMetadata_StreamInfo
& info
= metadata
->data
.stream_info
;
411 unsigned char buffer
[FLAC__STREAM_METADATA_STREAMINFO_LENGTH
];
412 const unsigned int channelsMinus1
= info
.channels
- 1;
413 const unsigned int bitsMinus1
= info
.bits_per_sample
- 1;
415 packUint32 (info
.min_blocksize
, buffer
, 2);
416 packUint32 (info
.max_blocksize
, buffer
+ 2, 2);
417 packUint32 (info
.min_framesize
, buffer
+ 4, 3);
418 packUint32 (info
.max_framesize
, buffer
+ 7, 3);
419 buffer
[10] = (uint8
) ((info
.sample_rate
>> 12) & 0xff);
420 buffer
[11] = (uint8
) ((info
.sample_rate
>> 4) & 0xff);
421 buffer
[12] = (uint8
) (((info
.sample_rate
& 0x0f) << 4) | (channelsMinus1
<< 1) | (bitsMinus1
>> 4));
422 buffer
[13] = (FLAC__byte
) (((bitsMinus1
& 0x0f) << 4) | (unsigned int) ((info
.total_samples
>> 32) & 0x0f));
423 packUint32 ((FLAC__uint32
) info
.total_samples
, buffer
+ 14, 4);
424 memcpy (buffer
+ 18, info
.md5sum
, 16);
426 const bool seekOk
= output
->setPosition (4);
429 // if this fails, you've given it an output stream that can't seek! It needs
430 // to be able to seek back to write the header
433 output
->writeIntBigEndian (FLAC__STREAM_METADATA_STREAMINFO_LENGTH
);
434 output
->write (buffer
, FLAC__STREAM_METADATA_STREAMINFO_LENGTH
);
437 //==============================================================================
438 static FlacNamespace::FLAC__StreamEncoderWriteStatus
encodeWriteCallback (const FlacNamespace::FLAC__StreamEncoder
*,
439 const FlacNamespace::FLAC__byte buffer
[],
441 unsigned int /*samples*/,
442 unsigned int /*current_frame*/,
445 using namespace FlacNamespace
;
446 return static_cast <FlacWriter
*> (client_data
)->writeData (buffer
, (int) bytes
)
447 ? FLAC__STREAM_ENCODER_WRITE_STATUS_OK
448 : FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR
;
451 static FlacNamespace::FLAC__StreamEncoderSeekStatus
encodeSeekCallback (const FlacNamespace::FLAC__StreamEncoder
*, FlacNamespace::FLAC__uint64
, void*)
453 using namespace FlacNamespace
;
454 return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
;
457 static FlacNamespace::FLAC__StreamEncoderTellStatus
encodeTellCallback (const FlacNamespace::FLAC__StreamEncoder
*, FlacNamespace::FLAC__uint64
* absolute_byte_offset
, void* client_data
)
459 using namespace FlacNamespace
;
460 if (client_data
== 0)
461 return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
;
463 *absolute_byte_offset
= (FLAC__uint64
) static_cast <FlacWriter
*> (client_data
)->output
->getPosition();
464 return FLAC__STREAM_ENCODER_TELL_STATUS_OK
;
467 static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder
*, const FlacNamespace::FLAC__StreamMetadata
* metadata
, void* client_data
)
469 static_cast <FlacWriter
*> (client_data
)->writeMetaData (metadata
);
475 FlacNamespace::FLAC__StreamEncoder
* encoder
;
477 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FlacWriter
);
481 //==============================================================================
482 FlacAudioFormat::FlacAudioFormat()
483 : AudioFormat (TRANS (flacFormatName
), StringArray (flacExtensions
))
487 FlacAudioFormat::~FlacAudioFormat()
491 const Array
<int> FlacAudioFormat::getPossibleSampleRates()
493 const int rates
[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000, 0 };
494 return Array
<int> (rates
);
497 const Array
<int> FlacAudioFormat::getPossibleBitDepths()
499 const int depths
[] = { 16, 24, 0 };
500 return Array
<int> (depths
);
503 bool FlacAudioFormat::canDoStereo() { return true; }
504 bool FlacAudioFormat::canDoMono() { return true; }
505 bool FlacAudioFormat::isCompressed() { return true; }
507 AudioFormatReader
* FlacAudioFormat::createReaderFor (InputStream
* in
,
508 const bool deleteStreamIfOpeningFails
)
510 ScopedPointer
<FlacReader
> r (new FlacReader (in
));
512 if (r
->sampleRate
> 0)
515 if (! deleteStreamIfOpeningFails
)
521 AudioFormatWriter
* FlacAudioFormat::createWriterFor (OutputStream
* out
,
523 unsigned int numberOfChannels
,
525 const StringPairArray
& /*metadataValues*/,
526 int qualityOptionIndex
)
528 if (getPossibleBitDepths().contains (bitsPerSample
))
530 ScopedPointer
<FlacWriter
> w (new FlacWriter (out
, sampleRate
, numberOfChannels
, bitsPerSample
, qualityOptionIndex
));
539 StringArray
FlacAudioFormat::getQualityOptions()
541 const char* options
[] = { "0 (Fastest)", "1", "2", "3", "4", "5 (Default)","6", "7", "8 (Highest quality)", 0 };
542 return StringArray (options
);