pedalboard/juce_overrides/juce_PatchedFLACAudioFormat.cpp (454 lines of code) (raw):
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include "juce_PatchedFLACAudioFormat.h"
#if defined _WIN32 && !defined __CYGWIN__
#include <io.h>
#else
#include <unistd.h>
#endif
#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
#include <sys/types.h> /* for off_t */
#endif
#if HAVE_INTTYPES_H
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#endif
#if defined _MSC_VER || defined __MINGW32__ || defined __CYGWIN__ || \
defined __EMX__
#include <fcntl.h> /* for _O_BINARY */
#include <io.h> /* for _setmode(), chmod() */
#else
#include <unistd.h> /* for chown(), unlink() */
#endif
#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
#if defined __BORLANDC__
#include <utime.h> /* for utime() */
#else
#include <sys/utime.h> /* for utime() */
#endif
#else
#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
#include <utime.h> /* for utime() */
#endif
#if defined _MSC_VER
#if _MSC_VER >= 1600
#include <stdint.h>
#else
#include <limits.h>
#endif
#endif
#ifdef _WIN32
#include <stdarg.h>
#include <stdio.h>
#include <sys/stat.h>
#include <windows.h>
#endif
#ifdef DEBUG
#include <assert.h>
#endif
#include <stdio.h>
#include <stdlib.h>
namespace juce {
namespace PatchedFlacNamespace {
#if JUCE_INCLUDE_FLAC_CODE || !defined(JUCE_INCLUDE_FLAC_CODE)
#undef VERSION
#define VERSION "1.3.1"
#define FLAC__NO_DLL 1
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)
#if !JUCE_MSVC
#define HAVE_LROUND 1
#endif
#if JUCE_MAC
#define FLAC__SYS_DARWIN 1
#endif
#ifndef SIZE_MAX
#define SIZE_MAX 0xffffffff
#endif
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE("-Wconversion", "-Wshadow",
"-Wdeprecated-register", "-Wswitch-enum",
"-Wswitch-default",
"-Wimplicit-fallthrough",
"-Wzero-as-null-pointer-constant",
"-Wsign-conversion", "-Wredundant-decls",
"-Wlanguage-extension-token")
#if JUCE_INTEL
#if JUCE_32BIT
#define FLAC__CPU_IA32 1
#endif
#if JUCE_64BIT
#define FLAC__CPU_X86_64 1
#endif
#define FLAC__HAS_X86INTRIN 1
#endif
#undef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#define flac_max jmax
#define flac_min jmin
#undef DEBUG // (some flac code dumps debug trace if the app defines this macro)
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/all.h"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/bitmath.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/bitreader.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/bitwriter.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/cpu.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/crc.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/fixed.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/float.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/format.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/lpc_flac.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/md5.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/memory.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/stream_decoder.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/stream_encoder.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/stream_encoder_framing.c"
#include "../../JUCE/modules/juce_audio_formats/codecs/flac/libFLAC/window_flac.c"
#include "../../vendors/libFLAC/metadata_object.c"
#undef VERSION
#else
#include <FLAC/all.h>
#endif
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
JUCE_END_IGNORE_WARNINGS_MSVC
} // namespace PatchedFlacNamespace
#undef max
#undef min
//==============================================================================
static const char *const flacFormatName = "FLAC file";
template <typename Item> auto emptyRange(Item item) {
return Range<Item>::emptyRange(item);
}
//==============================================================================
class PatchedFlacReader : public AudioFormatReader {
public:
PatchedFlacReader(InputStream *in) : AudioFormatReader(in, flacFormatName) {
lengthInSamples = 0;
decoder = PatchedFlacNamespace::FLAC__stream_decoder_new();
ok = FLAC__stream_decoder_init_stream(
decoder, readCallback_, seekCallback_, tellCallback_,
lengthCallback_, eofCallback_, writeCallback_, metadataCallback_,
errorCallback_,
this) == PatchedFlacNamespace::FLAC__STREAM_DECODER_INIT_STATUS_OK;
if (ok) {
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
if (lengthInSamples == 0 && sampleRate > 0) {
// the length hasn't been stored in the metadata, so we'll need to
// work it out the length the hard way, by scanning the whole file..
scanningForLength = true;
FLAC__stream_decoder_process_until_end_of_stream(decoder);
scanningForLength = false;
auto tempLength = lengthInSamples;
FLAC__stream_decoder_reset(decoder);
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
lengthInSamples = tempLength;
}
}
}
~PatchedFlacReader() override {
PatchedFlacNamespace::FLAC__stream_decoder_delete(decoder);
}
void useMetadata(
const PatchedFlacNamespace::FLAC__StreamMetadata_StreamInfo &info) {
sampleRate = info.sample_rate;
bitsPerSample = info.bits_per_sample;
lengthInSamples = (unsigned int)info.total_samples;
numChannels = info.channels;
reservoir.setSize((int)numChannels, 2 * (int)info.max_blocksize, false,
false, true);
}
bool readSamples(int **destSamples, int numDestChannels,
int startOffsetInDestBuffer, int64 startSampleInFile,
int numSamples) override {
if (!ok)
return false;
const auto getBufferedRange = [this] { return bufferedRange; };
const auto readFromReservoir =
[this, &destSamples, &numDestChannels, &startOffsetInDestBuffer,
&startSampleInFile](const Range<int64> rangeToRead) {
const auto bufferIndices = rangeToRead - bufferedRange.getStart();
const auto writePos = (int64)startOffsetInDestBuffer +
(rangeToRead.getStart() - startSampleInFile);
for (int i = jmin(numDestChannels, reservoir.getNumChannels());
--i >= 0;) {
if (destSamples[i] != nullptr) {
memcpy(destSamples[i] + writePos,
reservoir.getReadPointer(i) + bufferIndices.getStart(),
(size_t)bufferIndices.getLength() * sizeof(int));
}
}
};
const auto fillReservoir = [this](const int64 requestedStart) {
if (requestedStart >= lengthInSamples) {
bufferedRange = emptyRange(requestedStart);
return;
}
if (requestedStart < bufferedRange.getStart() ||
requestedStart > bufferedRange.getEnd()) {
bufferedRange = emptyRange(requestedStart);
FLAC__stream_decoder_seek_absolute(
decoder,
(PatchedFlacNamespace::FLAC__uint64)bufferedRange.getStart());
return;
}
bufferedRange = emptyRange(bufferedRange.getEnd());
FLAC__stream_decoder_process_single(decoder);
};
const auto remainingSamples = Reservoir::doBufferedRead(
Range<int64>{startSampleInFile, startSampleInFile + numSamples},
getBufferedRange, readFromReservoir, fillReservoir);
if (!remainingSamples.isEmpty())
for (int i = numDestChannels; --i >= 0;)
if (destSamples[i] != nullptr)
zeromem(destSamples[i] + startOffsetInDestBuffer,
(size_t)remainingSamples.getLength() * sizeof(int));
return true;
}
void useSamples(const PatchedFlacNamespace::FLAC__int32 *const buffer[],
int numSamples) {
if (scanningForLength) {
lengthInSamples += numSamples;
} else {
if (numSamples > reservoir.getNumSamples())
reservoir.setSize((int)numChannels, numSamples, false, false, true);
auto bitsToShift = 32 - bitsPerSample;
for (int i = 0; i < (int)numChannels; ++i) {
auto *src = buffer[i];
int n = i;
while (src == nullptr && n > 0)
src = buffer[--n];
if (src != nullptr) {
auto *dest = reinterpret_cast<int *>(reservoir.getWritePointer(i));
for (int j = 0; j < numSamples; ++j)
dest[j] = src[j] << bitsToShift;
}
}
bufferedRange.setLength(numSamples);
}
}
//==============================================================================
static PatchedFlacNamespace::FLAC__StreamDecoderReadStatus
readCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
PatchedFlacNamespace::FLAC__byte buffer[], size_t *bytes,
void *client_data) {
*bytes = (size_t) static_cast<const PatchedFlacReader *>(client_data)
->input->read(buffer, (int)*bytes);
return PatchedFlacNamespace::FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
static PatchedFlacNamespace::FLAC__StreamDecoderSeekStatus
seekCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
PatchedFlacNamespace::FLAC__uint64 absolute_byte_offset,
void *client_data) {
static_cast<const PatchedFlacReader *>(client_data)
->input->setPosition((int)absolute_byte_offset);
return PatchedFlacNamespace::FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
static PatchedFlacNamespace::FLAC__StreamDecoderTellStatus
tellCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
PatchedFlacNamespace::FLAC__uint64 *absolute_byte_offset,
void *client_data) {
*absolute_byte_offset =
(uint64) static_cast<const PatchedFlacReader *>(client_data)
->input->getPosition();
return PatchedFlacNamespace::FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
static PatchedFlacNamespace::FLAC__StreamDecoderLengthStatus
lengthCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
PatchedFlacNamespace::FLAC__uint64 *stream_length,
void *client_data) {
*stream_length =
(uint64) static_cast<const PatchedFlacReader *>(client_data)
->input->getTotalLength();
return PatchedFlacNamespace::FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
static PatchedFlacNamespace::FLAC__bool
eofCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
void *client_data) {
return static_cast<const PatchedFlacReader *>(client_data)
->input->isExhausted();
}
static PatchedFlacNamespace::FLAC__StreamDecoderWriteStatus
writeCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
const PatchedFlacNamespace::FLAC__Frame *frame,
const PatchedFlacNamespace::FLAC__int32 *const buffer[],
void *client_data) {
static_cast<PatchedFlacReader *>(client_data)
->useSamples(buffer, (int)frame->header.blocksize);
return PatchedFlacNamespace::FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void
metadataCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
const PatchedFlacNamespace::FLAC__StreamMetadata *metadata,
void *client_data) {
static_cast<PatchedFlacReader *>(client_data)
->useMetadata(metadata->data.stream_info);
}
static void
errorCallback_(const PatchedFlacNamespace::FLAC__StreamDecoder *,
PatchedFlacNamespace::FLAC__StreamDecoderErrorStatus, void *) {
}
private:
PatchedFlacNamespace::FLAC__StreamDecoder *decoder;
AudioBuffer<float> reservoir;
Range<int64> bufferedRange;
bool ok = false, scanningForLength = false;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PatchedFlacReader)
};
//==============================================================================
class PatchedFlacWriter : public AudioFormatWriter {
public:
PatchedFlacWriter(OutputStream *out, double rate, uint32 numChans,
uint32 bits, int qualityOptionIndex)
: AudioFormatWriter(out, flacFormatName, rate, numChans, bits),
streamStartPos(output != nullptr ? jmax(output->getPosition(), 0ll)
: 0ll) {
encoder = PatchedFlacNamespace::FLAC__stream_encoder_new();
if (qualityOptionIndex > 0)
FLAC__stream_encoder_set_compression_level(
encoder, (uint32)jmin(8, qualityOptionIndex));
FLAC__stream_encoder_set_do_mid_side_stereo(encoder, numChannels == 2);
FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, numChannels == 2);
FLAC__stream_encoder_set_channels(encoder, numChannels);
FLAC__stream_encoder_set_bits_per_sample(
encoder, jmin((unsigned int)24, bitsPerSample));
FLAC__stream_encoder_set_sample_rate(encoder, (unsigned int)sampleRate);
FLAC__stream_encoder_set_blocksize(encoder, 0);
FLAC__stream_encoder_set_do_escape_coding(encoder, true);
// Create a seek table, which is empty by default:
seektable = PatchedFlacNamespace::FLAC__metadata_object_new(
PatchedFlacNamespace::FLAC__METADATA_TYPE_SEEKTABLE);
if (!seektable)
return;
// Write a single placeholder to the seek table.
if (!PatchedFlacNamespace::
FLAC__metadata_object_seektable_template_append_placeholders(
seektable, /* number of placeholder elements */ 1))
return;
if (!PatchedFlacNamespace::FLAC__metadata_object_seektable_template_sort(
seektable, /*compact=*/true))
return;
if (!PatchedFlacNamespace::FLAC__stream_encoder_set_metadata(
encoder, &seektable, 1)) {
return;
}
ok = FLAC__stream_encoder_init_stream(encoder, encodeWriteCallback,
encodeSeekCallback,
encodeTellCallback, nullptr, this) ==
PatchedFlacNamespace::FLAC__STREAM_ENCODER_INIT_STATUS_OK;
}
~PatchedFlacWriter() override {
if (ok) {
PatchedFlacNamespace::FLAC__stream_encoder_finish(encoder);
output->flush();
} else {
output = nullptr; // to stop the base class deleting this, as it needs to
// be returned to the caller of createWriter()
}
PatchedFlacNamespace::FLAC__stream_encoder_delete(encoder);
if (seektable) {
PatchedFlacNamespace::FLAC__metadata_object_delete(seektable);
seektable = nullptr;
}
}
//==============================================================================
bool write(const int **samplesToWrite, int numSamples) override {
if (!ok)
return false;
HeapBlock<int *> channels;
HeapBlock<int> temp;
auto bitsToShift = 32 - (int)bitsPerSample;
if (bitsToShift > 0) {
temp.malloc(numChannels * (size_t)numSamples);
channels.calloc(numChannels + 1);
for (unsigned int i = 0; i < numChannels; ++i) {
if (samplesToWrite[i] == nullptr)
break;
auto *destData = temp.get() + i * (size_t)numSamples;
channels[i] = destData;
for (int j = 0; j < numSamples; ++j)
destData[j] = (samplesToWrite[i][j] >> bitsToShift);
}
samplesToWrite = const_cast<const int **>(channels.get());
}
return FLAC__stream_encoder_process(
encoder,
(const PatchedFlacNamespace::FLAC__int32 **)samplesToWrite,
(unsigned)numSamples) != 0;
}
bool writeData(const void *const data, const int size) const {
return output->write(data, (size_t)size);
}
static void packUint32(PatchedFlacNamespace::FLAC__uint32 val,
PatchedFlacNamespace::FLAC__byte *b, const int bytes) {
b += bytes;
for (int i = 0; i < bytes; ++i) {
*(--b) = (PatchedFlacNamespace::FLAC__byte)(val & 0xff);
val >>= 8;
}
}
//==============================================================================
static PatchedFlacNamespace::FLAC__StreamEncoderWriteStatus
encodeWriteCallback(const PatchedFlacNamespace::FLAC__StreamEncoder *,
const PatchedFlacNamespace::FLAC__byte buffer[],
size_t bytes, unsigned int /*samples*/,
unsigned int /*current_frame*/, void *client_data) {
return static_cast<PatchedFlacWriter *>(client_data)
->writeData(buffer, (int)bytes)
? PatchedFlacNamespace::FLAC__STREAM_ENCODER_WRITE_STATUS_OK
: PatchedFlacNamespace::
FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
static PatchedFlacNamespace::FLAC__StreamEncoderSeekStatus
encodeSeekCallback(const PatchedFlacNamespace::FLAC__StreamEncoder *,
PatchedFlacNamespace::FLAC__uint64 position,
void *client_data) {
if (client_data == nullptr)
return PatchedFlacNamespace::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
auto *writer = static_cast<PatchedFlacWriter *>(client_data);
return writer->output->setPosition(writer->streamStartPos + position)
? PatchedFlacNamespace::FLAC__STREAM_ENCODER_SEEK_STATUS_OK
: PatchedFlacNamespace::FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
}
static PatchedFlacNamespace::FLAC__StreamEncoderTellStatus
encodeTellCallback(const PatchedFlacNamespace::FLAC__StreamEncoder *,
PatchedFlacNamespace::FLAC__uint64 *absolute_byte_offset,
void *client_data) {
if (client_data == nullptr)
return PatchedFlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
auto *writer = static_cast<PatchedFlacWriter *>(client_data);
*absolute_byte_offset =
(PatchedFlacNamespace::FLAC__uint64)writer->output->getPosition() -
writer->streamStartPos;
return PatchedFlacNamespace::FLAC__STREAM_ENCODER_TELL_STATUS_OK;
}
bool ok = false;
private:
PatchedFlacNamespace::FLAC__StreamEncoder *encoder;
PatchedFlacNamespace::FLAC__StreamMetadata *seektable;
int64 streamStartPos;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PatchedFlacWriter)
};
//==============================================================================
PatchedFlacAudioFormat::PatchedFlacAudioFormat()
: AudioFormat(flacFormatName, ".flac") {}
PatchedFlacAudioFormat::~PatchedFlacAudioFormat() {}
Array<int> PatchedFlacAudioFormat::getPossibleSampleRates() {
return {8000, 11025, 12000, 16000, 22050, 32000, 44100,
48000, 88200, 96000, 176400, 192000, 352800, 384000};
}
Array<int> PatchedFlacAudioFormat::getPossibleBitDepths() { return {16, 24}; }
bool PatchedFlacAudioFormat::canDoStereo() { return true; }
bool PatchedFlacAudioFormat::canDoMono() { return true; }
bool PatchedFlacAudioFormat::isCompressed() { return true; }
AudioFormatReader *
PatchedFlacAudioFormat::createReaderFor(InputStream *in,
const bool deleteStreamIfOpeningFails) {
std::unique_ptr<PatchedFlacReader> r(new PatchedFlacReader(in));
if (r->sampleRate > 0)
return r.release();
if (!deleteStreamIfOpeningFails)
r->input = nullptr;
return nullptr;
}
AudioFormatWriter *PatchedFlacAudioFormat::createWriterFor(
OutputStream *out, double sampleRate, unsigned int numberOfChannels,
int bitsPerSample, const StringPairArray & /*metadataValues*/,
int qualityOptionIndex) {
if (out != nullptr && getPossibleBitDepths().contains(bitsPerSample)) {
std::unique_ptr<PatchedFlacWriter> w(
new PatchedFlacWriter(out, sampleRate, numberOfChannels,
(uint32)bitsPerSample, qualityOptionIndex));
if (w->ok)
return w.release();
}
return nullptr;
}
StringArray PatchedFlacAudioFormat::getQualityOptions() {
return {"0 (Fastest)", "1", "2", "3", "4", "5 (Default)", "6", "7",
"8 (Highest quality)"};
}
} // namespace juce