diff --git a/lib/libfoxenflac/flac.c b/lib/libfoxenflac/flac.c
deleted file mode 100644
index d4030e11..00000000
--- a/lib/libfoxenflac/flac.c
+++ /dev/null
@@ -1,2022 +0,0 @@
-/*
- * libfoxenflac -- Tiny FLAC Decoder Library
- * Copyright (C) 2018-2022 Andreas Stöckel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include
-#include
-#include
-#include
-
-#include
-
-#if 0
-/* Set FX_FLAC_NO_CRC if you control the input data and already performed other
- integrity checks. This makes the decoder significantly faster. */
-#define FX_FLAC_NO_CRC
-#endif
-
-/******************************************************************************
- * CODE MERGED FROM OTHER LIBFOXEN PROJECTS *
- ******************************************************************************/
-
-/******************************************************************************
- * Copy of foxen/bitstream.h *
- ******************************************************************************/
-
-/**
- * Structure holding the current state of the bitstream reader.
- */
-struct fx_bitstream {
- /**
- * 64 bit word from which the data is extracted.
- */
- uint64_t buf;
-
- /**
- * Pointer at the source byte stream.
- */
- uint8_t const *src;
-
- /**
- * Pointer at the end of the source byte stream.
- */
- uint8_t const *src_end;
-
- /**
- * Position within the source byte stream in bits, i.e. the number of bits
- * that have been consumed.
- */
- uint8_t pos;
-};
-
-/**
- * Typedef for the fx_bitstream struct.
- */
-typedef struct fx_bitstream fx_bitstream_t;
-
-/**
- * Callback called whenever a fully byte has been consumed. This is useful for
- * CRC calculations.
- */
-typedef void (*fx_bitstream_byte_callback_t)(uint8_t byte, void *data);
-
-/**
- * Initializes the bitstream reader instance. Call fx_bitstream_set_source()
- * to set the byte buffer from which the bitstream reader should read its
- * data.
- *
- * @param reader is the bitstream reader instance that should be
- * initialized.
- */
-static inline void fx_bitstream_init(fx_bitstream_t *reader) {
- reader->buf = 0U;
- reader->pos = sizeof(reader->buf) * 8U;
- reader->src = NULL;
- reader->src_end = NULL;
-}
-
-/**
- * Sets the backing source buffer for the bitstream. This function may only be
- * called if the given pointer is a direct continuation of the previous data,
- * i.e. are essentially set to reader->src.
- *
- * @param reader is the bitstream reader instance for which the source byte
- * buffer should be set.
- * @param src is a pointer at the source byte buffer.
- * @param src_len is the length of the source byte buffer in bytes.
- */
-static inline void fx_bitstream_set_source(fx_bitstream_t *reader,
- const uint8_t *src,
- uint32_t src_len);
-
-/**
- * Returns true if the corresponding read operation will be successful.
- *
- * @param reader is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read from the bitstream
- * reader. Must be in 1 <= n_bits <= 57.
- * @return true if the number of available bits is smaller or equal to n_bits.
- */
-static inline bool fx_bitstream_can_read(fx_bitstream_t *reader,
- uint8_t n_bits) {
- return (sizeof(reader->buf) * 8U) >= (n_bits + reader->pos);
-}
-
-/**
- * Reads up to 64 bits from the input buffer in MSB order. Note that this
- * function does not check whether the read operation returns valid data, so
- * make sure to call fx_bitstream_can_read() before reading.
- *
- * @param reader is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read. Must be in
- * 1 <= n_bits <= 57.
- * @return an integer corresponding the the specified number of bits.
- */
-static inline uint64_t fx_bitstream_read_msb(fx_bitstream_t *reader,
- uint8_t n_bits);
-
-/**
- * Reads up to 64 bits from the input buffer in MSB order. Note that this
- * function does not check whether the read operation returns valid data, so
- * make sure to call fx_bitstream_can_read() before reading.
- *
- * @param reader is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read. Must be in
- * 1 <= n_bits <= 57.
- * @param callback is called whenever a full byte is consumed. Note that this
- * includes a "virtual" set of zeros at the beginning of the bitstream.
- * @param callback_data is a user-defined pointer passed to the byte callback.
- * @return an integer corresponding the the specified number of bits.
- */
-static inline uint64_t fx_bitstream_read_msb_ex(
- fx_bitstream_t *reader, uint8_t n_bits,
- fx_bitstream_byte_callback_t callback, void *callback_data);
-
-/**
- * Reads up to 64 bits from the input buffer in MSB order without advancing the
- * buffer location. Note that this function does not check whether the read
- * operation returns valid data, so make sure to call fx_bitstream_can_read()
- * before reading.
- *
- * @param reader is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read. Must be in
- * 1 <= n_bits <= 57.
- * @return an integer corresponding to the specified number of bits.
- */
-static inline uint64_t fx_bitstream_peek_msb(fx_bitstream_t *reader,
- uint8_t n_bits);
-
-/**
- * Combination of fx_bitstream_can_read and fx_bitstream_read_msb. Returns a
- * negative value if the desired number of bits cannot be read from the source.
- * If the given number of threads are available, returns the desired integer.
- *
- * @param reads is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read. Must be in
- * 1 <= n_bits <= 57.
- * @return -1 if the desired number of bits is not available in the bitstream.
- * Otherwise the integer corresponding to the specified number of bits is
- * returned.
- */
-static inline int64_t fx_bitstream_try_read_msb(fx_bitstream_t *reader,
- uint8_t n_bits) {
- return fx_bitstream_can_read(reader, n_bits)
- ? (int64_t)fx_bitstream_read_msb(reader, n_bits)
- : -1;
-}
-
-/**
- * Combination of fx_bitstream_can_read and fx_bitstream_read_msb. Returns a
- * negative value if the desired number of bits cannot be read from the source.
- * If the given number of threads are available, returns the desired integer.
- *
- * @param reads is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read. Must be in
- * 1 <= n_bits <= 57.
- * @param callback is called whenever a full byte is consumed. Note that this
- * includes a "virtual" set of zeros at the beginning of the bitstream.
- * @param callback_data is a user-defined pointer passed to the byte callback.
- * @return -1 if the desired number of bits is not available in the bitstream.
- * Otherwise the integer corresponding to the specified number of bits is
- * returned.
- */
-static inline int64_t fx_bitstream_try_read_msb_ex(
- fx_bitstream_t *reader, uint8_t n_bits,
- fx_bitstream_byte_callback_t callback, void *callback_data) {
- return fx_bitstream_can_read(reader, n_bits)
- ? (int64_t)fx_bitstream_read_msb_ex(reader, n_bits, callback,
- callback_data)
- : -1;
-}
-
-/**
- * Combination of fx_bitstream_can_read and fx_bitstream_peek. Returns a
- * negative value if the desired number of bits cannot be read from the source.
- * If the given number of threads are available, returns the desired integer.
- * In contrast to fx_bitstream_try_read_msb() this function does not advance
- * the actual reader pointer.
- *
- * @param reads is the bitstream reader instance from which the data should be
- * read.
- * @param n_bits is the number of bits that should be read. Must be in
- * 1 <= n_bits <= 57.
- * @return -1 if the desired number of bits is not available in the bitstream.
- * Otherwise the integer corresponding to the specified number of bits is
- * returned.
- */
-static inline int64_t fx_bitstream_try_peek_msb(fx_bitstream_t *reader,
- uint8_t n_bits) {
- return fx_bitstream_can_read(reader, n_bits)
- ? (int64_t)fx_bitstream_peek_msb(reader, n_bits)
- : -1;
-}
-
-#define BUFSIZE (sizeof(((fx_bitstream_t *)NULL)->buf) * 8U)
-
-static inline void _fx_bitstream_fill_buf(fx_bitstream_t *reader) {
- while (reader->pos >= 8U && reader->src != reader->src_end) {
- reader->buf = (reader->buf << 8U) | *(reader->src++);
- reader->pos -= 8U;
- }
-}
-
-static inline uint64_t _fx_bitstream_read_msb(
- fx_bitstream_t *reader, uint8_t n_bits,
- fx_bitstream_byte_callback_t callback, void *callback_data) {
- assert((n_bits >= 1U) && (n_bits <= (BUFSIZE - 7U)));
-
- /* Copy the current buffer content, skip already read bits */
- uint64_t bits = reader->buf << reader->pos;
-
- /* If the callback is specified, issue bytes that were read entirely */
- const uint8_t pos_new = reader->pos + n_bits;
- if (callback) {
- const uint8_t i0 = reader->pos / 8U, i1 = pos_new / 8U;
- uint64_t buf = reader->buf << (i0 * 8U);
- for (uint8_t i = i0; i < i1; i++) {
- uint8_t byte = buf >> (BUFSIZE - 8U);
- callback(byte, callback_data);
- buf = buf << 8U;
- }
- }
-
- /* Advance the position */
- reader->pos = pos_new;
-
- /* Read new bytes from the byte stream */
- _fx_bitstream_fill_buf(reader);
-
- /* Mask out the "low" bits */
- return bits >> (BUFSIZE - n_bits);
-}
-
-static inline void fx_bitstream_set_source(fx_bitstream_t *reader,
- const uint8_t *src,
- uint32_t src_len) {
- reader->src = src;
- reader->src_end = src + src_len;
- _fx_bitstream_fill_buf(reader);
-}
-
-static inline uint64_t fx_bitstream_read_msb(fx_bitstream_t *reader,
- uint8_t n_bits) {
- return _fx_bitstream_read_msb(reader, n_bits, NULL, NULL);
-}
-
-static inline uint64_t fx_bitstream_read_msb_ex(
- fx_bitstream_t *reader, uint8_t n_bits,
- fx_bitstream_byte_callback_t callback, void *callback_data) {
- return _fx_bitstream_read_msb(reader, n_bits, callback, callback_data);
-}
-
-static inline uint64_t fx_bitstream_peek_msb(fx_bitstream_t *reader,
- uint8_t n_bits) {
- assert((n_bits >= 1U) && (n_bits <= (BUFSIZE - 7U)));
- return (reader->buf << reader->pos) >> (BUFSIZE - n_bits);
-}
-
-/******************************************************************************
- * Copy of foxen/mem.h *
- ******************************************************************************/
-
-/**
- * Memory alignment for pointers internally used by Stanchion. Aligning memory
- * and telling the compiler about it allows the compiler to perform better
- * optimization. Furthermore, some platforms (WASM) do not allow unaligned
- * memory access.
- */
-#define FX_ALIGN 1
-
-/**
- * Macro telling the compiler that P is aligned with the specified alignment
- * ALIGN.
- */
-#define FX_ASSUME_ALIGNED_EX(P, ALIGN) P
-#ifdef __GNUC__
-#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4)
-#undef FX_ASSUME_ALIGNED_EX
-#define FX_ASSUME_ALIGNED_EX(P, ALIGN) (__builtin_assume_aligned(P, ALIGN))
-#endif /* (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) */
-#endif /* __GNUC__ */
-
-/**
- * Macro telling the compiler that P is aligned with the alignment defined
- * above.
- */
-#define FX_ASSUME_ALIGNED(P) FX_ASSUME_ALIGNED_EX(P, FX_ALIGN)
-
-/**
- * Forces a pointer to have the specified alignment.
- */
-#define FX_ALIGN_ADDR_EX(P, ALIGN) \
- (FX_ASSUME_ALIGNED_EX( \
- (void *)(((uintptr_t)(P) + ALIGN - 1) & (~(uintptr_t)(ALIGN - 1))), \
- ALIGN))
-
-/**
- * Forces a pointer to have the alignment defined above.
- */
-#define FX_ALIGN_ADDR(P) FX_ALIGN_ADDR_EX(P, FX_ALIGN)
-
-/**
- * Macro that fills the structure pointed at by P with zeros. See
- * fx_mem_zero_aligned() regarding potential dangers.
- */
-#define FX_MEM_ZERO_ALIGNED(P) \
- do { \
- fx_mem_zero_aligned(P, sizeof(*(P))); \
- } while (0)
-
-/**
- * Call this first in a chain of fx_mem_update_size() calls. It will make sure
- * that there is enough space to align the datastructure whenever the user
- * provides a non-aligned target memory pointer.
- *
- * @param size is a pointer at a variable that holds the size of the object
- * that we're describing. This function initializes this value to FX_ALIGN - 1.
- * @return Always returns true to facilitate chaining with other fx_mem_*_size()
- * functions.
- */
-static inline bool fx_mem_init_size(uint32_t *size) {
- *size = FX_ALIGN;
- return true;
-}
-
-/**
- * Function used to compute the total size of a datastructure consisting of
- * multiple substructures. Calling this function updates the size of the outer
- * datastructure by adding a substructure of size n_bytes. Assumes that the
- * beginning of the substructure must be aligned to the given alignment.
- *
- * @param size is a pointer at the variable holding the size of the
- * datastructure. This must always be a multiple of FX_ALIGN.
- * @param n_bytes size of the sub-structure that should be added.
- * @return zero if there was an overflow, one otherwise.
- */
-static inline bool fx_mem_update_size_ex(uint32_t *size, uint32_t n_bytes,
- uint32_t align) {
- const uint32_t new_size = ((*size + n_bytes + align - 1) & (~(align - 1)));
- if (new_size < *size) {
- return false; /* error, there has been an overflow */
- }
- *size = new_size;
- return true; /* success */
-}
-
-/**
- * Function used to compute the total size of a datastructure consisting of
- * multiple substructures. Calling this function updates the size of the outer
- * datastructure by adding a substructure of size n_bytes. Assumes that the
- * beginning of the substructure must be aligned to the default alignment.
- *
- * @param size is a pointer at the variable holding the size of the
- * datastructure. This must always be a multiple of FX_ALIGN.
- * @param n_bytes size of the sub-structure that should be added.
- * @return zero if there was an overflow, one otherwise.
- */
-static inline bool fx_mem_update_size(uint32_t *size, uint32_t n_bytes) {
- return fx_mem_update_size_ex(size, n_bytes, FX_ALIGN);
-}
-
-/**
- * Computes the aligned pointer pointing at the substructure of the given size
- * for the specified alignment.
- *
- * @param mem pointer at the variable holding the pointer at the current
- * pointer. The pointer is advanced by the given size after the return value is
- * computed.
- * @param size is the size of the substructure for which the pointer should be
- * returned.
- * @param align is the memory alignment to use.
- * @return an aligned pointer pointing at the beginning of the substructure.
- */
-static inline void *fx_mem_align_ex(void **mem, uint32_t size, uint32_t align) {
- void *res = FX_ALIGN_ADDR_EX(*mem, align);
- *mem = (void *)((uintptr_t)res + size);
- return res;
-}
-
-/**
- * Computes the default-aligned pointer pointing at the substructure of the
- * given size.
- *
- * @param mem pointer at the variable holding the pointer at the current
- * pointer. The pointer is advanced by the given size after the return value is
- * computed.
- * @param size is the size of the substructure for which the pointer should be
- * returned.
- * @return an aligned pointer pointing at the beginning of the substructure.
- */
-static inline void *fx_mem_align(void **mem, uint32_t size) {
- return fx_mem_align_ex(mem, size, FX_ALIGN);
-}
-
-/**
- * Fills the given memory region with zeros. In contrast to memset(mem, 0, size)
- * this assumes that the pointer is at least aligned at the FX_ALIGN boundary
- * and that we can write multiples of FX_ALIGN bytes at once. This is
- * potentially dangerous, so do not use this function if you don't know exactly
- * what you're doing.
- *
- * @param mem is a pointer at the memory region that should be zeroed out. This
- * pointer is assumed to be aligned.
- * @param size is the size of the memory region that should be zeroed in bytes.
- * This value is effectively rounded up to a multiple of FX_ALIGN
- */
-static inline void fx_mem_zero_aligned(void *mem, uint32_t size) {
- assert((((uintptr_t)mem) & (FX_ALIGN - 1)) == 0); /* mem must be aligned */
- mem = FX_ASSUME_ALIGNED(mem);
- for (uint32_t i = 0; i < (size + FX_ALIGN - 1) / FX_ALIGN; i++) {
- ((uint64_t *)mem)[2 * i + 0] = 0; /* If we're lucky, this loop is */
- ((uint64_t *)mem)[2 * i + 1] = 0; /* unrolled and vectorised. */
- }
-}
-
-/******************************************************************************
- * DATATYPES *
- ******************************************************************************/
-
-/******************************************************************************
- * Enums and constants defined in the FLAC format specifiction *
- ******************************************************************************/
-
-/**
- * Possible metadata block types.
- */
-typedef enum {
- META_TYPE_STREAMINFO = 0,
- META_TYPE_PADDING = 1,
- META_TYPE_APPLICATION = 2,
- META_TYPE_SEEKTABLE = 3,
- META_TYPE_VORBIS_COMMENT = 4,
- META_TYPE_CUESHEET = 5,
- META_TYPE_PICTURE = 6,
- META_TYPE_INVALID = 127
-} fx_flac_metadata_type_t;
-
-typedef enum { BLK_FIXED = 0, BLK_VARIABLE = 1 } fx_flac_blocking_strategy_t;
-
-typedef enum {
- INDEPENDENT_MONO = 0,
- INDEPENDENT_STEREO = 1,
- INDEPENDENT_3C = 2,
- INDEPENDENT_4C = 3,
- INDEPENDENT_5C = 4,
- INDEPENDENT_6C = 5,
- INDEPENDENT_7C = 6,
- INDEPENDENT_8C = 7,
- LEFT_SIDE_STEREO = 8,
- RIGHT_SIDE_STEREO = 9,
- MID_SIDE_STEREO = 10,
-} fx_flac_channel_assignment_t;
-
-typedef enum {
- BLK_SIZE_RESERVED = 0,
- BLK_SIZE_192 = 1,
- BLK_SIZE_576 = 2,
- BLK_SIZE_1152 = 3,
- BLK_SIZE_2304 = 4,
- BLK_SIZE_4608 = 5,
- BLK_SIZE_READ_8BIT = 6,
- BLK_SIZE_READ_16BIT = 7,
- BLK_SIZE_256 = 8,
- BLK_SIZE_512 = 9,
- BLK_SIZE_1024 = 10,
- BLK_SIZE_2048 = 11,
- BLK_SIZE_4096 = 12,
- BLK_SIZE_8192 = 13,
- BLK_SIZE_16384 = 14,
- BLK_SIZE_32768 = 15
-} fx_flac_block_size_t;
-
-static const int32_t fx_flac_block_sizes_[] = {
- -1, 192, 576, 1152, 2304, 4608, 0, 0,
- 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
-
-typedef enum {
- FS_STREAMINFO = 0,
- FS_88_2KHZ = 1,
- FS_176_4KHZ = 2,
- FS_192KHZ = 3,
- FS_8KHZ = 4,
- FS_16KHZ = 5,
- FS_22_05KHZ = 6,
- FS_24KHZ = 7,
- FS_32KHZ = 8,
- FS_44_1KHZ = 9,
- FS_48KHZ = 10,
- FS_96KHZ = 11,
- FS_READ_8BIT_KHZ = 12,
- FS_READ_16BIT_HZ = 13,
- FS_READ_16BIT_DHZ = 14,
- FS_INVALID = 15
-} fx_flac_sample_rate_t;
-
-static const int32_t fx_flac_sample_rates_[] = {
- 0, 88200, 176400, 192000, 8000, 16000, 22050, 24000,
- 32000, 44100, 48000, 96000, 0, 0, 0, -1};
-
-typedef enum {
- SS_STREAMINFO = 0,
- SS_8BIT = 1,
- SS_12BIT = 2,
- SS_RESERVED_1 = 3,
- SS_16BIT = 4,
- SS_20BIT = 5,
- SS_24BIT = 6,
- SS_RESERVED_2 = 7
-} fx_flac_sample_size_t;
-
-static const int8_t fx_flac_sample_sizes_[] = {0, 8, 12, -1, 16, 20, 24, -1};
-
-typedef enum {
- SFT_CONSTANT,
- SFT_VERBATIM,
- SFT_FIXED,
- SFT_LPC
-} fx_flac_subframe_type_t;
-
-typedef enum {
- RES_RICE = 0,
- RES_RICE2 = 1,
- RES_RESERVED_1 = 2,
- RES_RESERVED_2 = 3
-} fx_flac_residual_method_t;
-
-/******************************************************************************
- * Structs defined in the flac format specification *
- ******************************************************************************/
-
-/**
- * Struc holding all the information stored in an individual block header.
- */
-typedef struct {
- /**
- * Set to 1 if this metadata block is the last metadata block in the
- * stream.
- */
- bool is_last;
-
- /**
- * Type of the metadata block.
- */
- fx_flac_metadata_type_t type;
-
- /**
- * Length of the metadata block in bytes.
- */
- uint32_t length;
-} fx_flac_metadata_t;
-
-/**
- * Data stored in the STREAMINFO header.
- */
-typedef struct {
- uint16_t min_block_size;
- uint16_t max_block_size;
- uint32_t min_frame_size;
- uint32_t max_frame_size;
- uint32_t sample_rate;
- uint8_t n_channels;
- uint8_t sample_size;
- uint64_t n_samples;
- uint8_t md5_sum[16];
-} fx_flac_streaminfo_t;
-
-/**
- * Frame header prepended to each FLAC audio block.
- */
-typedef struct {
- fx_flac_blocking_strategy_t blocking_strategy;
- fx_flac_block_size_t block_size_enum;
- fx_flac_sample_rate_t sample_rate_enum;
- fx_flac_channel_assignment_t channel_assignment;
- fx_flac_sample_size_t sample_size_enum;
- uint32_t block_size;
- uint32_t sample_rate;
- uint8_t channel_count;
- uint8_t sample_size;
- uint64_t sync_info;
- uint8_t crc8;
-} fx_flac_frame_header_t;
-
-/**
- * Header prepended to the channel-specific data of each FLAC audio block.
- */
-typedef struct {
- /**
- * Specifies the method used to encode the data.
- */
- fx_flac_subframe_type_t type;
-
- /**
- * Order of this frame.
- */
- uint8_t order;
-
- /**
- * Number of bits the decoded result has to be shifted to the left.
- */
- uint8_t wasted_bits;
-
- /**
- * Number of bits used to encode the linear predictor coefficients.
- */
- uint8_t lpc_prec;
-
- /**
- * Shift applied to the coefficients.
- */
- int8_t lpc_shift;
-
- /**
- * LPC coefficients. Number of used coefficients corresponds to the order.
- */
- int32_t *lpc_coeffs;
-
- /**
- * Method used to code the residual. FLAC currently only supports RICE and
- * RICE2.
- */
- fx_flac_residual_method_t residual_method;
-
- /**
- * Number of partitions the signal is divided into.
- */
- uint8_t rice_partition_order;
-
- /**
- * RICE parameter, i.e. the logarithm of the divisor.
- */
- uint8_t rice_parameter;
-
-} fx_flac_subframe_header_t;
-
-/**
- * Array containing the LPC coefficients for the fixed coding mode.
- */
-static const int32_t _fx_flac_fixed_coeffs[5][4] = {
- {0,0,0,0}, {1,0,0,0}, {2, -1, 0, 0}, {3, -3, 1, 0}, {4, -6, 4, -1}
-};
-
-/******************************************************************************
- * Internal state machine enums *
- ******************************************************************************/
-
-/**
- * More fine-grained state descriptor used in the internal state machine.
- */
-typedef enum {
- FLAC_SYNC_INIT = 0,
- FLAC_SYNC_F = 100,
- FLAC_SYNC_L = 101,
- FLAC_SYNC_A = 102,
- FLAC_METADATA_HEADER = 200,
- FLAC_METADATA_SKIP = 201,
- FLAC_METADATA_SINFO = 202,
- FLAC_FRAME_SYNC = 300,
- FLAC_FRAME_HEADER = 400,
- FLAC_FRAME_HEADER_SYNC_INFO = 401,
- FLAC_FRAME_HEADER_AUX = 402,
- FLAC_FRAME_HEADER_CRC = 403,
- FLAC_SUBFRAME_HEADER = 500,
- FLAC_SUBFRAME_CONSTANT = 502,
- FLAC_SUBFRAME_FIXED = 503,
- FLAC_SUBFRAME_FIXED_RESIDUAL = 504,
- FLAC_SUBFRAME_LPC = 505,
- FLAC_SUBFRAME_LPC_HEADER = 506,
- FLAC_SUBFRAME_LPC_COEFFS = 507,
- FLAC_SUBFRAME_LPC_RESIDUAL = 508,
- FLAC_SUBFRAME_RICE_INIT = 509,
- FLAC_SUBFRAME_RICE = 510,
- FLAC_SUBFRAME_RICE_UNARY = 511,
- FLAC_SUBFRAME_RICE_VERBATIM = 512,
- FLAC_SUBFRAME_RICE_FINALIZE = 513,
- FLAC_SUBFRAME_VERBATIM = 514,
- FLAC_SUBFRAME_FINALIZE = 515
-} fx_flac_private_state_t;
-
-/******************************************************************************
- * Internal structs *
- ******************************************************************************/
-
-/**
- * Private definition of the fx_flac structure.
- */
-struct fx_flac {
- /**
- * Bitstream reader used to read individual bits from the input.
- */
- fx_bitstream_t bitstream;
-
- /**
- * Current state of the decoder.
- */
- fx_flac_state_t state;
-
- /**
- * Current private state of the decoder.
- */
- fx_flac_private_state_t priv_state;
-
- /**
- * Number of bytes remaining to read for the current frame/block.
- */
- uint32_t n_bytes_rem;
-
- /**
- * Maximum numbers of samples in a single block, per channel.
- */
- uint16_t max_block_size;
-
- /**
- * Maximum number of channels supported by the decoder.
- */
- uint8_t max_channels;
-
- /**
- * Current coefficient.
- */
- uint8_t coef_cur;
-
- /**
- * Current rice partition.
- */
- uint16_t partition_cur;
-
- /**
- * Current sample index in the current rice partition (decremented to zero).
- */
- uint16_t partition_sample;
-
- /**
- * Current rice partition unary quotient counter.
- */
- uint16_t rice_unary_counter;
-
- /**
- * Current channel. This is reset at frame boundaries.
- */
- uint8_t chan_cur;
-
- /**
- * Pointer into the current block buffer.
- */
- uint16_t blk_cur;
-
- /**
- * Variable holding the checksum computed when reading the frame_header.
- */
- uint8_t crc8;
-
- /**
- * Variable holding the checksum of an entire frame. If this checksum does
- * not match after decoding a frame, the entire frame is rejected.
- */
- uint16_t crc16;
-
- /**
- * Flag indicating whether the current metadata block is the last metadata
- * block.
- */
- fx_flac_metadata_t *metadata;
-
- /**
- * Structure holding the current stream metadata.
- */
- fx_flac_streaminfo_t *streaminfo;
-
- /**
- * Structure holding the frame header.
- */
- fx_flac_frame_header_t *frame_header;
-
- /**
- * Structure holding the subframe header.
- */
- fx_flac_subframe_header_t *subframe_header;
-
- /**
- * Buffer used for storing the LPC coefficients.
- */
- int32_t *qbuf;
-
- /**
- * Structure holding the temporary/output buffers for each channel.
- */
- int32_t *blkbuf[FLAC_MAX_CHANNEL_COUNT];
-};
-
-/******************************************************************************
- * PRIVATE CODE *
- ******************************************************************************/
-
-/******************************************************************************
- * Initialization code utils *
- ******************************************************************************/
-
-static bool _fx_flac_check_params(uint16_t max_block_size,
- uint8_t max_channels) {
- return (max_block_size > 0U) && (max_channels > 0U) &&
- (max_channels <= FLAC_MAX_CHANNEL_COUNT);
-}
-
-/******************************************************************************
- * FLAC enum decoders *
- ******************************************************************************/
-
-static bool _fx_flac_decode_block_size(fx_flac_block_size_t block_size_enum,
- uint32_t *block_size) {
- const int32_t bs = fx_flac_block_sizes_[(int)block_size_enum];
- if (bs < 0) {
- return false; /* Invalid */
- } else if (bs > 0) {
- *block_size = bs;
- }
- return true;
-}
-
-static bool _fx_flac_decode_sample_rate(fx_flac_sample_rate_t sample_rate_enum,
- uint32_t *sample_rate) {
- const int32_t fs = fx_flac_sample_rates_[(int)sample_rate_enum];
- if (fs < 0) {
- return false; /* Invalid */
- } else if (fs > 0) {
- *sample_rate = fs;
- }
- return true;
-}
-
-static bool _fx_flac_decode_sample_size(fx_flac_sample_size_t sample_size_enum,
- uint8_t *sample_size) {
- const int8_t ss = fx_flac_sample_sizes_[(int)sample_size_enum];
- if (ss < 0) {
- return false; /* Invalid */
- } else if (ss > 0) {
- *sample_size = ss;
- }
- return true;
-}
-
-/**
- * Returns the number of channels encoded in the frame header.
- */
-static bool _fx_flac_decode_channel_count(
- fx_flac_channel_assignment_t channel_assignment, uint8_t *channel_count) {
- *channel_count = (channel_assignment >= LEFT_SIDE_STEREO)
- ? 2U
- : (uint8_t)channel_assignment + 1U;
- return true;
-}
-
-/******************************************************************************
- * Decoding functions *
- ******************************************************************************/
-
-static inline void _fx_flac_post_process_left_side(int32_t *blk1, int32_t *blk2,
- uint32_t blk_size) {
- blk1 = (int32_t *)FX_ASSUME_ALIGNED(blk1);
- blk2 = (int32_t *)FX_ASSUME_ALIGNED(blk2);
- for (uint32_t i = 0U; i < blk_size; i++) {
- blk2[i] = blk1[i] - blk2[i];
- }
-}
-
-static inline void _fx_flac_post_process_right_side(int32_t *blk1,
- int32_t *blk2,
- uint32_t blk_size) {
- blk1 = (int32_t *)FX_ASSUME_ALIGNED(blk1);
- blk2 = (int32_t *)FX_ASSUME_ALIGNED(blk2);
- for (uint32_t i = 0U; i < blk_size; i++) {
- blk1[i] = blk1[i] + blk2[i];
- }
-}
-
-static inline void _fx_flac_post_process_mid_side(int32_t *blk1, int32_t *blk2,
- uint32_t blk_size) {
- blk1 = (int32_t *)FX_ASSUME_ALIGNED(blk1);
- blk2 = (int32_t *)FX_ASSUME_ALIGNED(blk2);
- for (uint32_t i = 0U; i < blk_size; i++) {
- /* Code libflac from stream_decoder.c */
- int32_t mid = blk1[i];
- int32_t side = blk2[i];
- mid = ((uint32_t)mid) << 1;
- mid |= (side & 1); /* Round correctly */
- blk1[i] = (mid + side) >> 1;
- blk2[i] = (mid - side) >> 1;
- }
-}
-
-static inline void _fx_flac_restore_lpc_signal(int32_t *blk, uint32_t blk_size,
- int32_t *lpc_coeffs,
- uint8_t lpc_order,
- int8_t lpc_shift) {
- blk = (int32_t *)FX_ASSUME_ALIGNED(blk);
- lpc_coeffs = (int32_t *)FX_ASSUME_ALIGNED(lpc_coeffs);
-
- for (uint32_t i = lpc_order; i < blk_size; i++) {
- int64_t accu = 0;
- for (uint8_t j = 0; j < lpc_order; j++) {
- accu += (int64_t)lpc_coeffs[j] * (int64_t)blk[i - j - 1];
- }
- blk[i] = blk[i] + (accu >> lpc_shift);
- }
-}
-
-/******************************************************************************
- * Stream utility functions and macros *
- ******************************************************************************/
-
-/* http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
-#define SIGN_EXTEND(x, b) \
- (int64_t)((x) ^ (1LU << ((b)-1U))) - (int64_t)(1LU << ((b)-1U))
-
-#define ENSURE_BITS(n) \
- if (!fx_bitstream_can_read(&inst->bitstream, n)) { \
- return false; /* Need more data */ \
- }
-
-#define READ_BITS(n) \
- (tmp_ = fx_bitstream_try_read_msb(&inst->bitstream, n)); \
- if (tmp_ < 0) { \
- return false; /* Need more data */ \
- }
-
-#define READ_BITS_FAST(n) (tmp_ = fx_bitstream_read_msb(&inst->bitstream, n));
-
-#define PEEK_BITS(n) \
- (tmp_ = fx_bitstream_try_peek_msb(&inst->bitstream, n)); \
- if (tmp_ < 0) { \
- return false; /* Need more data */ \
- }
-
-#define SYNC_BYTESTREAM() \
- { \
- uint8_t n_ = inst->bitstream.pos & 0x07; \
- if (n_) { \
- READ_BITS(8U - n_); \
- } \
- }
-
-#ifdef FX_FLAC_NO_CRC
-
-/* Just alias the CRC versions of the READ macros to the read macros
- themselves */
-#define READ_BITS_CRC(n) READ_BITS(n)
-#define READ_BITS_FAST_CRC(n) READ_BITS_FAST(n)
-#define READ_BITS_DCRC(n) READ_BITS(n)
-#define READ_BITS_FAST_DCRC(n) READ_BITS_FAST(n)
-#define SYNC_BYTESTREAM_CRC() SYNC_BYTESTREAM()
-
-#else /* FX_FLAC_NO_CRC */
-
-/* Update the frame checksum while reading data */
-
-#define READ_BITS_CRC(n) \
- (tmp_ = fx_bitstream_try_read_msb_ex(&inst->bitstream, n, _fx_flac_crc16_, \
- inst)); \
- if (tmp_ < 0) { \
- return false; /* Need more data */ \
- }
-
-#define READ_BITS_FAST_CRC(n) \
- (tmp_ = fx_bitstream_read_msb_ex(&inst->bitstream, n, _fx_flac_crc16_, \
- inst));
-
-/* DCRC -> Dual CRC, update both the header and the frame checksum */
-
-#define READ_BITS_DCRC(n) \
- (tmp_ = fx_bitstream_try_read_msb_ex(&inst->bitstream, n, \
- _fx_flac_double_crc_, inst)); \
- if (tmp_ < 0) { \
- return false; /* Need more data */ \
- }
-
-#define READ_BITS_FAST_DCRC(n) \
- (tmp_ = fx_bitstream_read_msb_ex(&inst->bitstream, n, \
- _fx_flac_double_crc_, inst));
-
-#define SYNC_BYTESTREAM_CRC() \
- { \
- uint8_t n_ = inst->bitstream.pos & 0x07; \
- if (n_) { \
- READ_BITS_CRC(8U - n_); \
- } \
- }
-
-static const uint8_t fx_flac_crc8_table_[256] = {
- 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
- 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
- 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
- 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
- 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
- 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
- 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
- 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
- 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
- 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
- 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
- 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
- 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
- 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
- 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
- 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
- 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
- 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
- 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
- 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
- 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
- 0xfa, 0xfd, 0xf4, 0xf3};
-
-static const uint16_t fx_flac_crc16_table_[256] = {
- 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, 0x8033,
- 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, 0x8063, 0x0066,
- 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, 0x0050, 0x8055, 0x805f,
- 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, 0x80c3, 0x00c6, 0x00cc, 0x80c9,
- 0x00d8, 0x80dd, 0x80d7, 0x00d2, 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb,
- 0x00ee, 0x00e4, 0x80e1, 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be,
- 0x00b4, 0x80b1, 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087,
- 0x0082, 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
- 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, 0x01e0,
- 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, 0x81d3, 0x01d6,
- 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, 0x0140, 0x8145, 0x814f,
- 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, 0x8173, 0x0176, 0x017c, 0x8179,
- 0x0168, 0x816d, 0x8167, 0x0162, 0x8123, 0x0126, 0x012c, 0x8129, 0x0138,
- 0x813d, 0x8137, 0x0132, 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e,
- 0x0104, 0x8101, 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317,
- 0x0312, 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
- 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, 0x8353,
- 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, 0x03c0, 0x83c5,
- 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, 0x83f3, 0x03f6, 0x03fc,
- 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, 0x83a3, 0x03a6, 0x03ac, 0x83a9,
- 0x03b8, 0x83bd, 0x83b7, 0x03b2, 0x0390, 0x8395, 0x839f, 0x039a, 0x838b,
- 0x038e, 0x0384, 0x8381, 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e,
- 0x0294, 0x8291, 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7,
- 0x02a2, 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
- 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, 0x8243,
- 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, 0x0270, 0x8275,
- 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, 0x0220, 0x8225, 0x822f,
- 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, 0x8213, 0x0216, 0x021c, 0x8219,
- 0x0208, 0x820d, 0x8207, 0x0202};
-
-static inline void _fx_flac_crc8_(uint8_t byte, void *data) {
- fx_flac_t *inst = (fx_flac_t *)FX_ASSUME_ALIGNED(data);
- inst->crc8 = fx_flac_crc8_table_[inst->crc8 ^ byte];
-}
-
-static inline void _fx_flac_crc16_(uint8_t byte, void *data) {
- fx_flac_t *inst = (fx_flac_t *)FX_ASSUME_ALIGNED(data);
- const uint8_t i = ((inst->crc16 >> 8U) ^ byte) & 0xFF;
- inst->crc16 = fx_flac_crc16_table_[i] ^ (inst->crc16 << 8U);
-}
-
-static inline void _fx_flac_double_crc_(uint8_t byte, void *data) {
- _fx_flac_crc8_(byte, data);
- _fx_flac_crc16_(byte, data);
-}
-#endif /* FX_FLAC_NO_CRC */
-
-static bool _fx_flac_reader_utf8_coded_int(fx_flac_t *inst, uint8_t max_n,
- uint64_t *tar) {
- int64_t tmp_; /* Used by the READ_BITS macro */
-
- ENSURE_BITS(max_n * 8U);
- /* Read the first byte */
- uint8_t v = READ_BITS_FAST_DCRC(8U);
-
- /* Count the number of ones in the first byte */
- uint8_t n_ones = 0U;
- while (v & 0x80U) {
- v = v << 1U;
- n_ones++;
- }
-
- /* Abort if the number of bytes to read is larger than max_n */
- if (n_ones > max_n) {
- inst->priv_state = FLAC_FRAME_SYNC; /* Invalid header */
- return true;
- }
-
- /* Shift v back and store in var */
- *tar = (v >> n_ones);
-
- /* Read all continuation bytes */
- for (uint8_t i = 1U; i < n_ones; i++) {
- v = READ_BITS_FAST_DCRC(8U);
- /* Abort if continuation byte doesn't start with correct sequence */
- if ((v & 0xC0U) != 0x80) {
- inst->priv_state = FLAC_FRAME_SYNC; /* Invalid header */
- return true;
- }
- *tar = ((*tar) << 6U) | (v & 0x3F);
- }
- return true;
-}
-
-/******************************************************************************
- * Private decoder state machine *
- ******************************************************************************/
-
-/*
- * Note: the boolean return value of these functions indicates whether they
- * rand out of data -- true indicates that there is still enough data left,
- * false indicates that the outer state machine should return to the user code
- * to read more data. The return value does NOT indicate success/failure. This
- * is what inst->state == FLAC_ERR is for.
- */
-
-static bool _fx_flac_handle_err(fx_flac_t *inst) {
- /* TODO: Add flags to fx_flac_t which control this behaviour */
-
- /* If an error happens while searching for metadata, this is fatal. */
- if (inst->state < FLAC_END_OF_METADATA) {
- inst->state = FLAC_ERR;
- return false;
- }
-
- /* Otherwise just try to re-synchronise with the stream by searching for the
- next frame */
- inst->state = FLAC_SEARCH_FRAME;
- inst->priv_state = FLAC_FRAME_SYNC;
- return true;
-}
-
-/**
- * Statemachine used to search the beginning of the stream. This (for example)
- * skips IDv3 tags prepended to the file.
- */
-static bool _fx_flac_process_init(fx_flac_t *inst) {
- int64_t tmp_; /* Used by the READ_BITS macro */
- /* Search for the 'fLaC' sync word */
- uint8_t byte = READ_BITS(8);
- switch (inst->priv_state) {
- case FLAC_SYNC_INIT:
- if (byte == 'f') {
- inst->priv_state = FLAC_SYNC_F;
- }
- break;
- case FLAC_SYNC_F:
- if (byte == 'L') {
- inst->priv_state = FLAC_SYNC_L;
- } else {
- inst->priv_state = FLAC_SYNC_INIT;
- }
- break;
- case FLAC_SYNC_L:
- if (byte == 'a') {
- inst->priv_state = FLAC_SYNC_A;
- } else {
- inst->priv_state = FLAC_SYNC_INIT;
- }
- break;
- case FLAC_SYNC_A:
- if (byte == 'C') {
- inst->state = FLAC_IN_METADATA;
- inst->priv_state = FLAC_METADATA_HEADER;
- } else {
- inst->priv_state = FLAC_SYNC_INIT;
- }
- break;
- default:
- return _fx_flac_handle_err(inst);
- }
- return true;
-}
-
-static bool _fx_flac_process_in_metadata(fx_flac_t *inst) {
- int64_t tmp_; /* Used by the READ_BITS macro */
- switch (inst->priv_state) {
- case FLAC_METADATA_HEADER:
- ENSURE_BITS(32U);
- inst->metadata->is_last = READ_BITS_FAST(1U);
- inst->metadata->type = (fx_flac_metadata_type_t)READ_BITS_FAST(7U);
- if (inst->metadata->type == META_TYPE_INVALID) {
- return _fx_flac_handle_err(inst);
- }
- inst->metadata->length = inst->n_bytes_rem = READ_BITS_FAST(24U);
- if (inst->metadata->type == META_TYPE_STREAMINFO) {
- inst->priv_state = FLAC_METADATA_SINFO;
- /* The stream info header must be exactly 33 bytes long */
- if (inst->metadata->length != 34U) {
- return _fx_flac_handle_err(inst);
- }
- } else {
- inst->priv_state = FLAC_METADATA_SKIP;
- }
- break;
- case FLAC_METADATA_SINFO:
- switch (inst->n_bytes_rem) {
- case 34U:
- inst->streaminfo->min_block_size = READ_BITS(16U);
- inst->n_bytes_rem -= 2U;
- break;
- case 32U:
- inst->streaminfo->max_block_size = READ_BITS(16U);
- inst->n_bytes_rem -= 2U;
- break;
- case 30U:
- inst->streaminfo->min_frame_size = READ_BITS(24U);
- inst->n_bytes_rem -= 3U;
- break;
- case 27U:
- inst->streaminfo->max_frame_size = READ_BITS(24U);
- inst->n_bytes_rem -= 3U;
- break;
- case 24U:
- ENSURE_BITS(28U);
- inst->streaminfo->sample_rate = READ_BITS_FAST(20U);
- inst->streaminfo->n_channels = 1U + READ_BITS_FAST(3U);
- inst->streaminfo->sample_size = 1U + READ_BITS_FAST(5U);
- inst->n_bytes_rem -= 4U;
- break;
- case 20U:
- inst->streaminfo->n_samples = READ_BITS(36U);
- inst->n_bytes_rem -= 4U;
- break;
- case 1U:
- case 2U:
- case 3U:
- case 4U:
- case 5U:
- case 6U:
- case 7U:
- case 8U:
- case 9U:
- case 10U:
- case 11U:
- case 12U:
- case 13U:
- case 14U:
- case 15U:
- case 16U:
- inst->streaminfo->md5_sum[16U - inst->n_bytes_rem] =
- READ_BITS(8);
- inst->n_bytes_rem -= 1U;
- break;
- case 0U:
- /* Use the FLAC_END_OF_METADATA_SKIP state logic below */
- inst->priv_state = FLAC_METADATA_SKIP;
- break;
- default:
- return _fx_flac_handle_err(inst);
- }
- break;
- case FLAC_METADATA_SKIP: {
- const uint8_t n_read =
- (inst->n_bytes_rem >= 7U) ? 7U : inst->n_bytes_rem;
- if (n_read == 0U) { /* We read all the data for this block */
- if (inst->metadata->is_last) {
- /* Last metadata block, transition to the next state */
- inst->state = FLAC_END_OF_METADATA;
- } else {
- /* End of metadata block, read the next one */
- inst->priv_state = FLAC_METADATA_HEADER;
- }
- break;
- }
- READ_BITS(n_read * 8U);
- inst->n_bytes_rem -= n_read;
- break;
- }
- default:
- return _fx_flac_handle_err(inst); /* Internal error */
- }
- return true;
-}
-
-static bool _fx_flac_process_search_frame(fx_flac_t *inst) {
- int64_t tmp_; /* Used by the READ_BITS macro */
- fx_flac_frame_header_t *fh = inst->frame_header;
- fx_flac_streaminfo_t *si = inst->streaminfo;
- switch (inst->priv_state) {
- case FLAC_FRAME_SYNC:
- /* Synchronise with the underlying bytestream */
- SYNC_BYTESTREAM();
-
- ENSURE_BITS(15U);
- uint16_t sync_code = PEEK_BITS(15U);
- if (sync_code != 0x7FFCU) {
- READ_BITS(8U); /* Next byte (assume frames are byte aligned). */
- return true;
- } else {
- inst->crc8 = 0U; /* Reset the checksums */
- inst->crc16 = 0U;
- inst->priv_state = FLAC_FRAME_HEADER;
- READ_BITS_FAST_DCRC(15U);
- }
- break;
- case FLAC_FRAME_HEADER:
- ENSURE_BITS(17U);
-
- /* Read the frame header bits */
- fh->blocking_strategy =
- (fx_flac_blocking_strategy_t)READ_BITS_FAST_DCRC(1U);
- fh->block_size_enum = (fx_flac_block_size_t)READ_BITS_FAST_DCRC(4U);
- fh->sample_rate_enum =
- (fx_flac_sample_rate_t)READ_BITS_FAST_DCRC(4U);
- fh->channel_assignment =
- (fx_flac_channel_assignment_t)READ_BITS_FAST_DCRC(4U);
- fh->sample_size_enum =
- (fx_flac_sample_size_t)READ_BITS_FAST_DCRC(3U);
- READ_BITS_FAST_DCRC(1U);
- if (tmp_ != 0U || fh->channel_assignment > MID_SIDE_STEREO) {
- return _fx_flac_handle_err(inst); /* Invalid header */
- }
-
- /* Copy sample rate and sample size from the streaminfo */
- fh->sample_rate = si->sample_rate;
- fh->sample_size = si->sample_size;
-
- /* Decode the individual enums */
- if (!_fx_flac_decode_block_size(fh->block_size_enum,
- &fh->block_size) ||
- !_fx_flac_decode_sample_rate(fh->sample_rate_enum,
- &fh->sample_rate) ||
- !_fx_flac_decode_sample_size(fh->sample_size_enum,
- &fh->sample_size) ||
- !_fx_flac_decode_channel_count(fh->channel_assignment,
- &fh->channel_count)) {
- inst->priv_state = FLAC_FRAME_SYNC; /* Got invalid value */
- break;
- }
- inst->priv_state = FLAC_FRAME_HEADER_SYNC_INFO;
- break;
- case FLAC_FRAME_HEADER_SYNC_INFO:
- if (!_fx_flac_reader_utf8_coded_int(
- inst, (fh->blocking_strategy == BLK_VARIABLE) ? 7U : 6U,
- &fh->sync_info)) {
- return false;
- }
- inst->priv_state = FLAC_FRAME_HEADER_AUX;
- break;
- case FLAC_FRAME_HEADER_AUX:
- ENSURE_BITS(32U);
- /* Read block size/sample rate if not directly packed into the
- previous header */
- switch (fh->block_size_enum) {
- case BLK_SIZE_READ_8BIT:
- fh->block_size = 1U + READ_BITS_FAST_DCRC(8U);
- break;
- case BLK_SIZE_READ_16BIT:
- fh->block_size = 1U + READ_BITS_FAST_DCRC(16U);
- break;
- default:
- break;
- }
- switch (fh->sample_rate_enum) {
- case FS_READ_8BIT_KHZ:
- fh->sample_rate = 1000UL * READ_BITS_FAST_DCRC(8U);
- break;
- case FS_READ_16BIT_HZ:
- fh->sample_rate = READ_BITS_FAST_DCRC(16U);
- break;
- case FS_READ_16BIT_DHZ:
- fh->sample_rate = 10UL * READ_BITS_FAST_DCRC(16U);
- break;
- default:
- break;
- }
- inst->priv_state = FLAC_FRAME_HEADER_CRC;
- break;
- case FLAC_FRAME_HEADER_CRC:
- /* Read the CRC8 checksum, make sure it equals the checksum written
- to the header. If not, this is not a valid header. Continue
- searching. */
- fh->crc8 = READ_BITS_CRC(8U);
-#ifndef FX_FLAC_NO_CRC
- if (fh->crc8 != inst->crc8) {
- return _fx_flac_handle_err(inst);
- }
-#endif
-
- /* Make sure the decode has enough space */
- if ((fh->block_size > inst->max_block_size) ||
- (fh->channel_count > inst->max_channels)) {
- return _fx_flac_handle_err(inst);
- }
-
- /* Decode the subframes */
- inst->state = FLAC_IN_FRAME;
- inst->priv_state = FLAC_SUBFRAME_HEADER;
- inst->chan_cur = 0U; /* Start with the first channel */
- break;
- default:
- return _fx_flac_handle_err(inst);
- }
- return true;
-}
-
-static bool _fx_flac_process_in_frame(fx_flac_t *inst) {
- int64_t tmp_ = 0; /* Used by the READ_BITS macro */
- fx_flac_frame_header_t *fh = inst->frame_header;
- fx_flac_subframe_header_t *sfh = inst->subframe_header;
- int32_t *blk = inst->blkbuf[inst->chan_cur % FLAC_MAX_CHANNEL_COUNT];
- const uint32_t blk_n = fh->block_size;
-
- /* Figure out the number of bits to read for sample. This depends on the
- channel assignment. */
- uint8_t bps = fh->sample_size - sfh->wasted_bits;
- if ((fh->channel_assignment == LEFT_SIDE_STEREO && inst->chan_cur == 1) ||
- (fh->channel_assignment == RIGHT_SIDE_STEREO && inst->chan_cur == 0) ||
- (fh->channel_assignment == MID_SIDE_STEREO && inst->chan_cur == 1)) {
- bps++;
- }
-
- /* Discard frames with invalid bits per sample values */
- if (bps == 0U || bps > 32U) {
- return _fx_flac_handle_err(inst);
- }
-
- /* This flag is set to false whenever a state in the state machine
- encounters and error. */
- switch (inst->priv_state) {
- case FLAC_SUBFRAME_HEADER: {
- ENSURE_BITS(40U);
-
- /* Reset the block write cursor, make sure initial blk sample is set
- to zero for zero-order fixed LPC */
- inst->blk_cur = 0U;
- blk[0U] = 0U;
-
- /* Read a zero padding bit. This must be zero. */
- uint8_t padding = READ_BITS_FAST_CRC(1U);
- bool valid = padding == 0U;
-
- /* Read the frame type and order */
- uint8_t type = READ_BITS_FAST_CRC(6U);
- if (type & 0x20U) {
- sfh->order = (type & 0x1FU) + 1U;
- sfh->type = SFT_LPC;
- sfh->lpc_coeffs = inst->qbuf;
- inst->priv_state = FLAC_SUBFRAME_LPC;
- } else if (type & 0x10U) {
- return _fx_flac_handle_err(inst);
- } else if (type & 0x08U) {
- sfh->order = type & 0x07U;
- sfh->type = SFT_FIXED;
- sfh->lpc_shift = 0;
- inst->priv_state = FLAC_SUBFRAME_FIXED;
- valid = valid && (sfh->order <= 4U);
- if (valid) {
- sfh->lpc_coeffs =
- (int32_t *)_fx_flac_fixed_coeffs[sfh->order];
- }
- } else if ((type & 0x04U) || (type & 0x02U)) {
- return _fx_flac_handle_err(inst);
- } else if (type & 0x01U) {
- sfh->type = SFT_VERBATIM;
- inst->priv_state = FLAC_SUBFRAME_VERBATIM;
- } else {
- sfh->type = SFT_CONSTANT;
- inst->priv_state = FLAC_SUBFRAME_CONSTANT;
- }
-
- /* Read the "wasted_bits" flag */
- sfh->wasted_bits = READ_BITS_FAST_CRC(1U);
- if (sfh->wasted_bits) {
- for (uint8_t i = 1U; i <= 30U; i++) {
- const uint8_t bit = READ_BITS_FAST_CRC(1U);
- if (bit == 1U) {
- sfh->wasted_bits = i;
- break;
- }
- }
- valid = valid && (sfh->wasted_bits > 0U) &&
- (sfh->wasted_bits < fh->sample_size);
- }
-
- /* Make sure the block is large enough for the initial samples */
- valid = valid && (blk_n >= sfh->order);
- if (!valid) {
- _fx_flac_handle_err(inst);
- }
- break;
- }
- case FLAC_SUBFRAME_CONSTANT: {
- /* Read a single sample value and spread it over the entire block
- buffer for this subframe. */
- blk[0U] = READ_BITS_CRC(bps);
- blk[0U] = SIGN_EXTEND(blk[0U], bps);
- for (uint16_t i = 1U; i < blk_n; i++) {
- blk[i] = blk[0U];
- }
- inst->priv_state = FLAC_SUBFRAME_FINALIZE;
- break;
- }
- case FLAC_SUBFRAME_VERBATIM:
- case FLAC_SUBFRAME_FIXED:
- case FLAC_SUBFRAME_LPC: {
- /* Either just read up to "order" samples, or the entire block */
- const uint32_t n = (sfh->type == SFT_VERBATIM) ? blk_n : sfh->order;
- while (inst->blk_cur < n) {
- blk[inst->blk_cur] = READ_BITS_CRC(bps);
- blk[inst->blk_cur] = SIGN_EXTEND(blk[inst->blk_cur], bps);
- inst->blk_cur++;
- }
- inst->priv_state =
- (fx_flac_private_state_t)((int)inst->priv_state + 1U);
- break;
- }
- case FLAC_SUBFRAME_LPC_HEADER: {
- /* Read the coefficient precision as well as the shift value */
- ENSURE_BITS(9U);
- const uint8_t prec = READ_BITS_FAST_CRC(4U);
- const uint8_t shift = READ_BITS_FAST_CRC(5U);
- if (prec == 15U) { /* Precision of 15 bits is invalid */
- return _fx_flac_handle_err(inst);
- }
- sfh->lpc_prec = prec + 1U;
- sfh->lpc_shift = SIGN_EXTEND(shift, 5U);
- if (sfh->lpc_shift < 0) {
- return _fx_flac_handle_err(inst);
- }
- inst->coef_cur = 0U;
- inst->priv_state = FLAC_SUBFRAME_LPC_COEFFS;
- break;
- }
- case FLAC_SUBFRAME_LPC_COEFFS:
- /* Read the individual predictor coefficients */
- while (inst->coef_cur < sfh->order) {
- uint32_t coef = READ_BITS_CRC(sfh->lpc_prec);
- sfh->lpc_coeffs[inst->coef_cur] =
- SIGN_EXTEND(coef, sfh->lpc_prec);
- inst->coef_cur++;
- }
- inst->priv_state = FLAC_SUBFRAME_LPC_RESIDUAL;
- break;
- case FLAC_SUBFRAME_FIXED_RESIDUAL:
- case FLAC_SUBFRAME_LPC_RESIDUAL: {
- ENSURE_BITS(6U);
-
- /* Read the residual encoding type and the rice partition order */
- sfh->residual_method =
- (fx_flac_residual_method_t)READ_BITS_FAST_CRC(2U);
- if (sfh->residual_method > RES_RICE2) {
- return _fx_flac_handle_err(inst);
- }
- sfh->rice_partition_order = READ_BITS_FAST_CRC(4U);
- inst->partition_cur = 0U;
- inst->priv_state = FLAC_SUBFRAME_RICE_INIT;
- break;
- }
- case FLAC_SUBFRAME_RICE_INIT: {
- /* Read the Rice parameter */
- ENSURE_BITS(10U);
-
- uint8_t n_bits = (sfh->residual_method == RES_RICE) ? 4U : 5U;
- sfh->rice_parameter = READ_BITS_FAST_CRC(n_bits);
- if (sfh->rice_parameter == ((1U << n_bits) - 1U)) {
- sfh->rice_parameter = READ_BITS_FAST_CRC(5U);
- inst->priv_state = FLAC_SUBFRAME_RICE_VERBATIM;
- } else {
- inst->priv_state = FLAC_SUBFRAME_RICE_UNARY;
- inst->rice_unary_counter = 0U;
- }
-
- /* Compute the number of samples to read */
- inst->partition_sample = blk_n >> sfh->rice_partition_order;
- if (inst->partition_cur == 0U) {
- /* First partition alread includes verbatim samples */
- if (inst->partition_sample < sfh->order) {
- return _fx_flac_handle_err(
- inst); /* Number of samples is negative */
- }
- inst->partition_sample -= sfh->order;
- }
-
- /* Make sure we're never writing beyond the buffer for this
- channel */
- if ((inst->partition_sample + inst->blk_cur) > blk_n) {
- return _fx_flac_handle_err(inst);
- }
- break;
- }
- case FLAC_SUBFRAME_RICE:
- case FLAC_SUBFRAME_RICE_UNARY:
- /* Read the individual rice samples */
- while (inst->partition_sample > 0U) {
- /* Read the unary part of the Rice encoded sample bit-by-bit */
- if (inst->priv_state == FLAC_SUBFRAME_RICE_UNARY) {
- while (true) {
- const uint8_t bit = READ_BITS_CRC(1U);
- if (bit) {
- break;
- }
- inst->rice_unary_counter++;
- }
- }
-
- /* If there are no more bits left below, make sure we end up
- here instead of going through the unary decoder again. */
- inst->priv_state = FLAC_SUBFRAME_RICE;
-
- /* Read the remainder */
- uint32_t r = 0U;
- if (sfh->rice_parameter > 0U) {
- r = READ_BITS_CRC(sfh->rice_parameter);
- }
- const uint16_t q = inst->rice_unary_counter;
- const uint32_t val = (q << sfh->rice_parameter) | r;
-
- /* Last bit determines sign */
- if (val & 1) {
- blk[inst->blk_cur] = -((int32_t)(val >> 1)) - 1;
- } else {
- blk[inst->blk_cur] = (int32_t)(val >> 1);
- }
-
- /* Read the next sample */
- inst->rice_unary_counter = 0U;
- inst->priv_state = FLAC_SUBFRAME_RICE_UNARY;
- inst->blk_cur++;
- inst->partition_sample--;
- }
- inst->priv_state = FLAC_SUBFRAME_RICE_FINALIZE;
- break;
- case FLAC_SUBFRAME_RICE_VERBATIM: {
- /* Samples are encoded in verbatim in this partition */
- const uint8_t bps = sfh->rice_parameter;
- while (inst->partition_sample > 0U) {
- blk[inst->blk_cur] = (bps == 0) ? 0U : READ_BITS_CRC(bps);
- blk[inst->blk_cur] = SIGN_EXTEND(blk[inst->blk_cur], bps);
- inst->blk_cur++;
- inst->partition_sample--;
- }
- inst->priv_state = FLAC_SUBFRAME_RICE_FINALIZE;
- break;
- }
- case FLAC_SUBFRAME_RICE_FINALIZE:
- /* Go to the next partition or finalize this subframe */
- inst->partition_cur++;
- if (inst->partition_cur == (1U << sfh->rice_partition_order)) {
- /* Decode the residual */
- _fx_flac_restore_lpc_signal(blk, blk_n, sfh->lpc_coeffs,
- sfh->order, sfh->lpc_shift);
- inst->priv_state = FLAC_SUBFRAME_FINALIZE;
- } else {
- inst->priv_state = FLAC_SUBFRAME_RICE_INIT;
- }
- break;
- case FLAC_SUBFRAME_FINALIZE: {
- /* Apply the wasted bits transformation */
- if (sfh->wasted_bits) {
- uint8_t shift = sfh->wasted_bits;
- for (uint16_t i = 0U; i < blk_n; i++) {
- blk[i] = blk[i] * (1 << shift);
- }
- }
-
- /* There is another subframe to read, continue! */
- inst->chan_cur++; /* Go to the next channel */
- if (inst->chan_cur < fh->channel_count) {
- inst->priv_state = FLAC_SUBFRAME_HEADER;
- break;
- }
-
- /* Synchronise with the underlying byte stream */
- SYNC_BYTESTREAM_CRC();
-
- /* Read the CRC16 sum, resync if it doesn't match our own */
- uint16_t crc16 = READ_BITS(16U);
-#ifndef FX_FLAC_NO_CRC
- if (crc16 != inst->crc16) {
- return _fx_flac_handle_err(inst);
- }
-#else
- (void)crc16;
-#endif
-
- /* Post process side-stereo */
- int32_t *c1 = inst->blkbuf[0], *c2 = inst->blkbuf[1];
- switch (fh->channel_assignment) {
- case LEFT_SIDE_STEREO:
- _fx_flac_post_process_left_side(c1, c2, blk_n);
- break;
- case RIGHT_SIDE_STEREO:
- _fx_flac_post_process_right_side(c1, c2, blk_n);
- break;
- case MID_SIDE_STEREO:
- _fx_flac_post_process_mid_side(c1, c2, blk_n);
- break;
- default:
- break;
- }
-
- /* Shift the output such that the resulting int32 stream can be
- played back. */
- uint8_t shift = 32U - fh->sample_size;
- if (shift) {
- for (uint8_t c = 0U; c < fh->channel_count; c++) {
- int32_t *blk = inst->blkbuf[c];
- for (uint16_t i = 0U; i < blk_n; i++) {
- blk[i] = blk[i] * (1 << shift);
- }
- }
- }
-
- /* We're done decoding this frame! Notify the outer loop! */
- inst->blk_cur = 0U; /* Reset the read cursor */
- inst->chan_cur = 0U;
- inst->state = FLAC_DECODED_FRAME;
- break;
- }
- default:
- inst->state = FLAC_ERR;
- break;
- }
- return true;
-}
-
-static bool _fx_flac_process_decoded_frame(fx_flac_t *inst, int32_t *out,
- uint32_t *out_len) {
- /* Fetch the current stream and frame info. */
- const fx_flac_frame_header_t *fh = inst->frame_header;
-
- /* Fetch channel count and number of samples left to write */
- const uint8_t cc = fh->channel_count;
- uint32_t n_smpls_rem =
- (fh->block_size - inst->blk_cur - 1U) * cc + (cc - inst->chan_cur);
-
- /* Truncate to the actually available space. */
- if (n_smpls_rem > *out_len) {
- n_smpls_rem = *out_len;
- }
-
- /* Interlace the decoded samples in the output array */
- uint32_t tar = 0U; /* Number of samples written. */
- while (tar < n_smpls_rem) {
- /* Write to the output buffer */
- out[tar] = inst->blkbuf[inst->chan_cur][inst->blk_cur];
-
- /* Advance the read and write cursors */
- inst->chan_cur++;
- if (inst->chan_cur == cc) {
- inst->chan_cur = 0U;
- inst->blk_cur++;
- }
- tar++;
- }
-
- /* Inform the caller about the number of samples written */
- *out_len = tar;
-
- /* We're done with this frame! */
- if (inst->blk_cur == fh->block_size) {
- inst->state = FLAC_END_OF_FRAME;
- return true;
- }
-
- /* Since we're here, we need more space in the output array. */
- return false;
-}
-
-/******************************************************************************
- * PUBLIC API *
- ******************************************************************************/
-
-uint32_t fx_flac_size(uint32_t max_block_size, uint8_t max_channels) {
- /* Calculate the size of the fixed-size structures */
- uint32_t size;
- bool ok = _fx_flac_check_params(max_block_size, max_channels) &&
- fx_mem_init_size(&size) &&
- fx_mem_update_size(&size, sizeof(fx_flac_t)) &&
- fx_mem_update_size(&size, sizeof(fx_flac_metadata_t)) &&
- fx_mem_update_size(&size, sizeof(fx_flac_streaminfo_t)) &&
- fx_mem_update_size(&size, sizeof(fx_flac_frame_header_t)) &&
- fx_mem_update_size(&size, sizeof(fx_flac_subframe_header_t)) &&
- fx_mem_update_size(&size, sizeof(int32_t) * 32U);
-
- /* Calculate the size of the structures depending on the given parameters.
- */
- for (uint8_t i = 0; i < max_channels; i++) {
- ok = ok && fx_mem_update_size(&size, sizeof(int32_t) * max_block_size);
- }
- return ok ? size : 0;
-}
-
-fx_flac_t *fx_flac_init(void *mem, uint16_t max_block_size,
- uint8_t max_channels) {
- /* Make sure the parameters are valid. */
- if (!_fx_flac_check_params(max_block_size, max_channels)) {
- return NULL;
- }
-
- /* Abort if mem is NULL to allow passing malloc as a direct argument to this
- code. Furthermore, store the original "mem" pointer and return it later
- so the calling code is safe to pass the returned pointer to free. */
- fx_flac_t *inst_unaligned = (fx_flac_t *)mem;
- if (mem) {
- /* Fetch the base address of the flac_t address. */
- fx_flac_t *inst = (fx_flac_t *)fx_mem_align(&mem, sizeof(fx_flac_t));
-
- /* Copy the given parameters */
- inst->max_block_size = max_block_size;
- inst->max_channels = max_channels;
-
- /* Fetch the base addresses of the internal pointers. */
- inst->metadata = (fx_flac_metadata_t *)fx_mem_align(
- &mem, sizeof(fx_flac_metadata_t));
- inst->streaminfo = (fx_flac_streaminfo_t *)fx_mem_align(
- &mem, sizeof(fx_flac_streaminfo_t));
- inst->frame_header = (fx_flac_frame_header_t *)fx_mem_align(
- &mem, sizeof(fx_flac_frame_header_t));
- inst->subframe_header = (fx_flac_subframe_header_t *)fx_mem_align(
- &mem, sizeof(fx_flac_subframe_header_t));
- inst->qbuf = (int32_t *)fx_mem_align(&mem, sizeof(int32_t) * 32U);
-
- /* Compute the addresses of the per-channel buffers */
- for (uint8_t i = 0; i < FLAC_MAX_CHANNEL_COUNT; i++) {
- inst->blkbuf[i] = NULL;
- }
- for (uint8_t i = 0; i < max_channels; i++) {
- inst->blkbuf[i] =
- (int32_t *)fx_mem_align(&mem, sizeof(int32_t) * max_block_size);
- }
-
- /* Reset the instance, i.e. zero most/all fields. */
- fx_flac_reset(inst);
- }
- /* Return the original pointer. */
- return inst_unaligned;
-}
-
-void fx_flac_reset(fx_flac_t *inst) {
- inst = (fx_flac_t *)FX_ALIGN_ADDR(inst);
-
- /* Initialize the bitstream reader */
- fx_bitstream_init(&inst->bitstream);
-
- /* Initialize the current metadata block header */
- FX_MEM_ZERO_ALIGNED(inst->metadata);
- inst->metadata->type = META_TYPE_INVALID;
-
- /* Initialize the streaminfo structure */
- FX_MEM_ZERO_ALIGNED(inst->streaminfo);
-
- /* Initialize the frame_header structure */
- FX_MEM_ZERO_ALIGNED(inst->frame_header);
-
- /* Initialize the subframe_header structure */
- FX_MEM_ZERO_ALIGNED(inst->subframe_header);
-
- /* Initialize private member variables */
- inst->state = FLAC_INIT;
- inst->priv_state = FLAC_SYNC_INIT;
- inst->n_bytes_rem = 0U;
- inst->crc8 = 0U;
- inst->coef_cur = 0U;
- inst->partition_cur = 0U;
- inst->partition_sample = 0U;
- inst->rice_unary_counter = 0U;
- inst->chan_cur = 0U;
- inst->blk_cur = 0U;
-}
-
-fx_flac_state_t fx_flac_get_state(const fx_flac_t *inst) {
- return ((const fx_flac_t *)FX_ALIGN_ADDR(inst))->state;
-}
-
-int64_t fx_flac_get_streaminfo(fx_flac_t const *inst,
- fx_flac_streaminfo_key_t key) {
- inst = (fx_flac_t *)FX_ALIGN_ADDR(inst);
- switch (key) {
- case FLAC_KEY_MIN_BLOCK_SIZE:
- return inst->streaminfo->min_block_size;
- case FLAC_KEY_MAX_BLOCK_SIZE:
- return inst->streaminfo->max_block_size;
- case FLAC_KEY_MIN_FRAME_SIZE:
- return inst->streaminfo->min_frame_size;
- case FLAC_KEY_MAX_FRAME_SIZE:
- return inst->streaminfo->max_frame_size;
- case FLAC_KEY_SAMPLE_RATE:
- return inst->streaminfo->sample_rate;
- case FLAC_KEY_N_CHANNELS:
- return inst->streaminfo->n_channels;
- case FLAC_KEY_SAMPLE_SIZE:
- return inst->streaminfo->sample_size;
- case FLAC_KEY_N_SAMPLES:
- return inst->streaminfo->n_samples;
- case FLAC_KEY_MD5_SUM_0:
- case FLAC_KEY_MD5_SUM_1:
- case FLAC_KEY_MD5_SUM_2:
- case FLAC_KEY_MD5_SUM_3:
- case FLAC_KEY_MD5_SUM_4:
- case FLAC_KEY_MD5_SUM_5:
- case FLAC_KEY_MD5_SUM_6:
- case FLAC_KEY_MD5_SUM_7:
- case FLAC_KEY_MD5_SUM_8:
- case FLAC_KEY_MD5_SUM_9:
- case FLAC_KEY_MD5_SUM_A:
- case FLAC_KEY_MD5_SUM_B:
- case FLAC_KEY_MD5_SUM_C:
- case FLAC_KEY_MD5_SUM_D:
- case FLAC_KEY_MD5_SUM_E:
- case FLAC_KEY_MD5_SUM_F:
- return inst->streaminfo->md5_sum[key - FLAC_KEY_MD5_SUM_0];
- default:
- return FLAC_INVALID_METADATA_KEY;
- }
-}
-
-fx_flac_state_t fx_flac_process(fx_flac_t *inst, const uint8_t *in,
- uint32_t *in_len, int32_t *out,
- uint32_t *out_len) {
- inst = (fx_flac_t *)FX_ALIGN_ADDR(inst);
-
- /* Set the current bytestream source to the provided input buffer */
- fx_bitstream_t *bs = &inst->bitstream; /* Alias */
- fx_bitstream_set_source(bs, in, *in_len);
-
- /* Advance the statemachine */
- bool done = false;
- uint32_t out_len_ = 0U;
- fx_flac_state_t old_state = inst->state;
- while (!done) {
- /* Abort once we've reached an error state. */
- if (inst->state == FLAC_ERR) {
- done = true;
- continue; /* Panic, all hope is lost! */
- }
-
- /* Automatically return once the state transitions to a relevant state,
- even if there is still data to read. */
- if (old_state != inst->state) {
- old_state = inst->state;
- switch (inst->state) {
- case FLAC_END_OF_METADATA:
- case FLAC_END_OF_FRAME:
- done = true; /* Good point to return to the caller */
- continue;
- default:
- break;
- }
- }
-
- /* Main state machine. Dispatch calls to the corresponding state
- handlers. These will returns false in case there is no more data
- to read/space to write to. */
- switch (inst->state) {
- case FLAC_INIT:
- done = !_fx_flac_process_init(inst);
- break;
- case FLAC_IN_METADATA:
- done = !_fx_flac_process_in_metadata(inst);
- break;
- case FLAC_END_OF_METADATA:
- case FLAC_END_OF_FRAME:
- inst->state = FLAC_SEARCH_FRAME;
- inst->priv_state = FLAC_FRAME_SYNC;
- break;
- case FLAC_SEARCH_FRAME:
- done = !_fx_flac_process_search_frame(inst);
- break;
- case FLAC_IN_FRAME:
- done = !_fx_flac_process_in_frame(inst);
- break;
- case FLAC_DECODED_FRAME:
- /* If no output buffers are given, just discard the data. */
- if (!out || !out_len) {
- inst->state = FLAC_END_OF_FRAME;
- break;
- }
- out_len_ = *out_len;
- done = !_fx_flac_process_decoded_frame(inst, out, &out_len_);
- break;
- default:
- inst->state = FLAC_ERR; /* Internal error */
- break;
- }
- }
-
- /* Write the number of bytes we read from the input stream to in_len, the
- caller must not provide these bytes again. Also write the number of
- samples we wrote to the output buffer. */
- if (out_len) {
- *out_len = out_len_;
- }
- *in_len = bs->src - in;
-
- /* Return the current state */
- return inst->state;
-}
-
diff --git a/lib/libfoxenflac/include/foxen/flac.h b/lib/libfoxenflac/include/foxen/flac.h
deleted file mode 100644
index ec89ea36..00000000
--- a/lib/libfoxenflac/include/foxen/flac.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * libfoxenflac -- Tiny FLAC Decoder Library
- * Copyright (C) 2018-2022 Andreas Stöckel
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-/**
- * @file flac.h
- *
- * Provides a decoder for FLAC (Free Lossless Audio Codec).
- *
- * @author Andreas Stöckel
- */
-
-#ifndef FOXEN_FLAC_H
-#define FOXEN_FLAC_H
-
-#include
-
-#ifndef FX_EXPORT
-#if __EMSCRIPTEN__
-#import
-#define FX_EXPORT EMSCRIPTEN_KEEPALIVE
-#else
-#define FX_EXPORT
-#endif /* __EMSCRIPTEN__ */
-#endif /* FX_EXPORT */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Value returned by the fx_flac_get_streaminfo() method if the given streaminfo
- * key is invalid.
- */
-#define FLAC_INVALID_METADATA_KEY 0x7FFFFFFFFFFFFFFFULL
-
-/**
- * Maximum number of channels that can be encoded in a FLAC stream.
- */
-#define FLAC_MAX_CHANNEL_COUNT 8U
-
-/**
- * Maximum block size that can be used if the stream is encoded in the FLAC
- * Subset format and the sample rate is smaller than 48000 kHz.
- */
-#define FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ 4608U
-
-/**
- * Maximum block size than can always be safely used if the stream is encoded
- * in the FLAC Subset format.
- */
-#define FLAC_SUBSET_MAX_BLOCK_SIZE 16384U
-
-/**
- * Maximum block size in samples that can be used in a FLAC stream.
- */
-#define FLAC_MAX_BLOCK_SIZE 65535U
-
-/**
- * Opaque struct representing a FLAC decoder.
- */
-struct fx_flac;
-
-/**
- * Typedef for the fx_flac struct.
- */
-typedef struct fx_flac fx_flac_t;
-
-/**
- * Enum representing the state of a FLAC decoder instance.
- */
-typedef enum {
- /**
- * The decoder is in an error state; the decoder cannot recover from this
- * error. This error may for example occur if the data in the stream is
- * invalid, or the stream has a format that is outside the maximum specs
- * that are supported by the decoder. Call fx_flac_reset() and start anew!
- */
- FLAC_ERR = -1,
-
- /**
- * The decoder is currently in its initial state, fx_flac_process() has not
- * been called.
- */
- FLAC_INIT = 0,
-
- /**
- * The decoder found the beginning of the metadata packet!
- */
- FLAC_IN_METADATA = 1,
-
- /**
- * The decoder is done reading the current metadata block, this may be
- * followed by more metadata blocks, in which case the state is reset to
- * FLAC_IN_METADATA.
- */
- FLAC_END_OF_METADATA = 2,
-
- /**
- * The decoder is currently searching for an audio frame.
- */
- FLAC_SEARCH_FRAME = 3,
-
- /**
- * The decoder is currently inside the stream of audio frames.
- */
- FLAC_IN_FRAME = 4,
-
- /**
- * The decoder successfully decoded an entire frame. Write the data to the
- * client.
- */
- FLAC_DECODED_FRAME = 5,
-
- /**
- * The decoder reached the end of a block.
- */
- FLAC_END_OF_FRAME = 6
-} fx_flac_state_t;
-
-/**
- * Enum used in fx_flac_get_streaminfo() to query metadata about the stream.
- */
-typedef enum {
- FLAC_KEY_MIN_BLOCK_SIZE = 0,
- FLAC_KEY_MAX_BLOCK_SIZE = 1,
- FLAC_KEY_MIN_FRAME_SIZE = 2,
- FLAC_KEY_MAX_FRAME_SIZE = 3,
- FLAC_KEY_SAMPLE_RATE = 4,
- FLAC_KEY_N_CHANNELS = 5,
- FLAC_KEY_SAMPLE_SIZE = 6,
- FLAC_KEY_N_SAMPLES = 7,
- FLAC_KEY_MD5_SUM_0 = 128,
- FLAC_KEY_MD5_SUM_1 = 129,
- FLAC_KEY_MD5_SUM_2 = 130,
- FLAC_KEY_MD5_SUM_3 = 131,
- FLAC_KEY_MD5_SUM_4 = 132,
- FLAC_KEY_MD5_SUM_5 = 133,
- FLAC_KEY_MD5_SUM_6 = 134,
- FLAC_KEY_MD5_SUM_7 = 135,
- FLAC_KEY_MD5_SUM_8 = 136,
- FLAC_KEY_MD5_SUM_9 = 137,
- FLAC_KEY_MD5_SUM_A = 138,
- FLAC_KEY_MD5_SUM_B = 139,
- FLAC_KEY_MD5_SUM_C = 140,
- FLAC_KEY_MD5_SUM_D = 141,
- FLAC_KEY_MD5_SUM_E = 142,
- FLAC_KEY_MD5_SUM_F = 143,
-} fx_flac_streaminfo_key_t;
-
-/**
- * Returns the size of the FLAC decoder instance in bytes. This assumes that the
- * FLAC audio that is being decoded uses the maximum settings, i.e. the largest
- * bit depth and block size. See fx_flac_init() regarding parameters.
- *
- * @return zero if the given parameters are out of range, the number of bytes
- * required to hold the FLAC decoder structure otherwise.
- */
-FX_EXPORT uint32_t fx_flac_size(uint32_t max_block_size, uint8_t max_channels);
-
-/**
- * Initializes the FLAC decoder at the given memory location. Each decoder can
- * decode exactly one stream at a time.
- *
- * @param mem is a pointer at the memory region at which the FLAC decoder should
- * store its private data. The memory region must be at last as large as
- * indicated by fx_flac_size(). May be NULL, in which case NULL is returned.
- * @param max_block_size is the maximum block size for which the FLAC instance
- * will provide a buffer. For streams in the Subset format (which is used per
- * default in most FLAC encoders), max_block_size should can be set to 4608 if
- * the sample rate is <= 48000kHz, otherwise, for larger sample rates,
- * max_block_size must be set to 16384.
- * @param max_channels is the maximum number of channels that will be decoded.
- * @return a pointer at the FLAC decoder instance; note that this pointer may be
- * different from what was passed to mem. However, you may still pass the
- * original `mem` as `inst` parameter to other functions. Returns NULL if the
- * input pointer is NULL or the given parameters are invalid.
- */
-FX_EXPORT fx_flac_t *fx_flac_init(void *mem, uint16_t max_block_size,
- uint8_t max_channels);
-
-/**
- * Macro which calls malloc to allocate memory for a new fx_flac instance. The
- * returned pointer must be freed using free. Returns NULL if the allocation
- * fails or the given parameters are invalid.
- *
- * Note that this code is implemented as a macro to prevent explicitly having
- * a dependency on malloc while still providing a convenient allocation routine.
- */
-#define FX_FLAC_ALLOC(max_block_size, max_channels) \
- (fx_flac_size((max_block_size), (max_channels)) == 0U) \
- ? NULL \
- : fx_flac_init(malloc(fx_flac_size((max_block_size), (max_channels))), \
- (max_block_size), (max_channels))
-
-/**
- * Returns a new fx_flac instance that is sufficient to decode FLAC streams in
- * the FLAC Subset format with DAT parameters, i.e. up to 48 kHz, and two
- * channels. This will allocate about 40 kiB of memory.
- */
-#define FX_FLAC_ALLOC_SUBSET_FORMAT_DAT() \
- FX_FLAC_ALLOC(FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, 2U)
-
-/**
- * Returns a new fx_flac instance that is sufficient to decode FLAC streams in
- * the FLAC Subset format. This will allocate about 1.5 MiB of memory.
- */
-#define FX_FLAC_ALLOC_SUBSET_FORMAT_ANY() \
- FX_FLAC_ALLOC(FLAC_SUBSET_MAX_BLOCK_SIZE, FLAC_MAX_CHANNEL_COUNT)
-
-/**
- * Returns a new fx_flac instance that is sufficient to decode any valid FLAC
- * stream. Note that this will allocate between 2-3 MiB of memory.
- */
-#define FX_FLAC_ALLOC_DEFAULT() \
- FX_FLAC_ALLOC(FLAC_MAX_BLOCK_SIZE, FLAC_MAX_CHANNEL_COUNT)
-
-/**
- * Resets the FLAC decoder.
- *
- * @param inst is the FLAC decoder that should be reset.
- */
-FX_EXPORT void fx_flac_reset(fx_flac_t *inst);
-
-/**
- * Returns the current decoder state.
- *
- * @param inst is the FLAC decoder instance for which the state should be
- * returned.
- * @return the current state of the decoder.
- */
-FX_EXPORT fx_flac_state_t fx_flac_get_state(const fx_flac_t *inst);
-
-/**
- * Returns metadata about the FLAC stream that is currently being parsed. This
- * function may only be called if the decoder is in the state
- * FLAC_END_OF_METADATA or greater, otherwise the result may be undefined
- * (it will likely return zero for most of the metadata keys).
- *
- * @param inst is a pointer at the FLAC decoder instance for which the metadata
- * should be retrieved.
- * @param key is the metadata that should be retrieved.
- * @return the requested metadata value or FLAC_INVALID_METADATA_KEY if the
- * given key is unknown.
- */
-FX_EXPORT int64_t fx_flac_get_streaminfo(const fx_flac_t *inst,
- fx_flac_streaminfo_key_t key);
-
-/**
- * Decodes the given raw FLAC data; the given data must be RAW FLAC data as
- * specified in the FLAC format specification https://xiph.org/flac/format.html
- * This function will always return right after the decoder transitions to a new
- * relevant state.
- *
- * @param inst is the decoder instance.
- * @param in is a pointer at the encoded bytestream.
- * @param in_len is a pointer at a integer containing the number of valid bytes
- * in "in". After the function returns, in will contain the number of bytes that
- * were actually read. This number may be zero if the decoder is in the FLAC_ERR
- * or FLAC_STREAM_DONE state, or the internal buffers are full and need to be
- * flushed to the provided output first.
- * @param out is a pointer at a memory region that will accept the decoded
- * interleaved audio data. Samples are decoded as 32-bit signed integer; the
- * minimum and maximum value will depend on the original bit depth of the audio
- * stored in the bitstream. If this is NULL, the decoder will silently discard
- * the output.
- * @param out_len is a pointer at an integer containing the number of available
- * signed 32-bit integers at the memory address pointed at by out. After the
- * function returns, this value will contain the number of samples that were
- * written. If this is NULL, the deocder will silently discard the output.
- * @return the current state of the decoder. If the state transitions to
- * FLAC_END_OF_METADATA, FLAC_END_OF_FRAME or FLAC_END_OF_STREAM this function
- * will return immediately; only the data up to the point causing the transition
- * has been read.
- */
-FX_EXPORT fx_flac_state_t fx_flac_process(fx_flac_t *inst, const uint8_t *in,
- uint32_t *in_len, int32_t *out,
- uint32_t *out_len);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* FOXEN_FLAC_H */
diff --git a/lib/libfoxenflac/CMakeLists.txt b/lib/miniflac/CMakeLists.txt
similarity index 57%
rename from lib/libfoxenflac/CMakeLists.txt
rename to lib/miniflac/CMakeLists.txt
index 0389236b..68df4ca5 100644
--- a/lib/libfoxenflac/CMakeLists.txt
+++ b/lib/miniflac/CMakeLists.txt
@@ -1,8 +1,4 @@
# Copyright 2023 jacqueline
#
# SPDX-License-Identifier: GPL-3.0-only
-
-idf_component_register(
- SRCS "flac.c"
- INCLUDE_DIRS "include"
-)
+idf_component_register(SRCS miniflac.c INCLUDE_DIRS .)
diff --git a/lib/miniflac/miniflac.c b/lib/miniflac/miniflac.c
new file mode 100644
index 00000000..a4f1081e
--- /dev/null
+++ b/lib/miniflac/miniflac.c
@@ -0,0 +1,5 @@
+#define MINIFLAC_IMPLEMENTATION
+#define MINIFLAC_API
+#define MINIFLAC_PRIVATE static inline
+
+#include "miniflac.h"
diff --git a/lib/miniflac/miniflac.h b/lib/miniflac/miniflac.h
new file mode 100644
index 00000000..5a5f7e68
--- /dev/null
+++ b/lib/miniflac/miniflac.h
@@ -0,0 +1,6092 @@
+/* SPDX-License-Identifier: 0BSD
+Copyright (C) 2022 John Regan
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+*/
+#ifndef MINIFLAC_H
+#define MINIFLAC_H
+
+/*
+
+Building
+========
+
+In one C file, define MINIFLAC_IMPLEMENTATION before including this header, like:
+#define MINIFLAC_IMPLEMENTATION
+#include "miniflac.h"
+
+Usage
+=====
+
+You'll want to allocate a decoder, initialize it with miniflac_init, then start
+pushing data into it with functions like miniflac_sync or miniflac_decode.
+
+All the "feeding" functions take the same first 4 parameters:
+ 1. miniflac* pFlac - a pointer to a miniflac struct.
+ 2. const uint8_t* data - a pointer to a stream of bytes to push.
+ 3. uint32_t length - the length of your stream of bytes.
+ 4. uint32_t* out_length - an out-variable, it will be updated with the
+ number of bytes consumed.
+You'll to save any un-consumed bytes for your next call.
+
+All the "feeding" / public functions return a MINIFLAC_RESULT enum, these are the
+important values:
+ < 0 : error
+ 0 : more data is required (MINIFLAC_CONTINUE)
+ 1 : success (MINIFLAC_OK)
+
+You can use miniflac_sync to sync to a block boundary. It will automatically parse
+a metadata block header or frame header, so you can inspect it and check on things
+like the block size, bits-per-sample, etc. See the various struct definitions down
+below. The example program in "examples/basic-decoder.c" does this. Keep calling
+it until you get something other than MINIFLAC_CONTINUE (0). MINIFLAC_OK (1) means
+you've found a block boundary. Anything < 0 is an error.
+
+You can look at the .state field in the miniflac struct to see if you're in a
+metadata block or audio frame, and proceed accordingly.
+
+Decoding audio is done with miniflac_decode. You don't *have* to use miniflac_sync first,
+you could just call miniflac_decode (this is done in the example program
+"examples/single-byte-decoder.c"). The advantage of miniflac_sync is you can
+look at the frame properties in the header before you start decoding.
+
+miniflac_decode behaves similarly to miniflac_sync - when it returns MINIFLAC_OK (1),
+your output buffer will have decoded audio samples in it. You'll be at the end
+of the audio frame, so you can either call miniflac_sync to check the header of the next
+frame, or call miniflac_decode to continue on.
+
+*/
+
+#include
+#include
+#include
+
+#if !defined(MINIFLAC_API)
+ #ifdef MINIFLAC_DLL
+ #ifdef _WIN32
+ #define MINIFLAC_DLL_IMPORT __declspec(dllimport)
+ #define MINIFLAC_DLL_EXPORT __declspec(dllexport)
+ #define MINIFLAC_DLL_PRIVATE static
+ #else
+ #if defined(__GNUC__) && __GNUC__ >= 4
+ #define MINIFLAC_DLL_IMPORT __attribute__((visibility("default")))
+ #define MINIFLAC_DLL_EXPORT __attribute__((visibility("default")))
+ #define MINIFLAC_DLL_PRIVATE __attribute__((visibility("hidden")))
+ #else
+ #define MINIFLAC_DLL_IMPORT
+ #define MINIFLAC_DLL_EXPORT
+ #define MINIFLAC_DLL_PRIVATE static
+ #endif
+ #endif
+
+ #ifdef MINIFLAC_IMPLEMENTATION
+ #define MINIFLAC_API MINIFLAC_DLL_EXPORT
+ #else
+ #define MINIFLAC_API MINIFLAC_DLL_IMPORT
+ #endif
+ #define MINIFLAC_PRIVATE MINIFLAC_DLL_PRIVATE
+ #else
+ #define MINIFLAC_API extern
+ #define MINIFLAC_PRIVATE static
+ #endif
+#endif
+
+#if defined(__GNUC__) && __GNUC__ > 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)
+#define MINIFLAC_CONST __attribute__((__const__))
+#endif
+
+#define MINIFLAC_APPLICATION_H
+#define MINIFLAC_COMMON_H
+#define MINIFLAC_BITREADER_H
+#define MINIFLAC_CUESHEET_H
+#define MINIFLAC_FRAME_H
+#define MINIFLAC_FRAMEHEADER_H
+#define MINIFLAC_METADATA_H
+#define MINIFLAC_METADATA_HEADER_H
+#define MINIFLAC_OGG_H
+#define MINIFLAC_OGGHEADER_H
+#define MINIFLAC_PADDING_H
+#define MINIFLAC_PICTURE_H
+#define MINIFLAC_RESIDUAL_H
+#define MINIFLAC_SEEKTABLE_H
+#define MINIFLAC_STREAMINFO_H
+#define MINIFLAC_STREAMMARKER_H
+#define MINIFLAC_SUBFRAME_CONSTANT_H
+#define MINIFLAC_SUBFRAME_FIXED_H
+#define MINIFLAC_SUBFRAME_H
+#define MINIFLAC_SUBFRAME_HEADER_H
+#define MINIFLAC_SUBFRAME_LPC_H
+#define MINIFLAC_SUBFRAME_VERBATIM_H
+#define MINIFLAC_UNPACK_H
+#define MINIFLAC_VORBIS_COMMENT_H
+#define MFLAC_H
+
+#ifndef MINIFLAC_CONST
+#define MINIFLAC_CONST
+#endif
+
+enum MINIFLAC_RESULT {
+ MINIFLAC_OGG_HEADER_NOTFLAC = -18, /* attempted to read an Ogg header packet that isn't a FLAC-in-Ogg packet */
+ MINIFLAC_SUBFRAME_RESERVED_TYPE = -17, /* subframe header specified a reserved type */
+ MINIFLAC_SUBFRAME_RESERVED_BIT = -16, /* subframe header found a non-zero value in the reserved bit */
+ MINIFLAC_STREAMMARKER_INVALID = -15, /* encountered an illegal value while parsing the fLaC stream marker */
+ MINIFLAC_RESERVED_CODING_METHOD = -14, /* a residual block used a reserved coding method */
+ MINIFLAC_METADATA_TYPE_RESERVED = -13, /* a metadata header used a reserved type */
+ MINIFLAC_METADATA_TYPE_INVALID = -12, /* a metadata header used a invalid type */
+ MINIFLAC_FRAME_RESERVED_SAMPLE_SIZE = -11, /* the frame header lists reserved sample size */
+ MINIFLAC_FRAME_RESERVED_CHANNEL_ASSIGNMENT = -10, /* the frame header lists reserved channel assignment */
+ MINIFLAC_FRAME_INVALID_SAMPLE_SIZE = -9, /* the frame header sample rate was invalid */
+ MINIFLAC_FRAME_INVALID_SAMPLE_RATE = -8, /* the frame header sample rate was invalid */
+ MINIFLAC_FRAME_RESERVED_BLOCKSIZE = -7, /* the frame header lists a reserved block size */
+ MINIFLAC_FRAME_RESERVED_BIT2 = -6, /* the second reserved bit was non-zero when parsing the frame header */
+ MINIFLAC_FRAME_RESERVED_BIT1 = -5, /* the first reserved bit was non-zero when parsing the frame header */
+ MINIFLAC_FRAME_SYNCCODE_INVALID = -4, /* error when parsing a header sync code */
+ MINIFLAC_FRAME_CRC16_INVALID = -3, /* error in crc16 while decoding frame footer */
+ MINIFLAC_FRAME_CRC8_INVALID = -2, /* error in crc8 while decoding frame header */
+ MINIFLAC_ERROR = -1, /* generic error, likely in an invalid state */
+ MINIFLAC_CONTINUE = 0, /* needs more data, otherwise fine */
+ MINIFLAC_OK = 1, /* generic "OK" */
+ MINIFLAC_METADATA_END = 2, /* used to signify end-of-data in a metadata block */
+};
+
+enum MINIFLAC_OGGHEADER_STATE {
+ MINIFLAC_OGGHEADER_PACKETTYPE,
+ MINIFLAC_OGGHEADER_F,
+ MINIFLAC_OGGHEADER_L,
+ MINIFLAC_OGGHEADER_A,
+ MINIFLAC_OGGHEADER_C,
+ MINIFLAC_OGGHEADER_MAJOR,
+ MINIFLAC_OGGHEADER_MINOR,
+ MINIFLAC_OGGHEADER_HEADERPACKETS,
+};
+
+enum MINIFLAC_OGG_STATE {
+ MINIFLAC_OGG_CAPTUREPATTERN_O,
+ MINIFLAC_OGG_CAPTUREPATTERN_G1,
+ MINIFLAC_OGG_CAPTUREPATTERN_G2,
+ MINIFLAC_OGG_CAPTUREPATTERN_S,
+ MINIFLAC_OGG_VERSION,
+ MINIFLAC_OGG_HEADERTYPE,
+ MINIFLAC_OGG_GRANULEPOS,
+ MINIFLAC_OGG_SERIALNO,
+ MINIFLAC_OGG_PAGENO,
+ MINIFLAC_OGG_CHECKSUM,
+ MINIFLAC_OGG_PAGESEGMENTS,
+ MINIFLAC_OGG_SEGMENTTABLE,
+ MINIFLAC_OGG_DATA,
+ MINIFLAC_OGG_SKIP,
+};
+
+enum MINIFLAC_STREAMMARKER_STATE {
+ MINIFLAC_STREAMMARKER_F,
+ MINIFLAC_STREAMMARKER_L,
+ MINIFLAC_STREAMMARKER_A,
+ MINIFLAC_STREAMMARKER_C,
+};
+
+enum MINIFLAC_METADATA_TYPE {
+ MINIFLAC_METADATA_STREAMINFO = 0,
+ MINIFLAC_METADATA_PADDING = 1,
+ MINIFLAC_METADATA_APPLICATION = 2,
+ MINIFLAC_METADATA_SEEKTABLE = 3,
+ MINIFLAC_METADATA_VORBIS_COMMENT = 4,
+ MINIFLAC_METADATA_CUESHEET = 5,
+ MINIFLAC_METADATA_PICTURE = 6,
+ MINIFLAC_METADATA_INVALID = 127,
+ MINIFLAC_METADATA_UNKNOWN = 128,
+};
+
+enum MINIFLAC_METADATA_HEADER_STATE {
+ MINIFLAC_METADATA_LAST_FLAG,
+ MINIFLAC_METADATA_BLOCK_TYPE,
+ MINIFLAC_METADATA_LENGTH,
+};
+
+enum MINIFLAC_STREAMINFO_STATE {
+ MINIFLAC_STREAMINFO_MINBLOCKSIZE,
+ MINIFLAC_STREAMINFO_MAXBLOCKSIZE,
+ MINIFLAC_STREAMINFO_MINFRAMESIZE,
+ MINIFLAC_STREAMINFO_MAXFRAMESIZE,
+ MINIFLAC_STREAMINFO_SAMPLERATE,
+ MINIFLAC_STREAMINFO_CHANNELS,
+ MINIFLAC_STREAMINFO_BPS,
+ MINIFLAC_STREAMINFO_TOTALSAMPLES,
+ MINIFLAC_STREAMINFO_MD5,
+};
+
+enum MINIFLAC_VORBISCOMMENT_STATE {
+ MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH,
+ MINIFLAC_VORBISCOMMENT_VENDOR_STRING,
+ MINIFLAC_VORBISCOMMENT_TOTAL_COMMENTS,
+ MINIFLAC_VORBISCOMMENT_COMMENT_LENGTH,
+ MINIFLAC_VORBISCOMMENT_COMMENT_STRING,
+};
+
+enum MINIFLAC_PICTURE_STATE {
+ MINIFLAC_PICTURE_TYPE,
+ MINIFLAC_PICTURE_MIME_LENGTH,
+ MINIFLAC_PICTURE_MIME_STRING,
+ MINIFLAC_PICTURE_DESCRIPTION_LENGTH,
+ MINIFLAC_PICTURE_DESCRIPTION_STRING,
+ MINIFLAC_PICTURE_WIDTH,
+ MINIFLAC_PICTURE_HEIGHT,
+ MINIFLAC_PICTURE_COLORDEPTH,
+ MINIFLAC_PICTURE_TOTALCOLORS,
+ MINIFLAC_PICTURE_PICTURE_LENGTH,
+ MINIFLAC_PICTURE_PICTURE_DATA,
+};
+
+enum MINIFLAC_CUESHEET_STATE {
+ MINIFLAC_CUESHEET_CATALOG,
+ MINIFLAC_CUESHEET_LEADIN,
+ MINIFLAC_CUESHEET_CDFLAG,
+ MINIFLAC_CUESHEET_SHEET_RESERVE,
+ MINIFLAC_CUESHEET_TRACKS,
+ MINIFLAC_CUESHEET_TRACKOFFSET,
+ MINIFLAC_CUESHEET_TRACKNUMBER,
+ MINIFLAC_CUESHEET_TRACKISRC,
+ MINIFLAC_CUESHEET_TRACKTYPE,
+ MINIFLAC_CUESHEET_TRACKPREEMPH,
+ MINIFLAC_CUESHEET_TRACK_RESERVE,
+ MINIFLAC_CUESHEET_TRACKPOINTS,
+ MINIFLAC_CUESHEET_INDEX_OFFSET,
+ MINIFLAC_CUESHEET_INDEX_NUMBER,
+ MINIFLAC_CUESHEET_INDEX_RESERVE,
+};
+
+enum MINIFLAC_SEEKTABLE_STATE {
+ MINIFLAC_SEEKTABLE_SAMPLE_NUMBER,
+ MINIFLAC_SEEKTABLE_SAMPLE_OFFSET,
+ MINIFLAC_SEEKTABLE_SAMPLES,
+};
+
+enum MINIFLAC_APPLICATION_STATE {
+ MINIFLAC_APPLICATION_ID,
+ MINIFLAC_APPLICATION_DATA,
+};
+
+enum MINIFLAC_METADATA_STATE {
+ MINIFLAC_METADATA_HEADER,
+ MINIFLAC_METADATA_DATA,
+};
+
+enum MINIFLAC_RESIDUAL_STATE {
+ MINIFLAC_RESIDUAL_CODING_METHOD,
+ MINIFLAC_RESIDUAL_PARTITION_ORDER,
+ MINIFLAC_RESIDUAL_RICE_PARAMETER,
+ MINIFLAC_RESIDUAL_RICE_SIZE, /* used when rice_parameter is an escape code */
+ MINIFLAC_RESIDUAL_RICE_VALUE, /* used when rice_parameter is an escape code */
+ MINIFLAC_RESIDUAL_MSB, /* used when reading MSB bits */
+ MINIFLAC_RESIDUAL_LSB, /* used when reading MSB bits */
+};
+
+enum MINIFLAC_SUBFRAME_FIXED_STATE {
+ MINIFLAC_SUBFRAME_FIXED_DECODE,
+};
+
+enum MINIFLAC_SUBFRAME_LPC_STATE {
+ MINIFLAC_SUBFRAME_LPC_PRECISION,
+ MINIFLAC_SUBFRAME_LPC_SHIFT,
+ MINIFLAC_SUBFRAME_LPC_COEFF,
+};
+
+enum MINIFLAC_SUBFRAME_CONSTANT_STATE {
+ MINIFLAC_SUBFRAME_CONSTANT_DECODE,
+};
+
+enum MINIFLAC_SUBFRAME_VERBATIM_STATE {
+ MINIFLAC_SUBFRAME_VERBATIM_DECODE,
+};
+
+enum MINIFLAC_SUBFRAME_TYPE {
+ MINIFLAC_SUBFRAME_TYPE_UNKNOWN,
+ MINIFLAC_SUBFRAME_TYPE_CONSTANT,
+ MINIFLAC_SUBFRAME_TYPE_FIXED,
+ MINIFLAC_SUBFRAME_TYPE_LPC,
+ MINIFLAC_SUBFRAME_TYPE_VERBATIM,
+};
+
+enum MINIFLAC_SUBFRAME_HEADER_STATE {
+ MINIFLAC_SUBFRAME_HEADER_RESERVEBIT1,
+ MINIFLAC_SUBFRAME_HEADER_KIND,
+ MINIFLAC_SUBFRAME_HEADER_WASTED_BITS,
+ MINIFLAC_SUBFRAME_HEADER_UNARY,
+};
+
+enum MINIFLAC_SUBFRAME_STATE {
+ MINIFLAC_SUBFRAME_HEADER,
+ MINIFLAC_SUBFRAME_CONSTANT,
+ MINIFLAC_SUBFRAME_VERBATIM,
+ MINIFLAC_SUBFRAME_FIXED,
+ MINIFLAC_SUBFRAME_LPC,
+};
+
+enum MINIFLAC_CHASSGN {
+ MINIFLAC_CHASSGN_NONE,
+ MINIFLAC_CHASSGN_LEFT_SIDE,
+ MINIFLAC_CHASSGN_RIGHT_SIDE,
+ MINIFLAC_CHASSGN_MID_SIDE,
+};
+
+enum MINIFLAC_FRAME_HEADER_STATE {
+ MINIFLAC_FRAME_HEADER_SYNC,
+ MINIFLAC_FRAME_HEADER_RESERVEBIT_1,
+ MINIFLAC_FRAME_HEADER_BLOCKINGSTRATEGY,
+ MINIFLAC_FRAME_HEADER_BLOCKSIZE,
+ MINIFLAC_FRAME_HEADER_SAMPLERATE,
+ MINIFLAC_FRAME_HEADER_CHANNELASSIGNMENT,
+ MINIFLAC_FRAME_HEADER_SAMPLESIZE,
+ MINIFLAC_FRAME_HEADER_RESERVEBIT_2,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_1,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_2,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_3,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_4,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_5,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_6,
+ MINIFLAC_FRAME_HEADER_SAMPLENUMBER_7,
+ MINIFLAC_FRAME_HEADER_BLOCKSIZE_MAYBE,
+ MINIFLAC_FRAME_HEADER_SAMPLERATE_MAYBE,
+ MINIFLAC_FRAME_HEADER_CRC8,
+};
+
+enum MINIFLAC_FRAME_STATE {
+ MINIFLAC_FRAME_HEADER,
+ MINIFLAC_FRAME_SUBFRAME,
+ MINIFLAC_FRAME_FOOTER,
+};
+
+enum MINIFLAC_STATE {
+ MINIFLAC_OGGHEADER, /* will try to find an ogg header */
+ MINIFLAC_STREAMMARKER_OR_FRAME, /* poke for a stream marker or audio frame
+ */
+ MINIFLAC_STREAMMARKER, /* reading a stream marker */
+ MINIFLAC_METADATA_OR_FRAME, /* will try to find a frame sync code or try to parse a metadata block */
+ MINIFLAC_METADATA, /* currently reading a metadata block */
+ MINIFLAC_FRAME, /* currently reading an audio frame */
+};
+
+enum MINIFLAC_CONTAINER {
+ MINIFLAC_CONTAINER_UNKNOWN,
+ MINIFLAC_CONTAINER_NATIVE,
+ MINIFLAC_CONTAINER_OGG,
+};
+
+enum MFLAC_RESULT {
+ MFLAC_EOF = 0,
+ MFLAC_OK = 1,
+ MFLAC_METADATA_END = 2,
+};
+
+
+typedef size_t (*mflac_readcb)(uint8_t* buffer, size_t bytes, void* userdata);
+
+struct miniflac_bitreader_s {
+ uint64_t val;
+ uint8_t bits;
+ uint8_t crc8;
+ uint16_t crc16;
+ uint32_t pos;
+ uint32_t len;
+ const uint8_t* buffer;
+ uint32_t tot; /* total bytes read since last reset */
+};
+
+struct miniflac_oggheader_s {
+ enum MINIFLAC_OGGHEADER_STATE state;
+};
+
+struct miniflac_ogg_s {
+ enum MINIFLAC_OGG_STATE state;
+ struct miniflac_bitreader_s br; /* maintain our own bitreader */
+ uint8_t version;
+ uint8_t headertype;
+ int64_t granulepos;
+ int32_t serialno;
+ uint32_t pageno;
+ uint8_t segments;
+ uint8_t curseg; /* current position within the segment table */
+ uint16_t length; /* length of data within page */
+ uint16_t pos; /* where we are within page */
+};
+
+struct miniflac_streammarker_s {
+ enum MINIFLAC_STREAMMARKER_STATE state;
+};
+
+struct miniflac_metadata_header_s {
+ enum MINIFLAC_METADATA_HEADER_STATE state;
+ uint8_t is_last;
+ uint8_t type_raw;
+ enum MINIFLAC_METADATA_TYPE type;
+ uint32_t length;
+};
+
+struct miniflac_streaminfo_s {
+ enum MINIFLAC_STREAMINFO_STATE state;
+ uint8_t pos;
+ uint32_t sample_rate;
+ uint8_t bps;
+};
+
+struct miniflac_vorbis_comment_s {
+ enum MINIFLAC_VORBISCOMMENT_STATE state;
+ uint32_t len; /* length of the current string we're decoding */
+ uint32_t pos; /* position within current string */
+ uint32_t tot; /* total comments */
+ uint32_t cur; /* current comment being decoded */
+};
+
+struct miniflac_picture_s {
+ enum MINIFLAC_PICTURE_STATE state;
+ uint32_t len; /* length of the current string/data we're decoding */
+ uint32_t pos; /* position within current string */
+};
+
+struct miniflac_cuesheet_s {
+ enum MINIFLAC_CUESHEET_STATE state;
+ uint32_t pos;
+ uint8_t track;
+ uint8_t tracks;
+ uint8_t point;
+ uint8_t points;
+};
+
+struct miniflac_seektable_s {
+ enum MINIFLAC_SEEKTABLE_STATE state;
+ uint32_t len; /* number of seekpoints */
+ uint32_t pos; /* current seekpoint */
+};
+
+struct miniflac_application_s {
+ enum MINIFLAC_APPLICATION_STATE state;
+ uint32_t len; /* length of data */
+ uint32_t pos; /* current byte */
+};
+
+struct miniflac_padding_s {
+ uint32_t len; /* length of data */
+ uint32_t pos; /* current byte */
+};
+
+struct miniflac_metadata_s {
+ enum MINIFLAC_METADATA_STATE state;
+ uint32_t pos;
+ struct miniflac_metadata_header_s header;
+ struct miniflac_streaminfo_s streaminfo;
+ struct miniflac_vorbis_comment_s vorbis_comment;
+ struct miniflac_picture_s picture;
+ struct miniflac_cuesheet_s cuesheet;
+ struct miniflac_seektable_s seektable;
+ struct miniflac_application_s application;
+ struct miniflac_padding_s padding;
+};
+
+struct miniflac_residual_s {
+ enum MINIFLAC_RESIDUAL_STATE state;
+ uint8_t coding_method;
+ uint8_t partition_order;
+ uint8_t rice_parameter;
+ uint8_t rice_size;
+ uint32_t msb; /* unsure what the max for this is */
+ uint8_t rice_parameter_size; /* 4 or 5 based on coding method */
+ int32_t value; /* current residual value */
+
+ uint32_t partition; /* current partition */
+ uint32_t partition_total; /* total partitions */
+
+ uint32_t residual; /* current residual within partition */
+ uint32_t residual_total; /* total residuals in partition */
+};
+
+struct miniflac_subframe_fixed_s {
+ enum MINIFLAC_SUBFRAME_FIXED_STATE state;
+ uint32_t pos;
+};
+
+struct miniflac_subframe_lpc_s {
+ enum MINIFLAC_SUBFRAME_LPC_STATE state;
+ uint32_t pos;
+ uint8_t precision;
+ uint8_t shift;
+ uint8_t coeff;
+ int32_t coefficients[32];
+};
+
+struct miniflac_subframe_constant_s {
+ enum MINIFLAC_SUBFRAME_CONSTANT_STATE state;
+};
+
+struct miniflac_subframe_verbatim_s {
+ enum MINIFLAC_SUBFRAME_VERBATIM_STATE state;
+ uint32_t pos;
+};
+
+struct miniflac_subframe_header_s {
+ enum MINIFLAC_SUBFRAME_HEADER_STATE state;
+ enum MINIFLAC_SUBFRAME_TYPE type;
+ uint8_t order;
+ uint8_t wasted_bits;
+ uint8_t type_raw;
+};
+
+struct miniflac_subframe_s {
+ enum MINIFLAC_SUBFRAME_STATE state;
+ uint8_t bps; /* effective bps for this subframe */
+ struct miniflac_subframe_header_s header;
+ struct miniflac_subframe_constant_s constant;
+ struct miniflac_subframe_verbatim_s verbatim;
+ struct miniflac_subframe_fixed_s fixed;
+ struct miniflac_subframe_lpc_s lpc;
+ struct miniflac_residual_s residual;
+};
+
+struct miniflac_frame_header_s {
+ uint8_t block_size_raw; /* block size value direct from header */
+ uint8_t sample_rate_raw; /* sample rate value direct from header */
+ uint8_t channel_assignment_raw; /* channel assignment value direct from header */
+ uint8_t blocking_strategy;
+ uint16_t block_size; /* calculated/parsed block size */
+ uint32_t sample_rate; /* calculated/parsed sample rate */
+ enum MINIFLAC_CHASSGN channel_assignment;
+ uint8_t channels;
+ uint8_t bps;
+ union {
+ uint64_t sample_number;
+ uint32_t frame_number;
+ };
+ uint8_t crc8;
+ enum MINIFLAC_FRAME_HEADER_STATE state;
+};
+
+struct miniflac_frame_s {
+ enum MINIFLAC_FRAME_STATE state;
+ uint8_t cur_subframe;
+ uint16_t crc16;
+ size_t size; /* size of the frame, in bytes, only valid after decode */
+ struct miniflac_frame_header_s header;
+ struct miniflac_subframe_s subframe;
+};
+
+struct miniflac_s {
+ enum MINIFLAC_STATE state;
+ enum MINIFLAC_CONTAINER container;
+ struct miniflac_bitreader_s br;
+ struct miniflac_ogg_s ogg;
+ struct miniflac_oggheader_s oggheader;
+ struct miniflac_streammarker_s streammarker;
+ struct miniflac_metadata_s metadata;
+ struct miniflac_frame_s frame;
+ int32_t oggserial;
+ uint8_t oggserial_set;
+};
+
+struct mflac_s {
+ struct miniflac_s flac;
+ mflac_readcb read;
+ void* userdata;
+ size_t bufpos;
+ size_t buflen;
+#ifndef MFLAC_BUFFER_SIZE
+#define MFLAC_BUFFER_SIZE 16384
+#endif
+ uint8_t buffer[MFLAC_BUFFER_SIZE];
+};
+
+
+typedef struct miniflac_bitreader_s miniflac_bitreader_t;
+typedef struct miniflac_oggheader_s miniflac_oggheader_t;
+typedef struct miniflac_ogg_s miniflac_ogg_t;
+typedef struct miniflac_streammarker_s miniflac_streammarker_t;
+typedef struct miniflac_metadata_header_s miniflac_metadata_header_t;
+typedef struct miniflac_streaminfo_s miniflac_streaminfo_t;
+typedef struct miniflac_vorbis_comment_s miniflac_vorbis_comment_t;
+typedef struct miniflac_picture_s miniflac_picture_t;
+typedef struct miniflac_cuesheet_s miniflac_cuesheet_t;
+typedef struct miniflac_seektable_s miniflac_seektable_t;
+typedef struct miniflac_application_s miniflac_application_t;
+typedef struct miniflac_padding_s miniflac_padding_t;
+typedef struct miniflac_metadata_s miniflac_metadata_t;
+typedef struct miniflac_residual_s miniflac_residual_t;
+typedef struct miniflac_subframe_fixed_s miniflac_subframe_fixed_t;
+typedef struct miniflac_subframe_lpc_s miniflac_subframe_lpc_t;
+typedef struct miniflac_subframe_constant_s miniflac_subframe_constant_t;
+typedef struct miniflac_subframe_verbatim_s miniflac_subframe_verbatim_t;
+typedef struct miniflac_subframe_header_s miniflac_subframe_header_t;
+typedef struct miniflac_subframe_s miniflac_subframe_t;
+typedef struct miniflac_frame_header_s miniflac_frame_header_t;
+typedef struct miniflac_frame_s miniflac_frame_t;
+typedef struct miniflac_s miniflac_t;
+typedef struct mflac_s mflac_t;
+
+typedef enum MINIFLAC_RESULT MINIFLAC_RESULT;
+typedef enum MINIFLAC_OGGHEADER_STATE MINIFLAC_OGGHEADER_STATE;
+typedef enum MINIFLAC_OGG_STATE MINIFLAC_OGG_STATE;
+typedef enum MINIFLAC_STREAMMARKER_STATE MINIFLAC_STREAMMARKER_STATE;
+typedef enum MINIFLAC_METADATA_TYPE MINIFLAC_METADATA_TYPE;
+typedef enum MINIFLAC_METADATA_HEADER_STATE MINIFLAC_METADATA_HEADER_STATE;
+typedef enum MINIFLAC_STREAMINFO_STATE MINIFLAC_STREAMINFO_STATE;
+typedef enum MINIFLAC_VORBISCOMMENT_STATE MINIFLAC_VORBISCOMMENT_STATE;
+typedef enum MINIFLAC_PICTURE_STATE MINIFLAC_PICTURE_STATE;
+typedef enum MINIFLAC_CUESHEET_STATE MINIFLAC_CUESHEET_STATE;
+typedef enum MINIFLAC_SEEKTABLE_STATE MINIFLAC_SEEKTABLE_STATE;
+typedef enum MINIFLAC_APPLICATION_STATE MINIFLAC_APPLICATION_STATE;
+typedef enum MINIFLAC_METADATA_STATE MINIFLAC_METADATA_STATE;
+typedef enum MINIFLAC_RESIDUAL_STATE MINIFLAC_RESIDUAL_STATE;
+typedef enum MINIFLAC_SUBFRAME_FIXED_STATE MINIFLAC_SUBFRAME_FIXED_STATE;
+typedef enum MINIFLAC_SUBFRAME_LPC_STATE MINIFLAC_SUBFRAME_LPC_STATE;
+typedef enum MINIFLAC_SUBFRAME_CONSTANT_STATE MINIFLAC_SUBFRAME_CONSTANT_STATE;
+typedef enum MINIFLAC_SUBFRAME_VERBATIM_STATE MINIFLAC_SUBFRAME_VERBATIM_STATE;
+typedef enum MINIFLAC_SUBFRAME_TYPE MINIFLAC_SUBFRAME_TYPE;
+typedef enum MINIFLAC_SUBFRAME_HEADER_STATE MINIFLAC_SUBFRAME_HEADER_STATE;
+typedef enum MINIFLAC_SUBFRAME_STATE MINIFLAC_SUBFRAME_STATE;
+typedef enum MINIFLAC_CHASSGN MINIFLAC_CHASSGN;
+typedef enum MINIFLAC_FRAME_HEADER_STATE MINIFLAC_FRAME_HEADER_STATE;
+typedef enum MINIFLAC_FRAME_STATE MINIFLAC_FRAME_STATE;
+typedef enum MINIFLAC_STATE MINIFLAC_STATE;
+typedef enum MINIFLAC_CONTAINER MINIFLAC_CONTAINER;
+typedef enum MFLAC_RESULT MFLAC_RESULT;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* returns the number of bytes needed for the miniflac struct (for malloc, etc) */
+MINIFLAC_API
+MINIFLAC_CONST
+size_t
+miniflac_size(void);
+
+/* give the container type if you know the kind of container,
+ * otherwise 0 for unknown */
+MINIFLAC_API
+void
+miniflac_init(miniflac_t* pFlac, MINIFLAC_CONTAINER container);
+
+/* sync to the next metadata block or frame, parses the metadata header or frame header */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_sync(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length);
+
+/* decode a frame of audio, automatically skips metadata if needed */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_decode(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, int32_t** samples);
+
+/* functions to query the state without inspecting structs,
+ * only valid to call after miniflac_sync returns MINIFLAC_OK */
+MINIFLAC_API
+uint8_t
+miniflac_is_metadata(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_is_frame(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_last(miniflac_t* pFlac);
+
+MINIFLAC_API
+MINIFLAC_METADATA_TYPE
+miniflac_metadata_type(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint32_t
+miniflac_metadata_length(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_streaminfo(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_padding(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_application(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_seektable(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_vorbis_comment(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_cuesheet(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_picture(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_frame_blocking_strategy(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint16_t
+miniflac_frame_block_size(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint32_t
+miniflac_frame_sample_rate(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_frame_channels(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint8_t
+miniflac_frame_bps(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint64_t
+miniflac_frame_sample_number(miniflac_t* pFlac);
+
+MINIFLAC_API
+uint32_t
+miniflac_frame_frame_number(miniflac_t* pFlac);
+
+/* get the minimum block size from a streaminfo block */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_min_block_size(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint16_t* min_block_size);
+
+/* get the maximum block size */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_max_block_size(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint16_t* max_block_size);
+
+/* get the minimum frame size */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_min_frame_size(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* min_frame_size);
+
+/* get the maximum frame size */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_max_frame_size(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* max_frame_size);
+
+/* get the sample rate */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_sample_rate(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* sample_rate);
+
+/* get the channel count */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_channels(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* channels);
+
+/* get the bits per second */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_bps(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* bps);
+
+/* get the total samples */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_total_samples(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint64_t* total_samples);
+
+/* get the md5 length (always 16) */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_md5_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* md5_length);
+
+/* get the md5 string */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_streaminfo_md5_data(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* get the length of the vendor string, automatically skips metadata blocks, throws an error on audio frames */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_vorbis_comment_vendor_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* vendor_length);
+
+/* get the vendor string, automatically skips metadata blocks, throws an error on audio frames */
+/* will NOT be NULL-terminated! */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_vorbis_comment_vendor_string(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* get the total number of comments, automatically skips metadata blocks, throws an error on audio frames */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_vorbis_comment_total(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* total_comments);
+
+/* get the next comment length, automatically skips metadata blocks, throws an error on audio frames */
+/* returns MINIFLAC_METADATA_END when out of comments */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_vorbis_comment_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* comment_length);
+
+/* get the next comment string, automatically skips metadata blocks, throws an error on audio frames */
+/* will NOT be NULL-terminated! */
+/* returns MINIFLAC_METADATA_END when out of comments */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_vorbis_comment_string(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* read a picture type */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_type(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_type);
+
+/* read a picture mime string length */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_mime_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_mime_length);
+
+/* read a picture mime string */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_mime_string(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* read a picture description string length */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_description_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_description_length);
+
+/* read a picture description string */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_description_string(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* read a picture width */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_width(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_width);
+
+/* read a picture height */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_height(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_height);
+
+/* read a picture colordepth */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_colordepth(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_colordepth);
+
+/* read a picture totalcolors */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_totalcolors(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_totalcolors);
+
+/* read a picture data length */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* picture_length);
+
+/* read a picture data */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_picture_data(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* read a cuesheet catalog length (128 bytes) */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_catalog_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* catalog_length);
+
+/* read a cuesheet catalog number */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_catalog_string(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, char* buffer, uint32_t buffer_length, uint32_t* outlen);
+
+/* read a cuesheet leadin value */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_leadin(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint64_t* leadin);
+
+/* read a cuesheet "is this a cd" flag */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_cd_flag(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* cd_flag);
+
+/* read a cuesheet total tracks */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_tracks(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* tracks);
+
+/* read the next track offset (can return MINIFLAC_METADATA_END) */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_offset(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint64_t* track_offset);
+
+/* read the next track number */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_number(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* track_number);
+
+/* read the next track isrc length */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_isrc_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* isrc_length);
+
+/* read the next track isrc string */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_isrc_string(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, char* buffer, uint32_t buffer_length, uint32_t* outlen);
+
+/* read the next track type flag (0 = audio, 1 = non-audio) */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_audio_flag(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* track_audio_flag);
+
+/* read the track pre-emphasis flag */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_preemph_flag(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* track_preemph_flag);
+
+/* read the total number of track index points */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_track_indexpoints(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* track_indexpoints);
+
+/* read the next index point offset */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_index_point_offset(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint64_t* index_point_offset);
+
+/* read the next index point number */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_cuesheet_index_point_number(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* index_point_number);
+
+/* get the number of seekpoints */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_seektable_seekpoints(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* seekpoints);
+
+/* read the next seekpoint sample number */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_seektable_sample_number(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint64_t* sample_number);
+
+/* read the next seekpoint sample offset */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_seektable_sample_offset(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint64_t* sample_offset);
+
+/* read the next seekpoint # of samples in seekpoint */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_seektable_samples(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint16_t* samples);
+
+/* read an application block's ID */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_application_id(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* id);
+
+/* read an application block's data length */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_application_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* application_length);
+
+/* read an application block's data */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_application_data(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* buffer, uint32_t buffer_length, uint32_t* outlen);
+
+/* read a padding block's data length */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_padding_length(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint32_t* padding_length);
+
+/* read a padding block's data */
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_padding_data(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, uint8_t* buffer, uint32_t buffer_length, uint32_t* outlen);
+
+MINIFLAC_API
+unsigned int
+miniflac_version_major(void);
+
+MINIFLAC_API
+unsigned int
+miniflac_version_minor(void);
+
+MINIFLAC_API
+unsigned int
+miniflac_version_patch(void);
+
+MINIFLAC_API
+const char*
+miniflac_version_string(void);
+
+MINIFLAC_API
+MINIFLAC_CONST
+size_t
+mflac_size(void);
+
+MINIFLAC_API
+void
+mflac_init(mflac_t* m, MINIFLAC_CONTAINER container, mflac_readcb read, void* userdata);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_sync(mflac_t* m);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_decode(mflac_t* m, int32_t** samples);
+
+/* functions to query the state without inspecting structs,
+ * only valid to call after mflac_sync returns MFLAC_OK */
+MINIFLAC_API
+uint8_t
+mflac_is_frame(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_is_metadata(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_last(mflac_t* m);
+
+MINIFLAC_API
+MINIFLAC_METADATA_TYPE
+miniflac_metadata_type(miniflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_streaminfo(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_padding(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_application(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_seektable(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_vorbis_comment(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_cuesheet(mflac_t* m);
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_picture(mflac_t* m);
+
+/*
+ * METADATA FUNCTIONS
+ * ==================
+ *
+ * The below metadata-related functions are grouped based on metadata blocks,
+ * for conveience I've listed the miniflac enum label and value for each type */
+/*
+ * MINIFLAC_METADATA_STREAMINFO (0)
+ * ================================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_streaminfo_min_block_size, but - if you do, you have to call it before
+ * mflac_streaminfo_max_block_size.
+ */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_min_block_size(mflac_t* m, uint16_t* min_block_size);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_max_block_size(mflac_t* m, uint16_t* max_block_size);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_min_frame_size(mflac_t* m, uint32_t* min_frame_size);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_max_frame_size(mflac_t* m, uint32_t* max_frame_size);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_sample_rate(mflac_t* m, uint32_t* sample_rate);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_channels(mflac_t* m, uint8_t* channels);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_bps(mflac_t* m, uint8_t* bps);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_total_samples(mflac_t* m, uint64_t* total_samples);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_md5_length(mflac_t* m, uint32_t* md5_length);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_streaminfo_md5_data(mflac_t* m, uint8_t* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/*
+ * MINIFLAC_METADATA_PADDING (1)
+ * =============================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_padding_length, but - if you do, you have to call it before
+ * mflac_padding_data.
+ */
+/* gets the length of the PADDING block */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_padding_length(mflac_t* m, uint32_t* length);
+
+/* gets the data of the PADDING block */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_padding_data(mflac_t* m, uint8_t*buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/*
+ * MINIFLAC_METADATA_APPLICATION (2)
+ * =================================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_application_id, but - if you do, you have to call it before
+ * mflac_application_length and mflac_application_data.
+ */
+/* gets the id of the APPLICATION block */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_application_id(mflac_t* m, uint32_t* id);
+
+/* gets the length of the APPLICATION block */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_application_length(mflac_t* m, uint32_t* length);
+
+/* gets the data of the APPLICATION block */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_application_data(mflac_t* m, uint8_t*buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/*
+ * MINIFLAC_METADATA_SEEKTABLE (3)
+ * ===============================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_seektable_seekpoints, but - if you do, you have to call it before
+ * mflac_seektable_sample_number.
+ */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_seektable_seekpoints(mflac_t* m, uint32_t* seekpoints);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_seektable_sample_number(mflac_t* m, uint64_t* sample_number);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_seektable_sample_offset(mflac_t* m, uint64_t* sample_offset);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_seektable_samples(mflac_t* m, uint16_t* samples);
+
+/*
+ * MINIFLAC_METADATA_VORBIS_COMMENT (4)
+ * ===================================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_vorbis_comment_vendor_length, but - if you do, you have to call it before
+ * mflac_vorbis_comment_vendor_string
+ */
+/* gets the length of the vendor string - excludes the null terminator */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_vorbis_comment_vendor_length(mflac_t* m, uint32_t* length);
+
+/* gets the vendor string - will not be terminated */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_vorbis_comment_vendor_string(mflac_t* m, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/* gets the total number of comments */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_vorbis_comment_total(mflac_t* m, uint32_t* total);
+
+/* gets the length number of the next comment - does not include null terminator */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_vorbis_comment_length(mflac_t* m, uint32_t* length);
+
+/* gets the next comment - will not be null-terminated! */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_vorbis_comment_string(mflac_t* m, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+/*
+ * MINIFLAC_METADATA_CUESHEET (5)
+ * ==============================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_cuesheet_catalog_length, but - if you do, you have to call it before
+ * mflac_cuesheet_catalog_string.
+ */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_catalog_length(mflac_t* m, uint32_t* length);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_catalog_string(mflac_t* m, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_leadin(mflac_t* m, uint64_t* leadin);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_cd_flag(mflac_t* m, uint8_t* cd_flag);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_tracks(mflac_t* m, uint8_t* tracks);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_offset(mflac_t* m, uint64_t* track_offset);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_number(mflac_t* m, uint8_t* track_number);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_isrc_length(mflac_t* m, uint32_t* length);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_isrc_string(mflac_t* m, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_audio_flag(mflac_t* m, uint8_t* track_audio_flag);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_preemph_flag(mflac_t* m, uint8_t* track_preemph_flag);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_track_indexpoints(mflac_t* m, uint8_t* track_indexpoints);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_index_point_offset(mflac_t* m, uint64_t* index_point_offset);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_cuesheet_index_point_number(mflac_t* m, uint8_t* index_point_number);
+
+/*
+ * MINIFLAC_METADATA_PICTURE (6)
+ * ==============================
+ *
+ * Functions are listed in the order they should be called, but you can skip
+ * ones you don't need. For example, you don't have to call
+ * mflac_picture_type, but - if you do, you have to call it before
+ * mflac_pictue_mime_length.
+ */
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_type(mflac_t* m, uint32_t* picture_type);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_mime_length(mflac_t* m, uint32_t* picture_mime_length);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_mime_string(mflac_t* m, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_description_length(mflac_t* m, uint32_t* picture_description_length);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_description_string(mflac_t* m, char* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_width(mflac_t* m, uint32_t* picture_width);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_height(mflac_t* m, uint32_t* picture_height);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_colordepth(mflac_t* m, uint32_t* picture_colordepth);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_totalcolors(mflac_t* m, uint32_t* picture_totalcolors);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_length(mflac_t* m, uint32_t* picture_length);
+
+MINIFLAC_API
+MFLAC_RESULT
+mflac_picture_data(mflac_t* m, uint8_t* buffer, uint32_t buffer_length, uint32_t* buffer_used);
+
+MINIFLAC_API
+unsigned int
+mflac_version_major(void);
+
+MINIFLAC_API
+unsigned int
+mflac_version_minor(void);
+
+MINIFLAC_API
+unsigned int
+mflac_version_patch(void);
+
+MINIFLAC_API
+const char*
+mflac_version_string(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifdef MINIFLAC_IMPLEMENTATION
+
+#ifdef MINIFLAC_ABORT_ON_ERROR
+#include
+#define miniflac_abort() abort()
+#else
+#define miniflac_abort()
+#endif
+
+MINIFLAC_PRIVATE
+uint32_t
+miniflac_unpack_uint32le(uint8_t buffer[4]);
+
+MINIFLAC_PRIVATE
+int32_t
+miniflac_unpack_int32le(uint8_t buffer[4]);
+
+MINIFLAC_PRIVATE
+uint64_t
+miniflac_unpack_uint64le(uint8_t buffer[8]);
+
+MINIFLAC_PRIVATE
+int64_t
+miniflac_unpack_int64le(uint8_t buffer[8]);
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_init(miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+int
+miniflac_bitreader_fill(miniflac_bitreader_t* br, uint8_t bits);
+
+MINIFLAC_PRIVATE
+int
+miniflac_bitreader_fill_nocrc(miniflac_bitreader_t* br, uint8_t bits);
+
+MINIFLAC_PRIVATE
+uint64_t
+miniflac_bitreader_read(miniflac_bitreader_t* br, uint8_t bits);
+
+MINIFLAC_PRIVATE
+int64_t
+miniflac_bitreader_read_signed(miniflac_bitreader_t* br, uint8_t bits);
+
+MINIFLAC_PRIVATE
+uint64_t
+miniflac_bitreader_peek(miniflac_bitreader_t* br, uint8_t bits);
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_discard(miniflac_bitreader_t* br, uint8_t bits);
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_align(miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_reset_crc(miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_oggheader_init(miniflac_oggheader_t* oggheader);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_oggheader_decode(miniflac_oggheader_t* oggheader, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_ogg_init(miniflac_ogg_t* ogg);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_ogg_sync(miniflac_ogg_t* ogg, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_streammarker_init(miniflac_streammarker_t* streammarker);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streammarker_decode(miniflac_streammarker_t* streammarker, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_metadata_header_init(miniflac_metadata_header_t* header);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_metadata_header_decode(miniflac_metadata_header_t* header, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_streaminfo_init(miniflac_streaminfo_t* streaminfo);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_min_block_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint16_t* min_block_size);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_max_block_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint16_t* max_block_size);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_min_frame_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* min_frame_size);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_max_frame_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* max_frame_size);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_sample_rate(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* sample_rate);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_channels(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint8_t* channels);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_bps(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint8_t* bps);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_total_samples(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint64_t* total_samples);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_md5_length(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* md5_length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_md5_data(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+void
+miniflac_vorbis_comment_init(miniflac_vorbis_comment_t* vorbis_comment);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_vendor_length(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_vendor_string(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_total(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, uint32_t* total);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_length(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_string(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+void
+miniflac_picture_init(miniflac_picture_t* picture);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_type(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* type);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_mime_length(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_mime_string(miniflac_picture_t* picture, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_description_length(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_description_string(miniflac_picture_t* picture, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_width(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_height(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_colordepth(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_totalcolors(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_length(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_data(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+void
+miniflac_cuesheet_init(miniflac_cuesheet_t* cuesheet);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_catalog_length(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint32_t* catalog_length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_catalog_string(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_leadin(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint64_t* leadin);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_cd_flag(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* cd_flag);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_tracks(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* tracks);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_offset(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint64_t* track_offset);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_number(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_number);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_isrc_length(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint32_t* track_isrc_length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_isrc_string(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_audio_flag(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_audio_flag);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_preemph_flag(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_preemph_flag);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_indexpoints(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_indexpoints);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_index_point_offset(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint64_t* index_point_offset);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_index_point_number(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* index_point_number);
+
+MINIFLAC_PRIVATE
+void
+miniflac_seektable_init(miniflac_seektable_t* seektable);
+
+/* read the number of seekpoints */
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_seekpoints(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint32_t* seekpoints);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_sample_number(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint64_t* sample_number);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_sample_offset(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint64_t* sample_offset);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_samples(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint16_t* samples);
+
+MINIFLAC_PRIVATE
+void
+miniflac_application_init(miniflac_application_t* application);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_application_read_id(miniflac_application_t* application, miniflac_bitreader_t* br, uint32_t* id);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_application_read_length(miniflac_application_t* application, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_application_read_data(miniflac_application_t* application, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+void
+miniflac_padding_init(miniflac_padding_t* padding);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_padding_read_length(miniflac_padding_t* padding, miniflac_bitreader_t* br, uint32_t* length);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_padding_read_data(miniflac_padding_t* padding, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen);
+
+MINIFLAC_PRIVATE
+void
+miniflac_metadata_init(miniflac_metadata_t* metadata);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_metadata_sync(miniflac_metadata_t* metadata, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_metadata_decode(miniflac_metadata_t* metadata, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_residual_init(miniflac_residual_t* residual);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_residual_decode(miniflac_residual_t* residual, miniflac_bitreader_t* br, uint32_t* pos, uint32_t block_size, uint8_t predictor_order, int32_t *out);
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_fixed_init(miniflac_subframe_fixed_t* c);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_fixed_decode(miniflac_subframe_fixed_t* c, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps, miniflac_residual_t* residual, uint8_t predictor_order);
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_lpc_init(miniflac_subframe_lpc_t* l);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_lpc_decode(miniflac_subframe_lpc_t* l, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps, miniflac_residual_t* residual, uint8_t predictor_order);
+
+MINIFLAC_PRIVATE
+void miniflac_subframe_constant_init(miniflac_subframe_constant_t* c);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_constant_decode(miniflac_subframe_constant_t* c, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps);
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_verbatim_init(miniflac_subframe_verbatim_t* c);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_verbatim_decode(miniflac_subframe_verbatim_t* c, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps);
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_header_init(miniflac_subframe_header_t* subframeheader);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_header_decode(miniflac_subframe_header_t* subframeheader, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_init(miniflac_subframe_t* subframe);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_decode(miniflac_subframe_t* subframe, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps);
+
+MINIFLAC_PRIVATE
+void
+miniflac_frame_header_init(miniflac_frame_header_t* frame_header);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT miniflac_frame_header_decode(miniflac_frame_header_t* frame_header, miniflac_bitreader_t* br);
+
+MINIFLAC_PRIVATE
+void miniflac_frame_init(miniflac_frame_t* frame);
+
+/* ensures we've just read the audio frame header and are ready to decode */
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT miniflac_frame_sync(miniflac_frame_t* frame, miniflac_bitreader_t* br, miniflac_streaminfo_t* info);
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT miniflac_frame_decode(miniflac_frame_t* frame, miniflac_bitreader_t* br, miniflac_streaminfo_t* info, int32_t** output);
+
+
+
+#define MFLAC_PASTE(a,b) a ## b
+
+#define MFLAC_FUNC_BODY(a) \
+ while( (res = a) == MINIFLAC_CONTINUE ) { \
+ received = m->read(m->buffer, MFLAC_BUFFER_SIZE, m->userdata); \
+ if(received == 0) return MFLAC_EOF; \
+ m->buflen = received; \
+ m->bufpos = 0; \
+ } \
+ if(res < MINIFLAC_OK) { \
+ return (MFLAC_RESULT)res; \
+ } \
+ m->bufpos += used; \
+ m->buflen -= used;
+
+
+#define MFLAC_GET0_BODY(var) MFLAC_FUNC_BODY(miniflac_ ## var (&m->flac, &m->buffer[m->bufpos], m->buflen, &used) )
+#define MFLAC_GET1_BODY(var, a) MFLAC_FUNC_BODY(miniflac_ ## var(&m->flac, &m->buffer[m->bufpos], m->buflen, &used, a) )
+#define MFLAC_GET3_BODY(var, a, b, c) MFLAC_FUNC_BODY(miniflac_ ## var(&m->flac, &m->buffer[m->bufpos], m->buflen, &used, a, b, c) )
+
+#define MFLAC_FUNC(sig,body) \
+MINIFLAC_API \
+MFLAC_RESULT \
+sig { \
+ MINIFLAC_RESULT res = MINIFLAC_OK; \
+ uint32_t used = 0; \
+ size_t received = 0; \
+ body \
+ return (MFLAC_RESULT)res; \
+}
+
+#define MFLAC_GET0_FUNC(var) MFLAC_FUNC(MFLAC_PASTE(mflac_,var)(mflac_t* m),MFLAC_GET0_BODY(var))
+#define MFLAC_GET1_FUNC(var, typ) MFLAC_FUNC(MFLAC_PASTE(mflac_,var)(mflac_t* m, typ p1),MFLAC_GET1_BODY(var, p1))
+#define MFLAC_GET3_FUNC(var, typ) MFLAC_FUNC(MFLAC_PASTE(mflac_,var)(mflac_t* m, typ p1, uint32_t p2, uint32_t* p3),MFLAC_GET3_BODY(var, p1, p2, p3))
+
+MINIFLAC_API
+MINIFLAC_CONST
+size_t
+mflac_size(void) {
+ return sizeof(mflac_t);
+}
+
+MINIFLAC_API
+void
+mflac_init(mflac_t* m, MINIFLAC_CONTAINER container, mflac_readcb read, void *userdata) {
+ miniflac_init(&m->flac, container);
+ m->read = read;
+ m->userdata = userdata;
+ m->bufpos = 0;
+ m->buflen = 0;
+}
+
+MFLAC_GET0_FUNC(sync)
+
+MFLAC_GET1_FUNC(decode,int32_t**)
+
+MFLAC_GET1_FUNC(streaminfo_min_block_size, uint16_t*)
+MFLAC_GET1_FUNC(streaminfo_max_block_size, uint16_t*)
+MFLAC_GET1_FUNC(streaminfo_min_frame_size, uint32_t*)
+MFLAC_GET1_FUNC(streaminfo_max_frame_size, uint32_t*)
+MFLAC_GET1_FUNC(streaminfo_sample_rate, uint32_t*)
+MFLAC_GET1_FUNC(streaminfo_channels, uint8_t*)
+MFLAC_GET1_FUNC(streaminfo_bps, uint8_t*)
+MFLAC_GET1_FUNC(streaminfo_total_samples, uint64_t*)
+MFLAC_GET1_FUNC(streaminfo_md5_length, uint32_t*)
+MFLAC_GET3_FUNC(streaminfo_md5_data, uint8_t*)
+
+MFLAC_GET1_FUNC(vorbis_comment_vendor_length, uint32_t*)
+MFLAC_GET3_FUNC(vorbis_comment_vendor_string, char*)
+MFLAC_GET1_FUNC(vorbis_comment_total, uint32_t*)
+MFLAC_GET1_FUNC(vorbis_comment_length, uint32_t*)
+MFLAC_GET3_FUNC(vorbis_comment_string, char*)
+
+MFLAC_GET1_FUNC(padding_length, uint32_t*)
+MFLAC_GET3_FUNC(padding_data, uint8_t*)
+
+MFLAC_GET1_FUNC(application_id, uint32_t*)
+MFLAC_GET1_FUNC(application_length, uint32_t*)
+MFLAC_GET3_FUNC(application_data, uint8_t*)
+
+MFLAC_GET1_FUNC(seektable_seekpoints, uint32_t*)
+MFLAC_GET1_FUNC(seektable_sample_number, uint64_t*)
+MFLAC_GET1_FUNC(seektable_sample_offset, uint64_t*)
+MFLAC_GET1_FUNC(seektable_samples, uint16_t*)
+
+MFLAC_GET1_FUNC(cuesheet_catalog_length, uint32_t*)
+MFLAC_GET3_FUNC(cuesheet_catalog_string, char*)
+MFLAC_GET1_FUNC(cuesheet_leadin, uint64_t*)
+MFLAC_GET1_FUNC(cuesheet_cd_flag, uint8_t*)
+MFLAC_GET1_FUNC(cuesheet_tracks, uint8_t*)
+MFLAC_GET1_FUNC(cuesheet_track_offset, uint64_t*)
+MFLAC_GET1_FUNC(cuesheet_track_number, uint8_t*)
+MFLAC_GET1_FUNC(cuesheet_track_isrc_length, uint32_t*)
+MFLAC_GET3_FUNC(cuesheet_track_isrc_string, char*)
+MFLAC_GET1_FUNC(cuesheet_track_audio_flag, uint8_t*)
+MFLAC_GET1_FUNC(cuesheet_track_preemph_flag, uint8_t*)
+MFLAC_GET1_FUNC(cuesheet_track_indexpoints, uint8_t*)
+MFLAC_GET1_FUNC(cuesheet_index_point_offset, uint64_t*)
+MFLAC_GET1_FUNC(cuesheet_index_point_number, uint8_t*)
+
+MFLAC_GET1_FUNC(picture_type, uint32_t*)
+MFLAC_GET1_FUNC(picture_mime_length, uint32_t*)
+MFLAC_GET3_FUNC(picture_mime_string, char*)
+MFLAC_GET1_FUNC(picture_description_length, uint32_t*)
+MFLAC_GET3_FUNC(picture_description_string, char*)
+MFLAC_GET1_FUNC(picture_width, uint32_t*)
+MFLAC_GET1_FUNC(picture_height, uint32_t*)
+MFLAC_GET1_FUNC(picture_colordepth, uint32_t*)
+MFLAC_GET1_FUNC(picture_totalcolors, uint32_t*)
+MFLAC_GET1_FUNC(picture_length, uint32_t*)
+MFLAC_GET3_FUNC(picture_data, uint8_t*)
+
+MINIFLAC_API
+uint8_t
+mflac_is_frame(mflac_t* m) {
+ return m->flac.state == MINIFLAC_FRAME;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_is_metadata(mflac_t* m) {
+ return m->flac.state == MINIFLAC_METADATA;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_last(mflac_t* m) {
+ return m->flac.metadata.header.is_last;
+}
+
+MINIFLAC_API
+MINIFLAC_METADATA_TYPE
+mflac_metadata_type(mflac_t* m) {
+ return m->flac.metadata.header.type;
+}
+
+MINIFLAC_API
+uint32_t
+mflac_metadata_length(mflac_t* m) {
+ return m->flac.metadata.header.length;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_streaminfo(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_STREAMINFO;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_padding(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_PADDING;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_application(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_APPLICATION;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_seektable(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_SEEKTABLE;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_vorbis_comment(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_VORBIS_COMMENT;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_cuesheet(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_CUESHEET;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_metadata_is_picture(mflac_t* m) {
+ return m->flac.metadata.header.type == MINIFLAC_METADATA_PICTURE;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_frame_blocking_strategy(mflac_t* m) {
+ return m->flac.frame.header.blocking_strategy;
+}
+
+MINIFLAC_API
+uint16_t
+mflac_frame_block_size(mflac_t* m) {
+ return m->flac.frame.header.block_size;
+}
+
+MINIFLAC_API
+uint32_t
+mflac_frame_sample_rate(mflac_t* m) {
+ return m->flac.frame.header.sample_rate;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_frame_channels(mflac_t* m) {
+ return m->flac.frame.header.channels;
+}
+
+MINIFLAC_API
+uint8_t
+mflac_frame_bps(mflac_t* m) {
+ return m->flac.frame.header.bps;
+}
+
+MINIFLAC_API
+uint64_t
+mflac_frame_sample_number(mflac_t* m) {
+ return m->flac.frame.header.sample_number;
+}
+
+MINIFLAC_API
+uint32_t
+mflac_frame_frame_number(mflac_t* m) {
+ return m->flac.frame.header.frame_number;
+}
+
+MINIFLAC_API
+unsigned int
+mflac_version_major(void) {
+ return miniflac_version_major();
+}
+
+MINIFLAC_API
+unsigned int
+mflac_version_minor(void) {
+ return miniflac_version_minor();
+}
+
+MINIFLAC_API
+unsigned int
+mflac_version_patch(void) {
+ return miniflac_version_patch();
+}
+
+MINIFLAC_API
+const char*
+mflac_version_string(void) {
+ return miniflac_version_string();
+}
+
+#undef MFLAC_PASTE
+#undef MFLAC_FUNC_BODY
+#undef MFLAC_GET0_BODY
+#undef MFLAC_GET1_BODY
+#undef MFLAC_GET3_BODY
+#undef MFLAC_FUNC
+#undef MFLAC_GET0_FUNC
+#undef MFLAC_GET1_FUNC
+#undef MFLAC_GET3_FUNC
+
+#define MINIFLAC_VERSION_MAJOR 1
+#define MINIFLAC_VERSION_MINOR 1
+#define MINIFLAC_VERSION_PATCH 1
+
+#define MINIFLAC_STR(x) #x
+#define MINIFLAC_XSTR(x) MINIFLAC_STR(x)
+
+#define MINIFLAC_VERSION_STRING MINIFLAC_XSTR(MINIFLAC_VERSION_MAJOR) "." MINIFLAC_XSTR(MINIFLAC_VERSION_MINOR) "." MINIFLAC_XSTR(MINIFLAC_VERSION_PATCH)
+
+
+MINIFLAC_API
+unsigned int
+miniflac_version_major(void) {
+ return MINIFLAC_VERSION_MAJOR;
+}
+
+MINIFLAC_API
+unsigned int
+miniflac_version_minor(void) {
+ return MINIFLAC_VERSION_MINOR;
+}
+
+MINIFLAC_API
+unsigned int
+miniflac_version_patch(void) {
+ return MINIFLAC_VERSION_PATCH;
+}
+
+MINIFLAC_API
+const char*
+miniflac_version_string(void) {
+ return MINIFLAC_VERSION_STRING;
+}
+
+static
+void
+miniflac_oggreset(miniflac_t* pFlac) {
+ miniflac_bitreader_init(&pFlac->br);
+ miniflac_oggheader_init(&pFlac->oggheader);
+ miniflac_streammarker_init(&pFlac->streammarker);
+ miniflac_metadata_init(&pFlac->metadata);
+ miniflac_frame_init(&pFlac->frame);
+ pFlac->state = MINIFLAC_OGGHEADER;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_oggfunction_start(miniflac_t* pFlac, const uint8_t* data, const uint8_t** packet, uint32_t* packet_length) {
+ MINIFLAC_RESULT r;
+
+ while(pFlac->ogg.state != MINIFLAC_OGG_DATA) {
+ r = miniflac_ogg_sync(&pFlac->ogg,&pFlac->ogg.br);
+ if(r != MINIFLAC_OK) return r;
+
+ if(pFlac->oggserial_set == 0) {
+ if(pFlac->ogg.headertype & 0x02) {
+ miniflac_oggreset(pFlac);
+ }
+ } else {
+ if(pFlac->oggserial != pFlac->ogg.serialno) pFlac->ogg.state = MINIFLAC_OGG_SKIP;
+ }
+ }
+
+ *packet = &data[pFlac->ogg.br.pos];
+ *packet_length = pFlac->ogg.br.len - pFlac->ogg.br.pos;
+ if(*packet_length > (uint32_t)(pFlac->ogg.length - pFlac->ogg.pos)) {
+ *packet_length = (uint32_t)pFlac->ogg.length - pFlac->ogg.pos;
+ }
+
+ return MINIFLAC_OK;
+}
+
+static
+void
+miniflac_oggfunction_end(miniflac_t* pFlac, uint32_t packet_used) {
+ pFlac->ogg.br.pos += packet_used;
+ pFlac->ogg.pos += packet_used;
+
+ if(pFlac->ogg.pos == pFlac->ogg.length) {
+ pFlac->ogg.state = MINIFLAC_OGG_CAPTUREPATTERN_O;
+ if(pFlac->ogg.headertype & 0x04) {
+ if(pFlac->oggserial_set == 1 && pFlac->oggserial == pFlac->ogg.serialno) {
+ pFlac->oggserial_set = 0;
+ pFlac->oggserial = 0;
+ }
+ }
+ }
+}
+
+MINIFLAC_API
+MINIFLAC_CONST
+size_t
+miniflac_size(void) {
+ return sizeof(miniflac_t);
+}
+
+MINIFLAC_API
+void
+miniflac_init(miniflac_t* pFlac, MINIFLAC_CONTAINER container) {
+ miniflac_bitreader_init(&pFlac->br);
+ miniflac_ogg_init(&pFlac->ogg);
+ miniflac_oggheader_init(&pFlac->oggheader);
+ miniflac_streammarker_init(&pFlac->streammarker);
+ miniflac_metadata_init(&pFlac->metadata);
+ miniflac_frame_init(&pFlac->frame);
+ pFlac->container = container;
+ pFlac->oggserial = -1;
+ pFlac->oggserial_set = 0;
+
+ switch(pFlac->container) {
+ case MINIFLAC_CONTAINER_NATIVE: {
+ pFlac->state = MINIFLAC_STREAMMARKER_OR_FRAME;
+ break;
+ }
+ case MINIFLAC_CONTAINER_OGG: {
+ pFlac->state = MINIFLAC_OGGHEADER;
+ break;
+ }
+ default: break;
+ }
+
+ pFlac->state = MINIFLAC_STREAMMARKER;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_sync_internal(miniflac_t* pFlac, miniflac_bitreader_t* br) {
+ MINIFLAC_RESULT r;
+ unsigned char c;
+ uint16_t peek;
+
+ switch(pFlac->state) {
+ case MINIFLAC_OGGHEADER: {
+ r = miniflac_oggheader_decode(&pFlac->oggheader,br);
+ if (r != MINIFLAC_OK) return r;
+ pFlac->oggserial_set = 1;
+ pFlac->oggserial = pFlac->ogg.serialno;
+ pFlac->state = MINIFLAC_STREAMMARKER;
+ goto miniflac_sync_streammarker;
+ }
+ case MINIFLAC_STREAMMARKER_OR_FRAME: {
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ c = (unsigned char)miniflac_bitreader_peek(br,8);
+ if( (char)c == 'f') {
+ pFlac->state = MINIFLAC_STREAMMARKER;
+ goto miniflac_sync_streammarker;
+ } else if(c == 0xFF) {
+ pFlac->state = MINIFLAC_FRAME;
+ goto miniflac_sync_frame;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+
+ case MINIFLAC_STREAMMARKER: {
+ miniflac_sync_streammarker:
+ r = miniflac_streammarker_decode(&pFlac->streammarker,br);
+ if(r != MINIFLAC_OK) return r;
+ pFlac->state = MINIFLAC_METADATA_OR_FRAME;
+ }
+
+ /* fall-through */
+ case MINIFLAC_METADATA_OR_FRAME: {
+ miniflac_sync_metadata_or_frame:
+ if(miniflac_bitreader_fill(br,16)) return MINIFLAC_CONTINUE;
+ peek = (uint16_t)miniflac_bitreader_peek(br,14);
+ if(peek == 0x3FFE) {
+ pFlac->state = MINIFLAC_FRAME;
+ goto miniflac_sync_frame;
+ }
+ pFlac->state = MINIFLAC_METADATA;
+ goto miniflac_sync_metadata;
+ }
+
+ /* fall-through */
+ case MINIFLAC_METADATA: {
+ miniflac_sync_metadata:
+ while(pFlac->metadata.state != MINIFLAC_METADATA_HEADER) {
+ r = miniflac_metadata_decode(&pFlac->metadata,br);
+ if(r != MINIFLAC_OK) return r;
+ /* if we're here, it means we were in the middle of
+ * a metadata block and finished decoding, so the
+ * next block could be a metadata block or frame */
+ pFlac->state = MINIFLAC_METADATA_OR_FRAME;
+ goto miniflac_sync_metadata_or_frame;
+ }
+ return miniflac_metadata_sync(&pFlac->metadata,br);
+ }
+
+ case MINIFLAC_FRAME: {
+ miniflac_sync_frame:
+ while(pFlac->frame.state != MINIFLAC_FRAME_HEADER) {
+ r = miniflac_frame_decode(&pFlac->frame,br,&pFlac->metadata.streaminfo,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+
+ return miniflac_frame_sync(&pFlac->frame,br,&pFlac->metadata.streaminfo);
+ }
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_sync_native(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length) {
+ MINIFLAC_RESULT r;
+ pFlac->br.buffer = data;
+ pFlac->br.len = length;
+ pFlac->br.pos = 0;
+
+ r = miniflac_sync_internal(pFlac,&pFlac->br);
+
+ *out_length = pFlac->br.pos;
+ return r;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_decode_native(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, int32_t** samples) {
+ MINIFLAC_RESULT r;
+ pFlac->br.buffer = data;
+ pFlac->br.len = length;
+ pFlac->br.pos = 0;
+
+ while(pFlac->state != MINIFLAC_FRAME) {
+ r = miniflac_sync_internal(pFlac,&pFlac->br);
+ if(r != MINIFLAC_OK) goto miniflac_decode_exit;
+ }
+
+ r = miniflac_frame_decode(&pFlac->frame,&pFlac->br,&pFlac->metadata.streaminfo,samples);
+
+ miniflac_decode_exit:
+ *out_length = pFlac->br.pos;
+ return r;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_sync_ogg(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length) {
+ MINIFLAC_RESULT r = MINIFLAC_CONTINUE;
+
+ const uint8_t* packet = NULL;
+ uint32_t packet_length = 0;
+ uint32_t packet_used = 0;
+
+ pFlac->ogg.br.buffer = data;
+ pFlac->ogg.br.len = length;
+ pFlac->ogg.br.pos = 0;
+
+ do {
+ r = miniflac_oggfunction_start(pFlac,data,&packet,&packet_length);
+ if(r != MINIFLAC_OK) break;
+
+ r = miniflac_sync_native(pFlac,packet,packet_length,&packet_used);
+ miniflac_oggfunction_end(pFlac,packet_used);
+
+ if(r == MINIFLAC_OGG_HEADER_NOTFLAC) {
+ /* try reading more data */
+ pFlac->ogg.state = MINIFLAC_OGG_SKIP;
+ r = MINIFLAC_CONTINUE;
+ }
+ } while(r == MINIFLAC_CONTINUE && pFlac->ogg.br.pos < length);
+
+ *out_length = pFlac->ogg.br.pos;
+ return r;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_decode_ogg(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, int32_t** samples) {
+ MINIFLAC_RESULT r = MINIFLAC_CONTINUE;
+
+ const uint8_t* packet = NULL;
+ uint32_t packet_length = 0;
+ uint32_t packet_used = 0;
+
+ pFlac->ogg.br.buffer = data;
+ pFlac->ogg.br.len = length;
+ pFlac->ogg.br.pos = 0;
+
+ do {
+ r = miniflac_oggfunction_start(pFlac,data,&packet,&packet_length);
+ if(r != MINIFLAC_OK) break;
+
+ r = miniflac_decode_native(pFlac,packet,packet_length,&packet_used,samples);
+ miniflac_oggfunction_end(pFlac,packet_used);
+ } while(r == MINIFLAC_CONTINUE && pFlac->ogg.br.pos < length);
+
+ *out_length = pFlac->ogg.br.pos;
+ return r;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_probe(miniflac_t* pFlac, const uint8_t* data, uint32_t length) {
+ if(length == 0) return MINIFLAC_CONTINUE;
+ switch(data[0]) {
+ case 'f': {
+ pFlac->container = MINIFLAC_CONTAINER_NATIVE;
+ pFlac->state = MINIFLAC_STREAMMARKER;
+ break;
+ }
+ case 'O': {
+ pFlac->container = MINIFLAC_CONTAINER_OGG;
+ pFlac->state = MINIFLAC_OGGHEADER;
+ break;
+ }
+ default: return MINIFLAC_ERROR;
+ }
+ return MINIFLAC_OK;
+}
+
+
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_decode(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, int32_t** samples) {
+ MINIFLAC_RESULT r;
+
+ if(pFlac->container == MINIFLAC_CONTAINER_UNKNOWN) {
+ r = miniflac_probe(pFlac,data,length);
+ if(r != MINIFLAC_OK) return r;
+ }
+
+ if(pFlac->container == MINIFLAC_CONTAINER_NATIVE) {
+ r = miniflac_decode_native(pFlac,data,length,out_length,samples);
+ } else {
+ r = miniflac_decode_ogg(pFlac,data,length,out_length,samples);
+ }
+
+ return r;
+}
+
+MINIFLAC_API
+MINIFLAC_RESULT
+miniflac_sync(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length) {
+ MINIFLAC_RESULT r;
+
+ if(pFlac->container == MINIFLAC_CONTAINER_UNKNOWN) {
+ r = miniflac_probe(pFlac,data,length);
+ if(r != MINIFLAC_OK) return r;
+ }
+
+ if(pFlac->container == MINIFLAC_CONTAINER_NATIVE) {
+ r = miniflac_sync_native(pFlac,data,length,out_length);
+ } else {
+ r = miniflac_sync_ogg(pFlac,data,length,out_length);
+ }
+
+ return r;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_is_metadata(miniflac_t* pFlac) {
+ return pFlac->state == MINIFLAC_METADATA;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_is_frame(miniflac_t* pFlac) {
+ return pFlac->state == MINIFLAC_FRAME;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_last(miniflac_t* pFlac) {
+ return pFlac->metadata.header.is_last;
+}
+
+MINIFLAC_API
+MINIFLAC_METADATA_TYPE
+miniflac_metadata_type(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type;
+}
+
+MINIFLAC_API
+uint32_t
+miniflac_metadata_length(miniflac_t* pFlac) {
+ return pFlac->metadata.header.length;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_streaminfo(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_STREAMINFO;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_padding(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_PADDING;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_application(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_APPLICATION;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_seektable(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_SEEKTABLE;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_vorbis_comment(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_VORBIS_COMMENT;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_cuesheet(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_CUESHEET;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_metadata_is_picture(miniflac_t* pFlac) {
+ return pFlac->metadata.header.type == MINIFLAC_METADATA_PICTURE;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_frame_blocking_strategy(miniflac_t* pFlac) {
+ return pFlac->frame.header.blocking_strategy;
+}
+
+MINIFLAC_API
+uint16_t
+miniflac_frame_block_size(miniflac_t* pFlac) {
+ return pFlac->frame.header.block_size;
+}
+
+MINIFLAC_API
+uint32_t
+miniflac_frame_sample_rate(miniflac_t* pFlac) {
+ return pFlac->frame.header.sample_rate;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_frame_channels(miniflac_t* pFlac) {
+ return pFlac->frame.header.channels;
+}
+
+MINIFLAC_API
+uint8_t
+miniflac_frame_bps(miniflac_t* pFlac) {
+ return pFlac->frame.header.bps;
+}
+
+MINIFLAC_API
+uint64_t
+miniflac_frame_sample_number(miniflac_t* pFlac) {
+ return pFlac->frame.header.sample_number;
+}
+
+MINIFLAC_API
+uint32_t
+miniflac_frame_frame_number(miniflac_t* pFlac) {
+ return pFlac->frame.header.frame_number;
+}
+
+#define MINIFLAC_SUBSYS(subsys) &pFlac->metadata.subsys
+
+#define MINIFLAC_GEN_NATIVE_FUNC1(mt,subsys,val,t) \
+static \
+MINIFLAC_RESULT \
+miniflac_ ## subsys ## _ ## val ## _native(miniflac_t *pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, t* outvar) { \
+ MINIFLAC_RESULT r; \
+ pFlac->br.buffer = data; \
+ pFlac->br.len = length; \
+ pFlac->br.pos = 0; \
+ while(pFlac->state != MINIFLAC_METADATA) { \
+ r = miniflac_sync_internal(pFlac,&pFlac->br); \
+ if(r != MINIFLAC_OK) goto miniflac_ ## subsys ## _ ## val ##_exit; \
+ } \
+ while(pFlac->metadata.header.type != MINIFLAC_METADATA_ ## mt) { \
+ r = miniflac_sync_internal(pFlac,&pFlac->br); \
+ if(r != MINIFLAC_OK) goto miniflac_## subsys ## _ ## val ## _exit; \
+ if(pFlac->state != MINIFLAC_METADATA) { \
+ r = MINIFLAC_ERROR; \
+ goto miniflac_ ## subsys ## _ ## val ## _exit; \
+ } \
+ } \
+ r = miniflac_ ## subsys ## _read_ ## val(MINIFLAC_SUBSYS(subsys),&pFlac->br, outvar); \
+ miniflac_ ## subsys ## _ ## val ## _exit: \
+ *out_length = pFlac->br.pos; \
+ return r; \
+}
+
+#define MINIFLAC_GEN_OGG_FUNC1(subsys,val,t) \
+static \
+MINIFLAC_RESULT \
+miniflac_ ## subsys ## _ ## val ## _ogg(miniflac_t *pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, t* outvar) { \
+ MINIFLAC_RESULT r = MINIFLAC_CONTINUE; \
+ const uint8_t* packet = NULL; \
+ uint32_t packet_length = 0; \
+ uint32_t packet_used = 0; \
+ pFlac->ogg.br.buffer = data; \
+ pFlac->ogg.br.len = length; \
+ pFlac->ogg.br.pos = 0; \
+ do { \
+ r = miniflac_oggfunction_start(pFlac,data,&packet,&packet_length); \
+ if(r != MINIFLAC_OK) break; \
+ r = miniflac_ ## subsys ## _ ## val ## _native(pFlac,packet,packet_length,&packet_used,outvar); \
+ miniflac_oggfunction_end(pFlac,packet_used); \
+ } while(r == MINIFLAC_CONTINUE && pFlac->ogg.br.pos < length); \
+ *out_length = pFlac->ogg.br.pos; \
+ return r; \
+} \
+
+#define MINIFLAC_GEN_FUNC1(mt,subsys,val,t) \
+MINIFLAC_GEN_NATIVE_FUNC1(mt,subsys,val,t) \
+MINIFLAC_GEN_OGG_FUNC1(subsys,val,t) \
+MINIFLAC_API \
+MINIFLAC_RESULT \
+miniflac_ ## subsys ## _ ## val(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, t* outvar) { \
+ MINIFLAC_RESULT r; \
+ if(pFlac->container == MINIFLAC_CONTAINER_UNKNOWN) { \
+ r = miniflac_probe(pFlac,data,length); \
+ if(r != MINIFLAC_OK) return r; \
+ } \
+ if(pFlac->container == MINIFLAC_CONTAINER_NATIVE) { \
+ r = miniflac_ ## subsys ## _ ## val ## _native(pFlac,data,length,out_length,outvar); \
+ } else { \
+ r = miniflac_ ## subsys ## _ ## val ## _ogg(pFlac,data,length,out_length,outvar); \
+ } \
+ return r; \
+}
+
+#define MINIFLAC_GEN_NATIVE_FUNCSTR(mt,subsys,val,t) \
+static \
+MINIFLAC_RESULT \
+miniflac_ ## subsys ## _ ## val ## _native(miniflac_t *pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, t* buffer, uint32_t bufferlen, uint32_t* outlen) { \
+ MINIFLAC_RESULT r; \
+ pFlac->br.buffer = data; \
+ pFlac->br.len = length; \
+ pFlac->br.pos = 0; \
+ while(pFlac->state != MINIFLAC_METADATA) { \
+ r = miniflac_sync_internal(pFlac,&pFlac->br); \
+ if(r != MINIFLAC_OK) goto miniflac_ ## subsys ## _ ## val ##_exit; \
+ } \
+ while(pFlac->metadata.header.type != MINIFLAC_METADATA_ ## mt) { \
+ r = miniflac_sync_internal(pFlac,&pFlac->br); \
+ if(r != MINIFLAC_OK) goto miniflac_## subsys ## _ ## val ## _exit; \
+ if(pFlac->state != MINIFLAC_METADATA) { \
+ r = MINIFLAC_ERROR; \
+ goto miniflac_ ## subsys ## _ ## val ## _exit; \
+ } \
+ } \
+ r = miniflac_ ## subsys ## _read_ ## val(MINIFLAC_SUBSYS(subsys),&pFlac->br, buffer, bufferlen, outlen); \
+ miniflac_ ## subsys ## _ ## val ## _exit: \
+ *out_length = pFlac->br.pos; \
+ return r; \
+}
+
+#define MINIFLAC_GEN_OGG_FUNCSTR(subsys,val,t) \
+static \
+MINIFLAC_RESULT \
+miniflac_ ## subsys ## _ ## val ## _ogg(miniflac_t *pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, t* buffer, uint32_t bufferlen, uint32_t* outlen) { \
+ MINIFLAC_RESULT r = MINIFLAC_CONTINUE; \
+ const uint8_t* packet = NULL; \
+ uint32_t packet_length = 0; \
+ uint32_t packet_used = 0; \
+ pFlac->ogg.br.buffer = data; \
+ pFlac->ogg.br.len = length; \
+ pFlac->ogg.br.pos = 0; \
+ do { \
+ r = miniflac_oggfunction_start(pFlac,data,&packet,&packet_length); \
+ if(r != MINIFLAC_OK) break; \
+ r = miniflac_ ## subsys ## _ ## val ##_native(pFlac,packet,packet_length,&packet_used,buffer,bufferlen,outlen); \
+ miniflac_oggfunction_end(pFlac,packet_used); \
+ } while(r == MINIFLAC_CONTINUE && pFlac->ogg.br.pos < length); \
+ *out_length = pFlac->ogg.br.pos; \
+ return r; \
+} \
+
+#define MINIFLAC_GEN_FUNCSTR(mt,subsys,val,t) \
+MINIFLAC_GEN_NATIVE_FUNCSTR(mt,subsys,val,t) \
+MINIFLAC_GEN_OGG_FUNCSTR(subsys,val,t) \
+MINIFLAC_API \
+MINIFLAC_RESULT \
+miniflac_ ## subsys ## _ ## val(miniflac_t* pFlac, const uint8_t* data, uint32_t length, uint32_t* out_length, t* output, uint32_t buffer_length, uint32_t* outlen) { \
+ MINIFLAC_RESULT r; \
+ if(pFlac->container == MINIFLAC_CONTAINER_UNKNOWN) { \
+ r = miniflac_probe(pFlac,data,length); \
+ if(r != MINIFLAC_OK) return r; \
+ } \
+ if(pFlac->container == MINIFLAC_CONTAINER_NATIVE) { \
+ r = miniflac_ ## subsys ## _ ## val ## _native(pFlac,data,length,out_length,output,buffer_length,outlen); \
+ } else { \
+ r = miniflac_ ## subsys ## _ ## val ## _ogg(pFlac,data,length,out_length,output,buffer_length,outlen); \
+ } \
+ return r; \
+}
+
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,min_block_size,uint16_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,max_block_size,uint16_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,min_frame_size,uint32_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,max_frame_size,uint32_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,sample_rate,uint32_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,channels,uint8_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,bps,uint8_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,total_samples,uint64_t)
+MINIFLAC_GEN_FUNC1(STREAMINFO,streaminfo,md5_length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(STREAMINFO,streaminfo,md5_data,uint8_t)
+
+MINIFLAC_GEN_FUNC1(VORBIS_COMMENT,vorbis_comment,vendor_length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(VORBIS_COMMENT,vorbis_comment,vendor_string,char)
+MINIFLAC_GEN_FUNC1(VORBIS_COMMENT,vorbis_comment,total,uint32_t)
+MINIFLAC_GEN_FUNC1(VORBIS_COMMENT,vorbis_comment,length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(VORBIS_COMMENT,vorbis_comment,string,char)
+
+MINIFLAC_GEN_FUNC1(PICTURE,picture,type,uint32_t)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,mime_length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(PICTURE,picture,mime_string,char)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,description_length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(PICTURE,picture,description_string,char)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,width,uint32_t)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,height,uint32_t)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,colordepth,uint32_t)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,totalcolors,uint32_t)
+MINIFLAC_GEN_FUNC1(PICTURE,picture,length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(PICTURE,picture,data,uint8_t)
+
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,catalog_length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(CUESHEET,cuesheet,catalog_string,char)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,leadin,uint64_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,cd_flag,uint8_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,tracks,uint8_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,track_offset,uint64_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,track_number,uint8_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,track_isrc_length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(CUESHEET,cuesheet,track_isrc_string,char)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,track_audio_flag,uint8_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,track_preemph_flag,uint8_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,track_indexpoints,uint8_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,index_point_offset,uint64_t)
+MINIFLAC_GEN_FUNC1(CUESHEET,cuesheet,index_point_number,uint8_t)
+
+MINIFLAC_GEN_FUNC1(SEEKTABLE,seektable,seekpoints,uint32_t)
+MINIFLAC_GEN_FUNC1(SEEKTABLE,seektable,sample_number,uint64_t)
+MINIFLAC_GEN_FUNC1(SEEKTABLE,seektable,sample_offset,uint64_t)
+MINIFLAC_GEN_FUNC1(SEEKTABLE,seektable,samples,uint16_t)
+
+MINIFLAC_GEN_FUNC1(APPLICATION,application,id,uint32_t)
+MINIFLAC_GEN_FUNC1(APPLICATION,application,length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(APPLICATION,application,data,uint8_t)
+
+MINIFLAC_GEN_FUNC1(PADDING,padding,length,uint32_t)
+MINIFLAC_GEN_FUNCSTR(PADDING,padding,data,uint8_t)
+MINIFLAC_PRIVATE
+uint32_t
+miniflac_unpack_uint32le(uint8_t buffer[4]) {
+ return (
+ (((uint32_t)buffer[0]) << 0 ) |
+ (((uint32_t)buffer[1]) << 8 ) |
+ (((uint32_t)buffer[2]) << 16) |
+ (((uint32_t)buffer[3]) << 24));
+}
+
+MINIFLAC_PRIVATE
+int32_t
+miniflac_unpack_int32le(uint8_t buffer[4]) {
+ return (int32_t)miniflac_unpack_uint32le(buffer);
+}
+
+MINIFLAC_PRIVATE
+uint64_t
+miniflac_unpack_uint64le(uint8_t buffer[8]) {
+ return (
+ (((uint64_t)buffer[0]) << 0 ) |
+ (((uint64_t)buffer[1]) << 8 ) |
+ (((uint64_t)buffer[2]) << 16) |
+ (((uint64_t)buffer[3]) << 24) |
+ (((uint64_t)buffer[4]) << 32) |
+ (((uint64_t)buffer[5]) << 40) |
+ (((uint64_t)buffer[6]) << 48) |
+ (((uint64_t)buffer[7]) << 56));
+}
+
+MINIFLAC_PRIVATE
+int64_t
+miniflac_unpack_int64le(uint8_t buffer[8]) {
+ return (int64_t)miniflac_unpack_uint64le(buffer);
+}
+
+static const uint8_t miniflac_crc8_table[256] = {
+ 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
+ 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
+ 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
+ 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
+ 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
+ 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
+ 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
+ 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
+ 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
+ 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
+ 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
+ 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
+ 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
+ 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
+ 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
+ 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
+ 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
+ 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
+ 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
+ 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
+ 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
+ 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
+ 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
+ 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
+ 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
+ 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
+ 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
+ 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
+ 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
+ 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
+ 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
+ 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3,
+};
+
+static const uint16_t miniflac_crc16_table[256] = {
+ 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+ 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+ 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+ 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+ 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+ 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+ 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+ 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+ 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+ 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+ 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+ 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+ 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+ 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+ 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+ 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+ 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202,
+};
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_init(miniflac_bitreader_t* br) {
+ br->val = 0;
+ br->bits = 0;
+ br->crc8 = 0;
+ br->crc16 = 0;
+ br->pos = 0;
+ br->len = 0;
+ br->buffer = NULL;
+ br->tot = 0;
+}
+
+MINIFLAC_PRIVATE
+int
+miniflac_bitreader_fill(miniflac_bitreader_t* br, uint8_t bits) {
+ uint8_t byte = 0;
+ assert(bits <= 64);
+ if(bits == 0) return 0;
+ while(br->bits < bits && br->pos < br->len) {
+ byte = br->buffer[br->pos++];
+ br->val = (br->val << 8) | byte;
+ br->bits += 8;
+ br->crc8 = miniflac_crc8_table[br->crc8 ^ byte];
+ br->crc16 = miniflac_crc16_table[ (br->crc16 >> 8) ^ byte ] ^ (( br->crc16 & 0x00FF ) << 8);
+ br->tot++;
+ }
+ return br->bits < bits;
+}
+
+MINIFLAC_PRIVATE
+int
+miniflac_bitreader_fill_nocrc(miniflac_bitreader_t* br, uint8_t bits) {
+ uint8_t byte = 0;
+ assert(bits <= 64);
+ if(bits == 0) return 0;
+ while(br->bits < bits && br->pos < br->len) {
+ byte = br->buffer[br->pos++];
+ br->val = (br->val << 8) | byte;
+ br->bits += 8;
+ br->tot++;
+ }
+ return br->bits < bits;
+}
+
+
+MINIFLAC_PRIVATE
+uint64_t
+miniflac_bitreader_read(miniflac_bitreader_t* br, uint8_t bits) {
+ uint64_t mask = -1LL;
+ uint64_t imask = -1LL;
+ uint64_t r;
+
+ assert(bits <= br->bits);
+ if(bits == 0) return 0;
+
+ mask >>= (64 - bits);
+ br->bits -= bits;
+ r = br->val >> br->bits & mask;
+ if(br->bits == 0) {
+ imask = 0;
+ } else {
+ imask >>= (64 - br->bits);
+ }
+ br->val &= imask;
+
+ return r;
+}
+
+MINIFLAC_PRIVATE
+int64_t
+miniflac_bitreader_read_signed(miniflac_bitreader_t* br, uint8_t bits) {
+ uint64_t t;
+ uint64_t mask = -1LL;
+ if(bits == 0) return 0;
+ mask <<= bits;
+
+ t = miniflac_bitreader_read(br,bits);
+ if( (t & ( 1 << (bits - 1))) ) {
+ t |= mask;
+ }
+ return t;
+}
+
+
+MINIFLAC_PRIVATE
+uint64_t
+miniflac_bitreader_peek(miniflac_bitreader_t* br, uint8_t bits) {
+ uint64_t mask = -1LL;
+ uint64_t r;
+
+ assert(bits <= br->bits);
+ if(bits == 0) return 0;
+
+ mask >>= (64 - bits);
+ r = br->val >> (br->bits - bits) & mask;
+ return r;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_discard(miniflac_bitreader_t* br, uint8_t bits) {
+ uint64_t imask = -1LL;
+
+ assert(bits <= br->bits);
+ if(bits == 0) return;
+
+ br->bits -= bits;
+
+ if(br->bits == 0) {
+ imask = 0;
+ } else {
+ imask >>= (64 - br->bits);
+ }
+ br->val &= imask;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_align(miniflac_bitreader_t* br) {
+ assert(br->bits < 8);
+ br->bits = 0;
+ br->val = 0;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_bitreader_reset_crc(miniflac_bitreader_t* br) {
+ uint64_t val = br->val;
+ uint8_t bits = br->bits;
+
+ uint8_t byte;
+ uint64_t mask;
+ uint64_t imask;
+
+ br->crc8 = 0;
+ br->crc16 = 0;
+ br->tot = 0;
+
+ while(bits > 0) {
+ mask = -1LL;
+ imask = -1LL;
+
+ mask >>= (64 - 8);
+ bits -= 8;
+ byte = val >> bits & mask;
+ if(bits == 0) {
+ imask = 0;
+ } else {
+ imask >>= (64 - bits);
+ }
+ val &= imask;
+ br->crc8 = miniflac_crc8_table[br->crc8 ^ byte];
+ br->crc16 = miniflac_crc16_table[ (br->crc16 >> 8) ^ byte ] ^ (( br->crc16 & 0x00FF ) << 8);
+ br->tot++;
+ }
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_oggheader_init(miniflac_oggheader_t* oggheader) {
+ oggheader->state = MINIFLAC_OGGHEADER_PACKETTYPE;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_oggheader_decode(miniflac_oggheader_t* oggheader, miniflac_bitreader_t* br) {
+ switch(oggheader->state) {
+ case MINIFLAC_OGGHEADER_PACKETTYPE: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((uint8_t)miniflac_bitreader_read(br,8) != 0x7F) {
+ return MINIFLAC_OGG_HEADER_NOTFLAC;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_F;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_F: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((char)miniflac_bitreader_read(br,8) != 'F') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_L;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_L: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((char)miniflac_bitreader_read(br,8) != 'L') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_A;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_A: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((char)miniflac_bitreader_read(br,8) != 'A') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_C;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_C: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((char)miniflac_bitreader_read(br,8) != 'C') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_MAJOR;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_MAJOR: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((uint8_t)miniflac_bitreader_read(br,8) != 0x01) {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_MINOR;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_MINOR: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ if((uint8_t)miniflac_bitreader_read(br,8) != 0x00) {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ oggheader->state = MINIFLAC_OGGHEADER_HEADERPACKETS;
+ }
+ /* fall-through */
+ case MINIFLAC_OGGHEADER_HEADERPACKETS: {
+ if(miniflac_bitreader_fill_nocrc(br,16)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,16);
+ oggheader->state = MINIFLAC_OGGHEADER_PACKETTYPE;
+ }
+ /* fall-through */
+ default: break;
+ }
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_ogg_init(miniflac_ogg_t* ogg) {
+ ogg->state = MINIFLAC_OGG_CAPTUREPATTERN_O;
+ ogg->version = 0;
+ ogg->headertype = 0;
+ ogg->granulepos = 0;
+ ogg->serialno = 0;
+ ogg->pageno = 0;
+ ogg->segments = 0;
+ ogg->curseg = 0;
+ ogg->length = 0;
+ ogg->pos = 0;
+ miniflac_bitreader_init(&ogg->br);
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_ogg_sync(miniflac_ogg_t* ogg,miniflac_bitreader_t* br) {
+ unsigned char c;
+ uint8_t buffer[8];
+
+ switch(ogg->state) {
+ case MINIFLAC_OGG_SKIP: /* fall-through */
+ case MINIFLAC_OGG_DATA: {
+ while(ogg->pos < ogg->length) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,8);
+ ogg->pos++;
+ }
+ ogg->state = MINIFLAC_OGG_CAPTUREPATTERN_O;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_CAPTUREPATTERN_O: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (unsigned char)miniflac_bitreader_read(br,8);
+ if(c != 'O') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ ogg->state = MINIFLAC_OGG_CAPTUREPATTERN_G1;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_CAPTUREPATTERN_G1: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (unsigned char)miniflac_bitreader_read(br,8);
+ if(c != 'g') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ ogg->state = MINIFLAC_OGG_CAPTUREPATTERN_G2;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_CAPTUREPATTERN_G2: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (unsigned char)miniflac_bitreader_read(br,8);
+ if(c != 'g') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ ogg->state = MINIFLAC_OGG_CAPTUREPATTERN_S;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_CAPTUREPATTERN_S: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (unsigned char)miniflac_bitreader_read(br,8);
+ if(c != 'S') {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ ogg->state = MINIFLAC_OGG_VERSION;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_VERSION: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ ogg->version = (uint8_t)miniflac_bitreader_read(br,8);
+ if(ogg->version != 0) {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ ogg->state = MINIFLAC_OGG_HEADERTYPE;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_HEADERTYPE: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ ogg->headertype = (uint8_t)miniflac_bitreader_read(br,8);
+ ogg->state = MINIFLAC_OGG_GRANULEPOS;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_GRANULEPOS: {
+ if(miniflac_bitreader_fill_nocrc(br,64)) return MINIFLAC_CONTINUE;
+ buffer[0] = miniflac_bitreader_read(br,8);
+ buffer[1] = miniflac_bitreader_read(br,8);
+ buffer[2] = miniflac_bitreader_read(br,8);
+ buffer[3] = miniflac_bitreader_read(br,8);
+ buffer[4] = miniflac_bitreader_read(br,8);
+ buffer[5] = miniflac_bitreader_read(br,8);
+ buffer[6] = miniflac_bitreader_read(br,8);
+ buffer[7] = miniflac_bitreader_read(br,8);
+ ogg->granulepos = miniflac_unpack_int64le(buffer);
+ ogg->state = MINIFLAC_OGG_SERIALNO;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_SERIALNO: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ buffer[0] = miniflac_bitreader_read(br,8);
+ buffer[1] = miniflac_bitreader_read(br,8);
+ buffer[2] = miniflac_bitreader_read(br,8);
+ buffer[3] = miniflac_bitreader_read(br,8);
+ ogg->serialno = miniflac_unpack_int32le(buffer);
+ ogg->state = MINIFLAC_OGG_PAGENO;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_PAGENO: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ buffer[0] = miniflac_bitreader_read(br,8);
+ buffer[1] = miniflac_bitreader_read(br,8);
+ buffer[2] = miniflac_bitreader_read(br,8);
+ buffer[3] = miniflac_bitreader_read(br,8);
+ ogg->pageno = miniflac_unpack_uint32le(buffer);
+ ogg->state = MINIFLAC_OGG_CHECKSUM;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_CHECKSUM: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,32);
+ ogg->state = MINIFLAC_OGG_PAGESEGMENTS;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_PAGESEGMENTS: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ ogg->segments = (uint8_t) miniflac_bitreader_read(br,8);
+ ogg->curseg = 0;
+ ogg->length = 0;
+ ogg->state = MINIFLAC_OGG_SEGMENTTABLE;
+ }
+ /* fall-through */
+ case MINIFLAC_OGG_SEGMENTTABLE: {
+ while(ogg->curseg < ogg->segments) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ ogg->length += miniflac_bitreader_read(br,8);
+ ogg->curseg++;
+ }
+ ogg->pos = 0;
+ ogg->state = MINIFLAC_OGG_DATA;
+ return MINIFLAC_OK;
+ }
+ }
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_frame_init(miniflac_frame_t* frame) {
+ frame->crc16 = 0;
+ frame->cur_subframe = 0;
+ frame->state = MINIFLAC_FRAME_HEADER;
+ miniflac_frame_header_init(&frame->header);
+ miniflac_subframe_init(&frame->subframe);
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_frame_sync(miniflac_frame_t* frame, miniflac_bitreader_t* br, miniflac_streaminfo_t* info) {
+ MINIFLAC_RESULT r;
+ assert(frame->state == MINIFLAC_FRAME_HEADER);
+ r = miniflac_frame_header_decode(&frame->header,br);
+ if(r != MINIFLAC_OK) return r;
+
+ if(frame->header.sample_rate == 0) {
+ if(info->sample_rate == 0) return MINIFLAC_FRAME_INVALID_SAMPLE_RATE;
+ frame->header.sample_rate = info->sample_rate;
+ }
+
+ if(frame->header.bps == 0) {
+ if(info->bps == 0) return MINIFLAC_FRAME_INVALID_SAMPLE_SIZE;
+ frame->header.bps = info->bps;
+ }
+
+ frame->state = MINIFLAC_FRAME_SUBFRAME;
+ frame->cur_subframe = 0;
+ miniflac_subframe_init(&frame->subframe);
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_frame_decode(miniflac_frame_t* frame, miniflac_bitreader_t* br, miniflac_streaminfo_t* info, int32_t** output) {
+ MINIFLAC_RESULT r;
+ uint32_t bps;
+ uint32_t i;
+ uint64_t m,s;
+ uint16_t t;
+ switch(frame->state) {
+ case MINIFLAC_FRAME_HEADER: {
+ r = miniflac_frame_sync(frame,br,info);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_SUBFRAME: {
+ while(frame->cur_subframe < frame->header.channels) {
+ bps = frame->header.bps;
+ if(frame->header.channel_assignment == MINIFLAC_CHASSGN_LEFT_SIDE || frame->header.channel_assignment == MINIFLAC_CHASSGN_MID_SIDE) {
+ if(frame->cur_subframe == 1) bps += 1;
+ } else if(frame->header.channel_assignment == MINIFLAC_CHASSGN_RIGHT_SIDE) {
+ if(frame->cur_subframe == 0) bps += 1;
+ }
+ r = miniflac_subframe_decode(&frame->subframe,br,output == NULL ? NULL : output[frame->cur_subframe],frame->header.block_size,bps);
+ if(r != MINIFLAC_OK) return r;
+
+ miniflac_subframe_init(&frame->subframe);
+ frame->cur_subframe++;
+ }
+
+ miniflac_bitreader_align(br);
+ frame->crc16 = br->crc16;
+ frame->state = MINIFLAC_FRAME_FOOTER;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_FOOTER: {
+ if(miniflac_bitreader_fill(br,16)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,16);
+ if(frame->crc16 != t) {
+ miniflac_abort();
+ return MINIFLAC_FRAME_CRC16_INVALID;
+ }
+ frame->size = br->tot;
+ if(output != NULL) {
+ switch(frame->header.channel_assignment) {
+ case MINIFLAC_CHASSGN_LEFT_SIDE: {
+ for(i=0;iheader.block_size;i++) {
+ output[1][i] = output[0][i] - output[1][i];
+ }
+ break;
+ }
+ case MINIFLAC_CHASSGN_RIGHT_SIDE: {
+ for(i=0;iheader.block_size;i++) {
+ output[0][i] = output[0][i] + output[1][i];
+ }
+ break;
+ }
+ case MINIFLAC_CHASSGN_MID_SIDE: {
+ for(i=0;iheader.block_size;i++) {
+ m = (uint64_t)output[0][i];
+ s = (uint64_t)output[1][i];
+ m = (m << 1) | (s & 0x01);
+ output[0][i] = (int32_t)((m + s) >> 1 );
+ output[1][i] = (int32_t)((m - s) >> 1 );
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+ break;
+ }
+ default: {
+ /* invalid state */
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ }
+
+ assert(br->bits == 0);
+ br->crc8 = 0;
+ br->crc16 = 0;
+ frame->cur_subframe = 0;
+ frame->state = MINIFLAC_FRAME_HEADER;
+ miniflac_subframe_init(&frame->subframe);
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_frame_header_init(miniflac_frame_header_t* header) {
+ header->block_size_raw = 0;
+ header->sample_rate_raw = 0;
+ header->channel_assignment_raw = 0;
+ header->sample_rate = 0;
+ header->blocking_strategy = 0;
+ header->block_size = 0;
+ header->sample_rate = 0;
+ header->channel_assignment = MINIFLAC_CHASSGN_NONE;
+ header->channels = 0;
+ header->bps = 0;
+ header->sample_number = 0;
+ header->crc8 = 0;
+ header->state = MINIFLAC_FRAME_HEADER_SYNC;
+}
+
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_frame_header_decode(miniflac_frame_header_t* header, miniflac_bitreader_t* br) {
+ uint64_t t;
+
+ switch(header->state) {
+ case MINIFLAC_FRAME_HEADER_SYNC: {
+ miniflac_bitreader_reset_crc(br);
+ if(miniflac_bitreader_fill(br,14)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,14);
+ if(t != 0x3FFE) {
+ miniflac_abort();
+ return MINIFLAC_FRAME_SYNCCODE_INVALID;
+ }
+ miniflac_frame_header_init(header);
+ header->state = MINIFLAC_FRAME_HEADER_RESERVEBIT_1;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_RESERVEBIT_1: {
+ if(miniflac_bitreader_fill(br,1)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,1);
+ if(t != 0) {
+ miniflac_abort();
+ return MINIFLAC_FRAME_RESERVED_BIT1;
+ }
+ header->state = MINIFLAC_FRAME_HEADER_BLOCKINGSTRATEGY;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_BLOCKINGSTRATEGY: {
+ if(miniflac_bitreader_fill(br,1)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,1);
+ header->blocking_strategy = t;
+ header->state = MINIFLAC_FRAME_HEADER_BLOCKSIZE;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_BLOCKSIZE: {
+ if(miniflac_bitreader_fill(br,4)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,4);
+ header->block_size_raw = t;
+ header->block_size = 0;
+ switch(header->block_size_raw) {
+ case 0: {
+ miniflac_abort();
+ return MINIFLAC_FRAME_RESERVED_BLOCKSIZE;
+ }
+ case 1: {
+ header->block_size = 192;
+ break;
+ }
+ case 2: {
+ header->block_size = 576;
+ break;
+ }
+ case 3: {
+ header->block_size = 1152;
+ break;
+ }
+ case 4: {
+ header->block_size = 2304;
+ break;
+ }
+ case 5: {
+ header->block_size = 4608;
+ break;
+ }
+ case 8: {
+ header->block_size = 256;
+ break;
+ }
+ case 9: {
+ header->block_size = 512;
+ break;
+ }
+ case 10: {
+ header->block_size = 1024;
+ break;
+ }
+ case 11: {
+ header->block_size = 2048;
+ break;
+ }
+ case 12: {
+ header->block_size = 4096;
+ break;
+ }
+ case 13: {
+ header->block_size = 8192;
+ break;
+ }
+ case 14: {
+ header->block_size = 16384;
+ break;
+ }
+ case 15: {
+ header->block_size = 32768;
+ break;
+ }
+ default: break;
+ }
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLERATE;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLERATE: {
+ if(miniflac_bitreader_fill(br,4)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,4);
+ header->sample_rate_raw = t;
+ switch(header->sample_rate_raw) {
+ case 0: {
+ header->sample_rate = 0;
+ break;
+ }
+ case 1: {
+ header->sample_rate = 88200;
+ break;
+ }
+ case 2: {
+ header->sample_rate = 176400;
+ break;
+ }
+ case 3: {
+ header->sample_rate = 192000;
+ break;
+ }
+ case 4: {
+ header->sample_rate = 8000;
+ break;
+ }
+ case 5: {
+ header->sample_rate = 16000;
+ break;
+ }
+ case 6: {
+ header->sample_rate = 22050;
+ break;
+ }
+ case 7: {
+ header->sample_rate = 24000;
+ break;
+ }
+ case 8: {
+ header->sample_rate = 32000;
+ break;
+ }
+ case 9: {
+ header->sample_rate = 44100;
+ break;
+ }
+ case 10: {
+ header->sample_rate = 48000;
+ break;
+ }
+ case 11: {
+ header->sample_rate = 96000;
+ break;
+ }
+ case 12: /* fall-through */
+ case 13: /* fall-through */
+ case 14: {
+ header->sample_rate = 0;
+ break;
+ }
+ case 15: {
+ miniflac_abort();
+ return MINIFLAC_FRAME_INVALID_SAMPLE_RATE;
+ }
+ default: break;
+ }
+
+ header->state = MINIFLAC_FRAME_HEADER_CHANNELASSIGNMENT;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_CHANNELASSIGNMENT: {
+ if(miniflac_bitreader_fill(br,4)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,4);
+ if(t > 10) {
+ miniflac_abort();
+ return MINIFLAC_FRAME_RESERVED_CHANNEL_ASSIGNMENT;
+ }
+
+ if(t < 8) {
+ header->channels = t + 1;
+ header->channel_assignment = MINIFLAC_CHASSGN_NONE;
+ } else {
+ switch(t) {
+ case 8: {
+ header->channel_assignment = MINIFLAC_CHASSGN_LEFT_SIDE; break;
+ }
+ case 9: {
+ header->channel_assignment = MINIFLAC_CHASSGN_RIGHT_SIDE; break;
+ }
+ case 10: {
+ header->channel_assignment = MINIFLAC_CHASSGN_MID_SIDE; break;
+ }
+ default: break;
+ }
+ header->channels = 2;
+ }
+
+ header->channel_assignment_raw = t;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLESIZE;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLESIZE: {
+ if(miniflac_bitreader_fill(br,3)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,3);
+ switch(t) {
+ case 0: header->bps = 0; break;
+ case 1: header->bps = 8; break;
+ case 2: header->bps = 12; break;
+ case 3: {
+ miniflac_abort();
+ return MINIFLAC_FRAME_RESERVED_SAMPLE_SIZE;
+ }
+ case 4: header->bps = 16; break;
+ case 5: header->bps = 20; break;
+ case 6: header->bps = 24; break;
+ case 7: {
+ miniflac_abort();
+ return MINIFLAC_FRAME_RESERVED_SAMPLE_SIZE;
+ }
+ }
+ header->state = MINIFLAC_FRAME_HEADER_RESERVEBIT_2;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_RESERVEBIT_2: {
+ if(miniflac_bitreader_fill(br,1)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,1);
+ if(t != 0) {
+ miniflac_abort();
+ return MINIFLAC_FRAME_RESERVED_BIT2;
+ }
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_1;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_1: {
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+
+ if((t & 0x80) == 0x00) {
+ header->sample_number = t;
+ header->state = MINIFLAC_FRAME_HEADER_BLOCKSIZE_MAYBE;
+ goto flac_frame_blocksize_maybe;
+ }
+ else if((t & 0xE0) == 0xC0) {
+ header->sample_number = (t & 0x1F) << 6;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_7;
+ goto flac_frame_samplenumber_7;
+ } else if((t & 0xF0) == 0xE0) {
+ header->sample_number = (t & 0x0F) << 12;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_6;
+ goto flac_frame_samplenumber_6;
+ } else if((t & 0xF8) == 0xF0) {
+ header->sample_number = (t & 0x07) << 18;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_5;
+ goto flac_frame_samplenumber_5;
+ } else if((t & 0xFC) == 0xF8) {
+ header->sample_number = (t & 0x03) << 24;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_4;
+ goto flac_frame_samplenumber_4;
+ } else if((t & 0xFE) == 0xFC) {
+ header->sample_number = (t & 0x01) << 30;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_3;
+ goto flac_frame_samplenumber_3;
+ } else if((t & 0xFF) == 0xFE) {
+ /* untested, requires a variable blocksize stream with a lot of samples, YMMV */
+ header->sample_number = 0;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_2;
+ goto flac_frame_samplenumber_2;
+ }
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_2: {
+ flac_frame_samplenumber_2:
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_number += (t & 0x3F) << 30;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_3;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_3: {
+ flac_frame_samplenumber_3:
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_number += (t & 0x3F) << 24;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_4;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_4: {
+ flac_frame_samplenumber_4:
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_number += (t & 0x3F) << 18;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_5;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_5: {
+ flac_frame_samplenumber_5:
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_number += (t & 0x3F) << 12;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_6;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_6: {
+ flac_frame_samplenumber_6:
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_number += (t & 0x3F) << 6;
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLENUMBER_7;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLENUMBER_7: {
+ flac_frame_samplenumber_7:
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_number += (t & 0x3F);
+ header->state = MINIFLAC_FRAME_HEADER_BLOCKSIZE_MAYBE;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_BLOCKSIZE_MAYBE: {
+ flac_frame_blocksize_maybe:
+ switch(header->block_size_raw) {
+ case 6: {
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8) + 1;
+ header->block_size = t;
+ break;
+ }
+ case 7: {
+ if(miniflac_bitreader_fill(br,16)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,16) + 1;
+ header->block_size = t;
+ break;
+ }
+ default: break;
+ }
+ header->state = MINIFLAC_FRAME_HEADER_SAMPLERATE_MAYBE;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_SAMPLERATE_MAYBE: {
+ switch(header->sample_rate_raw) {
+ case 12: {
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ header->sample_rate = t * 1000;
+ break;
+ }
+ case 13: {
+ if(miniflac_bitreader_fill(br,16)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,16);
+ header->sample_rate = t;
+ break;
+ }
+ case 14: {
+ if(miniflac_bitreader_fill(br,16)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,16);
+ header->sample_rate = t * 10;
+ break;
+ }
+ default: break;
+ }
+
+ /* grab crc8 from bitreader before fill */
+ header->crc8 = br->crc8;
+ header->state = MINIFLAC_FRAME_HEADER_CRC8;
+ }
+ /* fall-through */
+ case MINIFLAC_FRAME_HEADER_CRC8: {
+ if(miniflac_bitreader_fill(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ if(header->crc8 != t) {
+ miniflac_abort();
+ return MINIFLAC_FRAME_CRC8_INVALID;
+ }
+ }
+ /* fall-through */
+ default: break;
+ }
+
+ header->state = MINIFLAC_FRAME_HEADER_SYNC;
+ return MINIFLAC_OK;
+}
+
+
+MINIFLAC_PRIVATE
+void
+miniflac_vorbis_comment_init(miniflac_vorbis_comment_t* vorbis_comment) {
+ vorbis_comment->state = MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH;
+ vorbis_comment->len = 0;
+ vorbis_comment->pos = 0;
+ vorbis_comment->tot = 0;
+ vorbis_comment->cur = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_vendor_length(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, uint32_t* length) {
+ uint8_t buffer[4];
+ switch(vorbis_comment->state) {
+ case MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ buffer[0] = miniflac_bitreader_read(br,8);
+ buffer[1] = miniflac_bitreader_read(br,8);
+ buffer[2] = miniflac_bitreader_read(br,8);
+ buffer[3] = miniflac_bitreader_read(br,8);
+ vorbis_comment->len = miniflac_unpack_uint32le(buffer);
+ if(length != NULL) *length = vorbis_comment->len;
+ vorbis_comment->state = MINIFLAC_VORBISCOMMENT_VENDOR_STRING;
+ return MINIFLAC_OK;
+ } default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_vendor_string(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ char c;
+
+ switch(vorbis_comment->state) {
+ case MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH: {
+ r = miniflac_vorbis_comment_read_vendor_length(vorbis_comment,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_VENDOR_STRING: {
+ while(vorbis_comment->pos < vorbis_comment->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (char)miniflac_bitreader_read(br,8);
+ if(output != NULL && vorbis_comment->pos < length) {
+ output[vorbis_comment->pos] = c;
+ }
+ vorbis_comment->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = vorbis_comment->len <= length ? vorbis_comment->len : length;
+ }
+ vorbis_comment->state = MINIFLAC_VORBISCOMMENT_TOTAL_COMMENTS;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_total(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, uint32_t* total) {
+ uint8_t buffer[4];
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+
+ switch(vorbis_comment->state) {
+ case MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH: /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_VENDOR_STRING: {
+ r = miniflac_vorbis_comment_read_vendor_string(vorbis_comment,br,NULL,0,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_TOTAL_COMMENTS: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ buffer[0] = miniflac_bitreader_read(br,8);
+ buffer[1] = miniflac_bitreader_read(br,8);
+ buffer[2] = miniflac_bitreader_read(br,8);
+ buffer[3] = miniflac_bitreader_read(br,8);
+ vorbis_comment->tot = miniflac_unpack_uint32le(buffer);
+ if(total != NULL) *total = vorbis_comment->tot;
+ vorbis_comment->state = MINIFLAC_VORBISCOMMENT_COMMENT_LENGTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_length(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, uint32_t* length) {
+ uint8_t buffer[4];
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+
+ switch(vorbis_comment->state) {
+ case MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH: /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_VENDOR_STRING: /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_TOTAL_COMMENTS: {
+ r = miniflac_vorbis_comment_read_total(vorbis_comment,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_COMMENT_LENGTH: {
+ case_miniflac_vorbis_comment_comment_length:
+ if(vorbis_comment->cur == vorbis_comment->tot) {
+ return MINIFLAC_METADATA_END;
+ }
+
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ buffer[0] = miniflac_bitreader_read(br,8);
+ buffer[1] = miniflac_bitreader_read(br,8);
+ buffer[2] = miniflac_bitreader_read(br,8);
+ buffer[3] = miniflac_bitreader_read(br,8);
+ vorbis_comment->len = miniflac_unpack_uint32le(buffer);
+ vorbis_comment->pos = 0;
+ if(length != NULL) *length = vorbis_comment->len;
+ vorbis_comment->state = MINIFLAC_VORBISCOMMENT_COMMENT_STRING;
+ return MINIFLAC_OK;
+ }
+ case MINIFLAC_VORBISCOMMENT_COMMENT_STRING: {
+ r = miniflac_vorbis_comment_read_string(vorbis_comment,br,NULL,0,NULL);
+ if(r != MINIFLAC_OK) return r;
+ goto case_miniflac_vorbis_comment_comment_length;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_vorbis_comment_read_string(miniflac_vorbis_comment_t* vorbis_comment, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ char c;
+
+ switch(vorbis_comment->state) {
+ case MINIFLAC_VORBISCOMMENT_VENDOR_LENGTH:
+ case MINIFLAC_VORBISCOMMENT_VENDOR_STRING:
+ case MINIFLAC_VORBISCOMMENT_TOTAL_COMMENTS:
+ case MINIFLAC_VORBISCOMMENT_COMMENT_LENGTH: {
+ r = miniflac_vorbis_comment_read_length(vorbis_comment,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_VORBISCOMMENT_COMMENT_STRING: {
+ while(vorbis_comment->pos < vorbis_comment->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (char)miniflac_bitreader_read(br,8);
+ if(output != NULL && vorbis_comment->pos < length) {
+ output[vorbis_comment->pos] = c;
+ }
+ vorbis_comment->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = vorbis_comment->len <= length ? vorbis_comment->len : length;
+ }
+ vorbis_comment->cur++;
+ vorbis_comment->state = MINIFLAC_VORBISCOMMENT_COMMENT_LENGTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_picture_init(miniflac_picture_t* picture) {
+ picture->state = MINIFLAC_PICTURE_TYPE;
+ picture->len = 0;
+ picture->pos = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_type(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* type) {
+ uint32_t t = 0;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,32);
+ if(type != NULL) *type = t;
+ picture->state = MINIFLAC_PICTURE_MIME_LENGTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_mime_length(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: {
+ r = miniflac_picture_read_type(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ picture->len = miniflac_bitreader_read(br,32);
+ picture->pos = 0;
+ if(length != NULL) *length = picture->len;
+ picture->state = MINIFLAC_PICTURE_MIME_STRING;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_mime_string(miniflac_picture_t* picture, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ char c;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: {
+ r = miniflac_picture_read_mime_length(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: {
+ while(picture->pos < picture->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (char)miniflac_bitreader_read(br,8);
+ if(output != NULL && picture->pos < length) {
+ output[picture->pos] = c;
+ }
+ picture->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = picture->len <= length ? picture->len : length;
+ }
+ picture->state = MINIFLAC_PICTURE_DESCRIPTION_LENGTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_description_length(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: {
+ r = miniflac_picture_read_mime_string(picture,br,NULL,0,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ picture->len = miniflac_bitreader_read(br,32);
+ picture->pos = 0;
+ if(length != NULL) *length = picture->len;
+ picture->state = MINIFLAC_PICTURE_DESCRIPTION_STRING;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_description_string(miniflac_picture_t* picture, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ char c;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: {
+ r = miniflac_picture_read_description_length(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: {
+ while(picture->pos < picture->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (char)miniflac_bitreader_read(br,8);
+ if(output != NULL && picture->pos < length) {
+ output[picture->pos] = c;
+ }
+ picture->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = picture->len <= length ? picture->len : length;
+ }
+ picture->state = MINIFLAC_PICTURE_WIDTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_width(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* width) {
+ uint32_t t = 0;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: {
+ r = miniflac_picture_read_description_string(picture,br,NULL,0,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_WIDTH: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,32);
+ if(width != NULL) *width = t;
+ picture->state = MINIFLAC_PICTURE_HEIGHT;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_height(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* height) {
+ uint32_t t = 0;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_WIDTH: {
+ r = miniflac_picture_read_width(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_HEIGHT: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,32);
+ if(height != NULL) *height = t;
+ picture->state = MINIFLAC_PICTURE_COLORDEPTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_colordepth(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* colordepth) {
+ uint32_t t = 0;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_WIDTH: /* fall-through */
+ case MINIFLAC_PICTURE_HEIGHT: {
+ r = miniflac_picture_read_height(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_COLORDEPTH: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,32);
+ if(colordepth != NULL) *colordepth = t;
+ picture->state = MINIFLAC_PICTURE_TOTALCOLORS;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_totalcolors(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* totalcolors) {
+ uint32_t t = 0;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_WIDTH: /* fall-through */
+ case MINIFLAC_PICTURE_HEIGHT: /* fall-through */
+ case MINIFLAC_PICTURE_COLORDEPTH: {
+ r = miniflac_picture_read_colordepth(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_TOTALCOLORS: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,32);
+ if(totalcolors != NULL) *totalcolors = t;
+ picture->state = MINIFLAC_PICTURE_PICTURE_LENGTH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_length(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint32_t* length) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_WIDTH: /* fall-through */
+ case MINIFLAC_PICTURE_HEIGHT: /* fall-through */
+ case MINIFLAC_PICTURE_COLORDEPTH: /* fall-through */
+ case MINIFLAC_PICTURE_TOTALCOLORS: {
+ r = miniflac_picture_read_totalcolors(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_PICTURE_LENGTH: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ picture->len = miniflac_bitreader_read(br,32);
+ picture->pos = 0;
+ if(length != NULL) *length = picture->len;
+ picture->state = MINIFLAC_PICTURE_PICTURE_DATA;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_picture_read_data(miniflac_picture_t* picture, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t c;
+ switch(picture->state) {
+ case MINIFLAC_PICTURE_TYPE: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_MIME_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_LENGTH: /* fall-through */
+ case MINIFLAC_PICTURE_DESCRIPTION_STRING: /* fall-through */
+ case MINIFLAC_PICTURE_WIDTH: /* fall-through */
+ case MINIFLAC_PICTURE_HEIGHT: /* fall-through */
+ case MINIFLAC_PICTURE_COLORDEPTH: /* fall-through */
+ case MINIFLAC_PICTURE_TOTALCOLORS: /* fall-through */
+ case MINIFLAC_PICTURE_PICTURE_LENGTH: {
+ r = miniflac_picture_read_length(picture,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_PICTURE_PICTURE_DATA: {
+ if(picture->pos == picture->len) return MINIFLAC_METADATA_END;
+ while(picture->pos < picture->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (uint8_t)miniflac_bitreader_read(br,8);
+ if(output != NULL && picture->pos < length) {
+ output[picture->pos] = c;
+ }
+ picture->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = picture->len <= length ? picture->len : length;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_cuesheet_init(miniflac_cuesheet_t* cuesheet) {
+ cuesheet->state = MINIFLAC_CUESHEET_CATALOG;
+ cuesheet->pos = 0;
+ cuesheet->track = 0;
+ cuesheet->tracks = 0;
+ cuesheet->point = 0;
+ cuesheet->points = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_catalog_length(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint32_t* catalog_length) {
+ (void)br;
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: {
+ if(catalog_length != NULL) {
+ *catalog_length = 128;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_catalog_string(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen) {
+ char c;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: {
+ while(cuesheet->pos < 128) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (char)miniflac_bitreader_read(br,8);
+ if(output != NULL && cuesheet->pos < length) {
+ output[cuesheet->pos] = c;
+ }
+ cuesheet->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = cuesheet->pos < length ? cuesheet->pos : length;
+ }
+ cuesheet->pos = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_LEADIN;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_leadin(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint64_t* leadin) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint64_t t = 0;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: {
+ r = miniflac_cuesheet_read_catalog_string(cuesheet,br, NULL, 0, NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: {
+ if(miniflac_bitreader_fill_nocrc(br,64)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,64);
+ if(leadin != NULL) {
+ *leadin = t;
+ }
+ cuesheet->state = MINIFLAC_CUESHEET_CDFLAG;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_cd_flag(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* flag) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t f = 0;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: {
+ r = miniflac_cuesheet_read_leadin(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: {
+ if(miniflac_bitreader_fill_nocrc(br,1)) return MINIFLAC_CONTINUE;
+ f = (uint8_t)miniflac_bitreader_read(br,1);
+ if(flag != NULL) {
+ *flag = f;
+ }
+ miniflac_bitreader_discard(br,7);
+ cuesheet->state = MINIFLAC_CUESHEET_SHEET_RESERVE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_tracks(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* tracks) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: {
+ r = miniflac_cuesheet_read_cd_flag(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: {
+ while(cuesheet->pos < 258) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,8);
+ cuesheet->pos++;
+ }
+ cuesheet->pos = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKS;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ cuesheet->tracks = (uint8_t)miniflac_bitreader_read(br,8);
+ if(tracks != NULL) {
+ *tracks = cuesheet->tracks;
+ }
+ cuesheet->track = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKOFFSET;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_offset(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint64_t* track_offset) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint64_t t = 0;
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: {
+ r = miniflac_cuesheet_read_tracks(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: {
+ case_miniflac_cuesheet_trackoffset:
+ if(cuesheet->track == cuesheet->tracks) return MINIFLAC_METADATA_END;
+ if(miniflac_bitreader_fill_nocrc(br,64)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,64);
+ if(track_offset != NULL) {
+ *track_offset = t;
+ }
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKNUMBER;
+ return MINIFLAC_OK;
+ }
+ case MINIFLAC_CUESHEET_INDEX_OFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_NUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_RESERVE: {
+ r = miniflac_cuesheet_read_index_point_offset(cuesheet,br,NULL);
+ if(r != MINIFLAC_METADATA_END) return r;
+ /* cuesheet state was changed to TRACKOFFSET for us */
+ goto case_miniflac_cuesheet_trackoffset;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_number(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_number) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t t = 0;
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: {
+ r = miniflac_cuesheet_read_track_offset(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = (uint8_t)miniflac_bitreader_read(br,8);
+ if(track_number != NULL) {
+ *track_number = t;
+ }
+ cuesheet->pos = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKISRC;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_isrc_length(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint32_t* isrc_length) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: {
+ r = miniflac_cuesheet_read_track_number(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: {
+ if(isrc_length != NULL) {
+ *isrc_length = 12;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_isrc_string(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, char* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ char c;
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: {
+ r = miniflac_cuesheet_read_track_number(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: {
+ while(cuesheet->pos < 12) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ c = (char)miniflac_bitreader_read(br,8);
+ if(output != NULL && cuesheet->pos < length) {
+ output[cuesheet->pos] = c;
+ }
+ cuesheet->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = cuesheet->pos < length ? cuesheet->pos : length;
+ }
+ cuesheet->pos = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKTYPE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_audio_flag(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_audio_flag) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t f = 0;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: {
+ r = miniflac_cuesheet_read_track_isrc_string(cuesheet,br,NULL,0,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKTYPE: {
+ if(miniflac_bitreader_fill_nocrc(br,1)) return MINIFLAC_CONTINUE;
+ f = (uint8_t)miniflac_bitreader_read(br,1);
+ if(track_audio_flag != NULL) {
+ *track_audio_flag = f;
+ }
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKPREEMPH;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_preemph_flag(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_preemph_flag) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t f = 0;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKTYPE: {
+ r = miniflac_cuesheet_read_track_audio_flag(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPREEMPH: {
+ if(miniflac_bitreader_fill_nocrc(br,1)) return MINIFLAC_CONTINUE;
+ f = (uint8_t)miniflac_bitreader_read(br,1);
+ if(track_preemph_flag != NULL) {
+ *track_preemph_flag = f;
+ }
+ miniflac_bitreader_discard(br,6);
+ cuesheet->pos = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_TRACK_RESERVE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_track_indexpoints(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* track_indexpoints) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_INDEX_OFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_NUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_RESERVE: {
+ /* finish reading indexpoints */
+ while(cuesheet->state != MINIFLAC_CUESHEET_TRACKOFFSET) {
+ r = miniflac_cuesheet_read_index_point_offset(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) break;
+ }
+ if(r != MINIFLAC_METADATA_END) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKTYPE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPREEMPH: {
+ r = miniflac_cuesheet_read_track_preemph_flag(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACK_RESERVE: {
+ while(cuesheet->pos < 13) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,8);
+ cuesheet->pos++;
+ }
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKPOINTS;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPOINTS: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ cuesheet->points = (uint8_t)miniflac_bitreader_read(br,8);
+ if(track_indexpoints != NULL) {
+ *track_indexpoints = cuesheet->points;
+ }
+ cuesheet->point = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_INDEX_OFFSET;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_index_point_offset(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint64_t* index_point_offset) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint64_t t = 0;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_INDEX_NUMBER: {
+ r = miniflac_cuesheet_read_index_point_number(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_RESERVE: {
+ while(cuesheet->pos < 3) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,8);
+ cuesheet->pos++;
+ }
+ cuesheet->point++;
+ cuesheet->state = MINIFLAC_CUESHEET_INDEX_OFFSET;
+ goto case_miniflac_cuesheet_index_offset;
+ }
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKTYPE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPREEMPH: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACK_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPOINTS: {
+ r = miniflac_cuesheet_read_track_indexpoints(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_OFFSET: {
+ case_miniflac_cuesheet_index_offset:
+ if(cuesheet->point == cuesheet->points) {
+ /* done reading track */
+ cuesheet->track++;
+ cuesheet->state = MINIFLAC_CUESHEET_TRACKOFFSET;
+ return MINIFLAC_METADATA_END;
+ }
+ if(miniflac_bitreader_fill_nocrc(br,64)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,64);
+ if(index_point_offset != NULL) {
+ *index_point_offset = t;
+ }
+ cuesheet->state = MINIFLAC_CUESHEET_INDEX_NUMBER;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_cuesheet_read_index_point_number(miniflac_cuesheet_t* cuesheet, miniflac_bitreader_t* br, uint8_t* index_point_number) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t t = 0;
+
+ switch(cuesheet->state) {
+ case MINIFLAC_CUESHEET_CATALOG: /* fall-through */
+ case MINIFLAC_CUESHEET_LEADIN: /* fall-through */
+ case MINIFLAC_CUESHEET_CDFLAG: /* fall-through */
+ case MINIFLAC_CUESHEET_SHEET_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKS: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKOFFSET: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKNUMBER: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKISRC: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKTYPE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPREEMPH: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACK_RESERVE: /* fall-through */
+ case MINIFLAC_CUESHEET_TRACKPOINTS:
+ case MINIFLAC_CUESHEET_INDEX_OFFSET: {
+ r = miniflac_cuesheet_read_index_point_offset(cuesheet,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_CUESHEET_INDEX_NUMBER: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,8);
+ if(index_point_number != NULL) {
+ *index_point_number = t;
+ }
+ cuesheet->pos = 0;
+ cuesheet->state = MINIFLAC_CUESHEET_INDEX_RESERVE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_seektable_init(miniflac_seektable_t* seektable) {
+ seektable->state = MINIFLAC_SEEKTABLE_SAMPLE_NUMBER;
+ seektable->len = 0;
+ seektable->pos = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_seekpoints(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint32_t* seekpoints) {
+ (void)br;
+
+ switch(seektable->state) {
+ case MINIFLAC_SEEKTABLE_SAMPLE_NUMBER: {
+ if(seekpoints != NULL) {
+ *seekpoints = seektable->len;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_sample_number(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint64_t* sample_number) {
+ uint64_t t = 0;
+
+ switch(seektable->state) {
+ case MINIFLAC_SEEKTABLE_SAMPLE_NUMBER: {
+ if(seektable->pos == seektable->len) return MINIFLAC_METADATA_END;
+ if(miniflac_bitreader_fill_nocrc(br,64)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,64);
+ if(sample_number != NULL) {
+ *sample_number = t;
+ }
+ seektable->state = MINIFLAC_SEEKTABLE_SAMPLE_OFFSET;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_sample_offset(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint64_t* sample_offset) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint64_t t = 0;
+
+ switch(seektable->state) {
+ case MINIFLAC_SEEKTABLE_SAMPLE_NUMBER: {
+ r = miniflac_seektable_read_sample_number(seektable,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_SEEKTABLE_SAMPLE_OFFSET: {
+ if(miniflac_bitreader_fill_nocrc(br,64)) return MINIFLAC_CONTINUE;
+ t = miniflac_bitreader_read(br,64);
+ if(sample_offset != NULL) {
+ *sample_offset = t;
+ }
+ seektable->state = MINIFLAC_SEEKTABLE_SAMPLES;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_seektable_read_samples(miniflac_seektable_t* seektable, miniflac_bitreader_t* br, uint16_t* samples) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint16_t t = 0;
+
+ switch(seektable->state) {
+ case MINIFLAC_SEEKTABLE_SAMPLE_NUMBER: /* fall-through */
+ case MINIFLAC_SEEKTABLE_SAMPLE_OFFSET: {
+ r = miniflac_seektable_read_sample_offset(seektable,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_SEEKTABLE_SAMPLES: {
+ if(miniflac_bitreader_fill_nocrc(br,16)) return MINIFLAC_CONTINUE;
+ t = (uint16_t)miniflac_bitreader_read(br,16);
+ if(samples != NULL) {
+ *samples = t;
+ }
+ seektable->pos++;
+ seektable->state = MINIFLAC_SEEKTABLE_SAMPLE_NUMBER;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_application_init(miniflac_application_t* application) {
+ application->state = MINIFLAC_APPLICATION_ID;
+ application->len = 0;
+ application->pos = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_application_read_id(miniflac_application_t* application, miniflac_bitreader_t* br, uint32_t* id) {
+ uint32_t t;
+ switch(application->state) {
+ case MINIFLAC_APPLICATION_ID: {
+ if(miniflac_bitreader_fill_nocrc(br,32)) return MINIFLAC_CONTINUE;
+ t = (uint32_t)miniflac_bitreader_read(br,32);
+ if(id != NULL) {
+ *id = t;
+ }
+ application->state = MINIFLAC_APPLICATION_DATA;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_application_read_length(miniflac_application_t* application, miniflac_bitreader_t* br, uint32_t* length) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(application->state) {
+ case MINIFLAC_APPLICATION_ID: {
+ r = miniflac_application_read_id(application,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_APPLICATION_DATA: {
+ if(length != NULL) {
+ *length = application->len;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_application_read_data(miniflac_application_t* application, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t d;
+ switch(application->state) {
+ case MINIFLAC_APPLICATION_ID: {
+ r = miniflac_application_read_id(application,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_APPLICATION_DATA: {
+ while(application->pos < application->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ d = (uint8_t) miniflac_bitreader_read(br,8);
+ if(output != NULL && application->pos < length) {
+ output[application->pos] = d;
+ }
+ application->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = application->len <= length ? application->len : length;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_padding_init(miniflac_padding_t* padding) {
+ padding->len = 0;
+ padding->pos = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_padding_read_length(miniflac_padding_t* padding, miniflac_bitreader_t* br, uint32_t* length) {
+ (void)padding;
+ (void)br;
+ if(length != NULL) {
+ *length = padding->len;
+ }
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_padding_read_data(miniflac_padding_t* padding, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen) {
+ uint8_t d;
+ while(padding->pos < padding->len) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ d = (uint8_t) miniflac_bitreader_read(br,8);
+ if(output != NULL && padding->pos < length) {
+ output[padding->pos] = d;
+ }
+ padding->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = padding->len <= length ? padding->len : length;
+ }
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_metadata_init(miniflac_metadata_t* metadata) {
+ metadata->state = MINIFLAC_METADATA_HEADER;
+ metadata->pos = 0;
+ miniflac_metadata_header_init(&metadata->header);
+ miniflac_streaminfo_init(&metadata->streaminfo);
+ miniflac_vorbis_comment_init(&metadata->vorbis_comment);
+ miniflac_picture_init(&metadata->picture);
+ miniflac_seektable_init(&metadata->seektable);
+ miniflac_application_init(&metadata->application);
+ miniflac_cuesheet_init(&metadata->cuesheet);
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_metadata_sync(miniflac_metadata_t* metadata, miniflac_bitreader_t* br) {
+ MINIFLAC_RESULT r;
+ assert(metadata->state == MINIFLAC_METADATA_HEADER);
+ r = miniflac_metadata_header_decode(&metadata->header,br);
+ if(r != MINIFLAC_OK) return r;
+
+ switch(metadata->header.type) {
+ case MINIFLAC_METADATA_STREAMINFO: {
+ miniflac_streaminfo_init(&metadata->streaminfo);
+ break;
+ }
+ case MINIFLAC_METADATA_VORBIS_COMMENT: {
+ miniflac_vorbis_comment_init(&metadata->vorbis_comment);
+ break;
+ }
+ case MINIFLAC_METADATA_PICTURE: {
+ miniflac_picture_init(&metadata->picture);
+ break;
+ }
+ case MINIFLAC_METADATA_CUESHEET: {
+ miniflac_cuesheet_init(&metadata->cuesheet);
+ break;
+ }
+ case MINIFLAC_METADATA_SEEKTABLE: {
+ miniflac_seektable_init(&metadata->seektable);
+ metadata->seektable.len = metadata->header.length / 18;
+ break;
+ }
+ case MINIFLAC_METADATA_APPLICATION: {
+ miniflac_application_init(&metadata->application);
+ metadata->application.len = metadata->header.length - 4;
+ break;
+ }
+ case MINIFLAC_METADATA_PADDING: {
+ miniflac_padding_init(&metadata->padding);
+ metadata->padding.len = metadata->header.length;
+ break;
+ }
+ default: break;
+ }
+
+ metadata->state = MINIFLAC_METADATA_DATA;
+ metadata->pos = 0;
+ return MINIFLAC_OK;
+}
+
+static
+MINIFLAC_RESULT
+miniflac_metadata_skip(miniflac_metadata_t* metadata, miniflac_bitreader_t* br) {
+ while(metadata->pos < metadata->header.length) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ miniflac_bitreader_discard(br,8);
+ metadata->pos++;
+ }
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_metadata_decode(miniflac_metadata_t* metadata, miniflac_bitreader_t* br) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(metadata->state) {
+ case MINIFLAC_METADATA_HEADER: {
+ r = miniflac_metadata_sync(metadata,br);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_METADATA_DATA: {
+ switch(metadata->header.type) {
+ case MINIFLAC_METADATA_STREAMINFO: {
+ r = miniflac_streaminfo_read_md5_data(&metadata->streaminfo,br,NULL,0,NULL);
+ break;
+ }
+ case MINIFLAC_METADATA_VORBIS_COMMENT: {
+ do {
+ r = miniflac_vorbis_comment_read_length(&metadata->vorbis_comment,br,NULL);
+ } while(r == MINIFLAC_OK);
+ break;
+ }
+ case MINIFLAC_METADATA_PICTURE: {
+ r = miniflac_picture_read_data(&metadata->picture,br,NULL,0,NULL);
+ break;
+ }
+ case MINIFLAC_METADATA_CUESHEET: {
+ do {
+ r = miniflac_cuesheet_read_track_indexpoints(&metadata->cuesheet,br,NULL);
+ } while(r == MINIFLAC_OK);
+ break;
+ }
+ case MINIFLAC_METADATA_SEEKTABLE: {
+ do {
+ r = miniflac_seektable_read_samples(&metadata->seektable,br,NULL);
+ } while(r == MINIFLAC_OK);
+ break;
+ }
+ case MINIFLAC_METADATA_APPLICATION: {
+ r = miniflac_application_read_data(&metadata->application,br,NULL,0,NULL);
+ break;
+ }
+ case MINIFLAC_METADATA_PADDING: {
+ r = miniflac_padding_read_data(&metadata->padding,br,NULL,0,NULL);
+ break;
+ }
+ default: {
+ r = miniflac_metadata_skip(metadata,br);
+ }
+ }
+ }
+ /* fall-through */
+ default: break;
+ }
+
+ if(r == MINIFLAC_METADATA_END) {
+ r = MINIFLAC_OK;
+ }
+
+ if(r != MINIFLAC_OK) return r;
+
+ assert(br->bits == 0);
+ br->crc8 = 0;
+ br->crc16 = 0;
+ metadata->state = MINIFLAC_METADATA_HEADER;
+ metadata->pos = 0;
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_metadata_header_init(miniflac_metadata_header_t* header) {
+ header->state = MINIFLAC_METADATA_LAST_FLAG;
+ header->type = MINIFLAC_METADATA_UNKNOWN;
+ header->is_last = 0;
+ header->type_raw = 0;
+ header->length = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_metadata_header_decode(miniflac_metadata_header_t* header, miniflac_bitreader_t* br) {
+ switch(header->state) {
+ case MINIFLAC_METADATA_LAST_FLAG: {
+ if(miniflac_bitreader_fill(br,1)) return MINIFLAC_CONTINUE;
+ miniflac_metadata_header_init(header);
+ header->is_last = (uint8_t)miniflac_bitreader_read(br,1);
+ header->state = MINIFLAC_METADATA_BLOCK_TYPE;
+ }
+ /* fall-through */
+ case MINIFLAC_METADATA_BLOCK_TYPE: {
+ if(miniflac_bitreader_fill(br,7)) return MINIFLAC_CONTINUE;
+ header->type_raw = (uint8_t)miniflac_bitreader_read(br,7);
+ switch(header->type_raw) {
+ case 0: header->type = MINIFLAC_METADATA_STREAMINFO; break;
+ case 1: header->type = MINIFLAC_METADATA_PADDING; break;
+ case 2: header->type = MINIFLAC_METADATA_APPLICATION; break;
+ case 3: header->type = MINIFLAC_METADATA_SEEKTABLE; break;
+ case 4: header->type = MINIFLAC_METADATA_VORBIS_COMMENT; break;
+ case 5: header->type = MINIFLAC_METADATA_CUESHEET; break;
+ case 6: header->type = MINIFLAC_METADATA_PICTURE; break;
+ case 127: {
+ header->type = MINIFLAC_METADATA_INVALID;
+ miniflac_abort();
+ return MINIFLAC_METADATA_TYPE_INVALID;
+ }
+ default: {
+ header->type = MINIFLAC_METADATA_UNKNOWN;
+ miniflac_abort();
+ return MINIFLAC_METADATA_TYPE_RESERVED;
+ }
+ }
+ header->state = MINIFLAC_METADATA_LENGTH;
+ }
+ /* fall-through */
+ case MINIFLAC_METADATA_LENGTH: {
+ if(miniflac_bitreader_fill(br,24)) return MINIFLAC_CONTINUE;
+ header->length = (uint32_t) miniflac_bitreader_read(br,24);
+ header->state = MINIFLAC_METADATA_LAST_FLAG;
+ break;
+ }
+ default: break;
+ }
+ return MINIFLAC_OK;
+}
+
+static const uint8_t escape_codes[2] = {
+ 15,
+ 31,
+};
+
+MINIFLAC_PRIVATE
+void
+miniflac_residual_init(miniflac_residual_t* residual) {
+ residual->coding_method = 0;
+ residual->partition_order = 0;
+ residual->rice_parameter = 0;
+ residual->rice_size = 0;
+ residual->msb = 0;
+ residual->rice_parameter_size = 0;
+ residual->value = 0;
+ residual->partition = 0;
+ residual->partition_total = 0;
+ residual->residual = 0;
+ residual->residual_total = 0;
+ residual->state = MINIFLAC_RESIDUAL_CODING_METHOD;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_residual_decode(miniflac_residual_t* residual, miniflac_bitreader_t* br, uint32_t* pos, uint32_t block_size, uint8_t predictor_order, int32_t *output) {
+ uint64_t temp;
+ uint32_t temp_32;
+
+ switch(residual->state) {
+ case MINIFLAC_RESIDUAL_CODING_METHOD: {
+ if(miniflac_bitreader_fill(br,2)) return MINIFLAC_CONTINUE;
+ temp = miniflac_bitreader_read(br,2);
+ if(temp > 1) {
+ miniflac_abort();
+ return MINIFLAC_RESERVED_CODING_METHOD;
+ }
+ residual->coding_method = temp;
+ switch(residual->coding_method) {
+ case 0: {
+ residual->rice_parameter_size = 4;
+ break;
+ }
+ case 1: {
+ residual->rice_parameter_size = 5;
+ break;
+ }
+ }
+ residual->msb = 0;
+ residual->state = MINIFLAC_RESIDUAL_PARTITION_ORDER;
+ }
+ /* fall-through */
+ case MINIFLAC_RESIDUAL_PARTITION_ORDER: {
+ if(miniflac_bitreader_fill(br,4)) return MINIFLAC_CONTINUE;
+ residual->partition_order = miniflac_bitreader_read(br,4);
+ residual->partition_total = 1 << residual->partition_order;
+ residual->state = MINIFLAC_RESIDUAL_RICE_PARAMETER;
+ }
+ /* fall-through */
+ case MINIFLAC_RESIDUAL_RICE_PARAMETER: {
+ miniflac_residual_rice_parameter:
+ if(miniflac_bitreader_fill(br,residual->rice_parameter_size)) return MINIFLAC_CONTINUE;
+ residual->rice_parameter = miniflac_bitreader_read(br,residual->rice_parameter_size);
+
+ residual->residual = 0;
+ residual->residual_total = block_size >> residual->partition_order;
+ if(residual->partition == 0) {
+ residual->residual_total -= predictor_order;
+ }
+
+ if(residual->rice_parameter == escape_codes[residual->coding_method]) {
+ residual->state = MINIFLAC_RESIDUAL_RICE_SIZE;
+ goto miniflac_residual_rice_size;
+ }
+ residual->state = MINIFLAC_RESIDUAL_MSB;
+ goto miniflac_residual_msb;
+ }
+ /* fall-through */
+ case MINIFLAC_RESIDUAL_RICE_SIZE: {
+ miniflac_residual_rice_size:
+ if(miniflac_bitreader_fill(br,5)) return MINIFLAC_CONTINUE;
+ residual->rice_size = miniflac_bitreader_read(br,5);
+ residual->state = MINIFLAC_RESIDUAL_RICE_VALUE;
+ }
+ /* fall-through */
+ case MINIFLAC_RESIDUAL_RICE_VALUE: {
+ miniflac_residual_rice_value:
+ if(miniflac_bitreader_fill(br,residual->rice_size)) return MINIFLAC_CONTINUE;
+ residual->value = miniflac_bitreader_read_signed(br,residual->rice_size);
+ if(output != NULL) {
+ output[*pos] = residual->value;
+ }
+ *pos += 1;
+ residual->residual++;
+ if(residual->residual < residual->residual_total) {
+ residual->state = MINIFLAC_RESIDUAL_RICE_VALUE;
+ goto miniflac_residual_rice_value;
+ }
+ goto miniflac_residual_nextpart;
+ }
+ /* fall-through */
+ case MINIFLAC_RESIDUAL_MSB: {
+ miniflac_residual_msb:
+ while(!miniflac_bitreader_fill(br,1)) {
+ if(miniflac_bitreader_read(br,1)) {
+ residual->state = MINIFLAC_RESIDUAL_LSB;
+ goto miniflac_residual_lsb;
+ }
+ residual->msb++;
+ }
+ return MINIFLAC_CONTINUE;
+ }
+ case MINIFLAC_RESIDUAL_LSB: {
+ miniflac_residual_lsb:
+ if(miniflac_bitreader_fill(br,residual->rice_parameter)) return MINIFLAC_CONTINUE;
+ temp_32 = (residual->msb << residual->rice_parameter) | ((uint32_t)miniflac_bitreader_read(br,residual->rice_parameter));
+ residual->value = (temp_32 >> 1) ^ -(temp_32 & 1);
+
+ if(output != NULL) {
+ output[*pos] = residual->value;
+ }
+ *pos += 1;
+
+ residual->msb = 0;
+ residual->residual++;
+ if(residual->residual < residual->residual_total) {
+ residual->state = MINIFLAC_RESIDUAL_MSB;
+ goto miniflac_residual_msb;
+ }
+
+ miniflac_residual_nextpart:
+ residual->residual = 0;
+ residual->partition++;
+ if(residual->partition < residual->partition_total) {
+ residual->state = MINIFLAC_RESIDUAL_RICE_PARAMETER;
+ goto miniflac_residual_rice_parameter;
+ }
+ break;
+ }
+ default: break;
+ }
+
+ miniflac_residual_init(residual);
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_streaminfo_init(miniflac_streaminfo_t* streaminfo) {
+ streaminfo->state = MINIFLAC_STREAMINFO_MINBLOCKSIZE;
+ streaminfo->pos = 0;
+ streaminfo->sample_rate = 0;
+ streaminfo->bps = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_min_block_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint16_t* min_block_size) {
+ uint16_t t;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: {
+ if(miniflac_bitreader_fill_nocrc(br,16)) return MINIFLAC_CONTINUE;
+ t = (uint16_t) miniflac_bitreader_read(br,16);
+ if(min_block_size != NULL) {
+ *min_block_size = t;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_MAXBLOCKSIZE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_max_block_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint16_t* max_block_size) {
+ uint16_t t;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: {
+ r = miniflac_streaminfo_read_min_block_size(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: {
+ if(miniflac_bitreader_fill_nocrc(br,16)) return MINIFLAC_CONTINUE;
+ t = (uint16_t) miniflac_bitreader_read(br,16);
+ if(max_block_size != NULL) {
+ *max_block_size = t;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_MINFRAMESIZE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_min_frame_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* min_frame_size) {
+ uint32_t t;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: {
+ r = miniflac_streaminfo_read_max_block_size(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: {
+ if(miniflac_bitreader_fill_nocrc(br,24)) return MINIFLAC_CONTINUE;
+ t = (uint32_t) miniflac_bitreader_read(br,24);
+ if(min_frame_size != NULL) {
+ *min_frame_size = t;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_MAXFRAMESIZE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_max_frame_size(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* max_frame_size) {
+ uint32_t t;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: {
+ r = miniflac_streaminfo_read_min_frame_size(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: {
+ if(miniflac_bitreader_fill_nocrc(br,24)) return MINIFLAC_CONTINUE;
+ t = (uint32_t) miniflac_bitreader_read(br,24);
+ if(max_frame_size != NULL) {
+ *max_frame_size = t;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_SAMPLERATE;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_sample_rate(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* sample_rate) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: {
+ r = miniflac_streaminfo_read_max_frame_size(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_SAMPLERATE: {
+ if(miniflac_bitreader_fill_nocrc(br,20)) return MINIFLAC_CONTINUE;
+ streaminfo->sample_rate = (uint32_t) miniflac_bitreader_read(br,20);
+ if(sample_rate != NULL) {
+ *sample_rate = streaminfo->sample_rate;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_CHANNELS;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_channels(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint8_t* channels) {
+ uint8_t t;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_SAMPLERATE: {
+ r = miniflac_streaminfo_read_sample_rate(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_CHANNELS: {
+ if(miniflac_bitreader_fill_nocrc(br,3)) return MINIFLAC_CONTINUE;
+ t = (uint8_t) miniflac_bitreader_read(br,3) + 1;
+ if(channels != NULL) {
+ *channels = t;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_BPS;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_bps(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint8_t* bps) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_SAMPLERATE: /* fall-through */
+ case MINIFLAC_STREAMINFO_CHANNELS: {
+ r = miniflac_streaminfo_read_channels(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_BPS: {
+ if(miniflac_bitreader_fill_nocrc(br,5)) return MINIFLAC_CONTINUE;
+ streaminfo->bps = (uint8_t) miniflac_bitreader_read(br,5) + 1;
+ if(bps != NULL) {
+ *bps = streaminfo->bps;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_TOTALSAMPLES;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_total_samples(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint64_t* total_samples) {
+ uint64_t t;
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_SAMPLERATE: /* fall-through */
+ case MINIFLAC_STREAMINFO_CHANNELS: /* fall-through */
+ case MINIFLAC_STREAMINFO_BPS: {
+ r = miniflac_streaminfo_read_bps(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_TOTALSAMPLES: {
+ if(miniflac_bitreader_fill_nocrc(br,36)) return MINIFLAC_CONTINUE;
+ t = (uint64_t) miniflac_bitreader_read(br,36);
+ if(total_samples != NULL) {
+ *total_samples = t;
+ }
+ streaminfo->state = MINIFLAC_STREAMINFO_MD5;
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_md5_length(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint32_t* md5_len) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_SAMPLERATE: /* fall-through */
+ case MINIFLAC_STREAMINFO_CHANNELS: /* fall-through */
+ case MINIFLAC_STREAMINFO_BPS: /* fall-through */
+ case MINIFLAC_STREAMINFO_TOTALSAMPLES: {
+ r = miniflac_streaminfo_read_total_samples(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ default: break;
+ }
+ if(md5_len != NULL) {
+ *md5_len = 16;
+ }
+ return MINIFLAC_OK;
+}
+
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streaminfo_read_md5_data(miniflac_streaminfo_t* streaminfo, miniflac_bitreader_t* br, uint8_t* output, uint32_t length, uint32_t* outlen) {
+ MINIFLAC_RESULT r = MINIFLAC_ERROR;
+ uint8_t t;
+ switch(streaminfo->state) {
+ case MINIFLAC_STREAMINFO_MINBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXBLOCKSIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MINFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_MAXFRAMESIZE: /* fall-through */
+ case MINIFLAC_STREAMINFO_SAMPLERATE: /* fall-through */
+ case MINIFLAC_STREAMINFO_CHANNELS: /* fall-through */
+ case MINIFLAC_STREAMINFO_BPS: /* fall-through */
+ case MINIFLAC_STREAMINFO_TOTALSAMPLES: {
+ r = miniflac_streaminfo_read_total_samples(streaminfo,br,NULL);
+ if(r != MINIFLAC_OK) return r;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMINFO_MD5: {
+ if(streaminfo->pos == 16) return MINIFLAC_METADATA_END;
+ while(streaminfo->pos < 16) {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = (uint8_t)miniflac_bitreader_read(br,8);
+ if(output != NULL && streaminfo->pos < length) {
+ output[streaminfo->pos] = t;
+ }
+ streaminfo->pos++;
+ }
+ if(outlen != NULL) {
+ *outlen = 16 < length ? 16 : length;
+ }
+ return MINIFLAC_OK;
+ }
+ default: break;
+ }
+
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_streammarker_init(miniflac_streammarker_t* streammarker) {
+ streammarker->state = MINIFLAC_STREAMMARKER_F;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_streammarker_decode(miniflac_streammarker_t* streammarker, miniflac_bitreader_t* br) {
+ char t;
+ switch(streammarker->state) {
+ case MINIFLAC_STREAMMARKER_F: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = (char)miniflac_bitreader_read(br,8);
+ if(t != 'f') {
+ miniflac_abort();
+ return MINIFLAC_STREAMMARKER_INVALID;
+ }
+ streammarker->state = MINIFLAC_STREAMMARKER_L;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMMARKER_L: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = (char)miniflac_bitreader_read(br,8);
+ if(t != 'L') {
+ miniflac_abort();
+ return MINIFLAC_STREAMMARKER_INVALID;
+ }
+ streammarker->state = MINIFLAC_STREAMMARKER_A;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMMARKER_A: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = (char)miniflac_bitreader_read(br,8);
+ if(t != 'a') {
+ miniflac_abort();
+ return MINIFLAC_STREAMMARKER_INVALID;
+ }
+ streammarker->state = MINIFLAC_STREAMMARKER_C;
+ }
+ /* fall-through */
+ case MINIFLAC_STREAMMARKER_C: {
+ if(miniflac_bitreader_fill_nocrc(br,8)) return MINIFLAC_CONTINUE;
+ t = (char)miniflac_bitreader_read(br,8);
+ if(t != 'C') {
+ miniflac_abort();
+ return MINIFLAC_STREAMMARKER_INVALID;
+ }
+ break;
+ }
+ default: {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ }
+
+ miniflac_streammarker_init(streammarker);
+
+ assert(br->bits == 0);
+ br->crc8 = 0;
+ br->crc16 = 0;
+
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_init(miniflac_subframe_t* subframe) {
+ subframe->bps = 0;
+ subframe->state = MINIFLAC_SUBFRAME_HEADER;
+ miniflac_subframe_header_init(&subframe->header);
+ miniflac_subframe_constant_init(&subframe->constant);
+ miniflac_subframe_verbatim_init(&subframe->verbatim);
+ miniflac_subframe_fixed_init(&subframe->fixed);
+ miniflac_subframe_lpc_init(&subframe->lpc);
+ miniflac_residual_init(&subframe->residual);
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_decode(miniflac_subframe_t* subframe, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps) {
+ MINIFLAC_RESULT r;
+ uint32_t i;
+
+ switch(subframe->state) {
+ case MINIFLAC_SUBFRAME_HEADER: {
+ r = miniflac_subframe_header_decode(&subframe->header,br);
+ if(r != MINIFLAC_OK) return r;
+
+ subframe->bps = bps - subframe->header.wasted_bits;
+
+ switch(subframe->header.type) {
+ case MINIFLAC_SUBFRAME_TYPE_CONSTANT: {
+ miniflac_subframe_constant_init(&subframe->constant);
+ subframe->state = MINIFLAC_SUBFRAME_CONSTANT;
+ goto miniflac_subframe_constant;
+ }
+ case MINIFLAC_SUBFRAME_TYPE_VERBATIM: {
+ miniflac_subframe_verbatim_init(&subframe->verbatim);
+ subframe->state = MINIFLAC_SUBFRAME_VERBATIM;
+ goto miniflac_subframe_verbatim;
+ }
+ case MINIFLAC_SUBFRAME_TYPE_FIXED: {
+ miniflac_residual_init(&subframe->residual);
+ miniflac_subframe_fixed_init(&subframe->fixed);
+ subframe->state = MINIFLAC_SUBFRAME_FIXED;
+ goto miniflac_subframe_fixed;
+ }
+ case MINIFLAC_SUBFRAME_TYPE_LPC: {
+ miniflac_residual_init(&subframe->residual);
+ miniflac_subframe_lpc_init(&subframe->lpc);
+ subframe->state = MINIFLAC_SUBFRAME_LPC;
+ goto miniflac_subframe_lpc;
+ }
+ default: {
+ miniflac_abort();
+ return MINIFLAC_ERROR;
+ }
+ }
+ break;
+ }
+
+ case MINIFLAC_SUBFRAME_CONSTANT: {
+ miniflac_subframe_constant:
+ r = miniflac_subframe_constant_decode(&subframe->constant,br,output,block_size,subframe->bps);
+ if(r != MINIFLAC_OK) return r;
+ break;
+ }
+ case MINIFLAC_SUBFRAME_VERBATIM: {
+ miniflac_subframe_verbatim:
+ r = miniflac_subframe_verbatim_decode(&subframe->verbatim,br,output,block_size,subframe->bps);
+ if(r != MINIFLAC_OK) return r;
+ break;
+ }
+ case MINIFLAC_SUBFRAME_FIXED: {
+ miniflac_subframe_fixed:
+ r = miniflac_subframe_fixed_decode(&subframe->fixed,br,output,block_size,subframe->bps,&subframe->residual,subframe->header.order);
+ if(r != MINIFLAC_OK) return r;
+ break;
+ }
+ case MINIFLAC_SUBFRAME_LPC: {
+ miniflac_subframe_lpc:
+ r = miniflac_subframe_lpc_decode(&subframe->lpc,br,output,block_size,subframe->bps,&subframe->residual,subframe->header.order);
+ if(r != MINIFLAC_OK) return r;
+ break;
+ }
+ default: break;
+ }
+
+ if(output != NULL && subframe->header.wasted_bits > 0) {
+ for(i=0;iheader.wasted_bits;
+ }
+ }
+
+ miniflac_subframe_init(subframe);
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_constant_init(miniflac_subframe_constant_t* c) {
+ c->state = MINIFLAC_SUBFRAME_CONSTANT_DECODE;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_constant_decode(miniflac_subframe_constant_t* c, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps) {
+ int32_t sample;
+ uint32_t i;
+ (void)c;
+
+ if(miniflac_bitreader_fill(br,bps)) return MINIFLAC_CONTINUE;
+ sample = (int32_t) miniflac_bitreader_read_signed(br,bps);
+
+ if(output != NULL) {
+ for(i=0;ipos = 0;
+ f->state = MINIFLAC_SUBFRAME_FIXED_DECODE;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_fixed_decode(miniflac_subframe_fixed_t* f, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps, miniflac_residual_t* residual, uint8_t predictor_order) {
+ int32_t sample;
+
+ int64_t sample1;
+ int64_t sample2;
+ int64_t sample3;
+ int64_t sample4;
+ int64_t current_residual;
+
+ MINIFLAC_RESULT r;
+ while(f->pos < predictor_order) {
+ if(miniflac_bitreader_fill(br,bps)) return MINIFLAC_CONTINUE;
+ sample = (int32_t) miniflac_bitreader_read_signed(br,bps);
+ if(output != NULL) {
+ output[f->pos] = sample;
+ }
+ f->pos++;
+ }
+ r = miniflac_residual_decode(residual,br,&f->pos,block_size,predictor_order,output);
+ if(r != MINIFLAC_OK) return r;
+
+ if(output != NULL) {
+ switch(predictor_order) {
+ case 0:
+#if 0
+ /* this is here for reference but not actually needed */
+ for(f->pos = predictor_order; f->pos < block_size; f->pos++) {
+ current_residual = output[f->pos];
+ output[f->pos] = (int32_t)current_residual;
+ }
+#endif
+ break;
+ case 1: {
+ for(f->pos = predictor_order; f->pos < block_size; f->pos++) {
+ current_residual = output[f->pos];
+ sample1 = output[f->pos-1];
+ output[f->pos] = (int32_t)(sample1 + current_residual);
+ }
+ break;
+ }
+ case 2: {
+ for(f->pos = predictor_order; f->pos < block_size; f->pos++) {
+ current_residual = output[f->pos];
+ sample1 = output[f->pos-1];
+ sample2 = output[f->pos-2];
+
+ sample1 *= 2;
+
+ output[f->pos] = (int32_t)(sample1 - sample2 + current_residual);
+ }
+ break;
+ }
+ case 3: {
+ for(f->pos = predictor_order; f->pos < block_size; f->pos++) {
+ current_residual = output[f->pos];
+ sample1 = output[f->pos-1];
+ sample2 = output[f->pos-2];
+ sample3 = output[f->pos-3];
+
+ sample1 *= 3;
+ sample2 *= 3;
+
+ output[f->pos] = (int32_t)(sample1 - sample2 + sample3 + current_residual);
+ }
+ break;
+ }
+ case 4: {
+ for(f->pos = predictor_order; f->pos < block_size; f->pos++) {
+ current_residual = output[f->pos];
+ sample1 = output[f->pos-1];
+ sample2 = output[f->pos-2];
+ sample3 = output[f->pos-3];
+ sample4 = output[f->pos-4];
+
+ sample1 *= 4;
+ sample2 *= 6;
+ sample3 *= 4;
+
+ output[f->pos] = (int32_t)(sample1 - sample2 + sample3 - sample4 + current_residual);
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+
+ return MINIFLAC_OK;
+
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_header_init(miniflac_subframe_header_t* subframeheader) {
+ subframeheader->state = MINIFLAC_SUBFRAME_HEADER_RESERVEBIT1;
+ subframeheader->type = MINIFLAC_SUBFRAME_TYPE_UNKNOWN;
+ subframeheader->order = 0;
+ subframeheader->wasted_bits = 0;
+ subframeheader->type_raw = 0;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_header_decode(miniflac_subframe_header_t* subframeheader, miniflac_bitreader_t* br) {
+ uint64_t t = 0;
+ switch(subframeheader->state) {
+ case MINIFLAC_SUBFRAME_HEADER_RESERVEBIT1: {
+ if(miniflac_bitreader_fill(br,1)) {
+ break;
+ }
+ t = miniflac_bitreader_read(br,1);
+ if(t != 0) {
+ miniflac_abort();
+ return MINIFLAC_SUBFRAME_RESERVED_BIT;
+ }
+ subframeheader->state = MINIFLAC_SUBFRAME_HEADER_KIND;
+ }
+ /* fall-through */
+ case MINIFLAC_SUBFRAME_HEADER_KIND: {
+ if(miniflac_bitreader_fill(br,6)) {
+ break;
+ }
+ t = (uint8_t)miniflac_bitreader_read(br,6);
+ subframeheader->type_raw = t;
+ if(t == 0) {
+ subframeheader->type = MINIFLAC_SUBFRAME_TYPE_CONSTANT;
+ } else if(t == 1) {
+ subframeheader->type = MINIFLAC_SUBFRAME_TYPE_VERBATIM;
+ } else if(t < 8) {
+ miniflac_abort();
+ return MINIFLAC_SUBFRAME_RESERVED_TYPE;
+ } else if(t < 13) {
+ subframeheader->type = MINIFLAC_SUBFRAME_TYPE_FIXED;
+ subframeheader->order = t - 8;
+ } else if(t < 32) {
+ miniflac_abort();
+ return MINIFLAC_SUBFRAME_RESERVED_TYPE;
+ } else {
+ subframeheader->type = MINIFLAC_SUBFRAME_TYPE_LPC;
+ subframeheader->order = t - 31;
+ }
+ subframeheader->state = MINIFLAC_SUBFRAME_HEADER_WASTED_BITS;
+ }
+ /* fall-through */
+ case MINIFLAC_SUBFRAME_HEADER_WASTED_BITS: {
+ if(miniflac_bitreader_fill(br,1)) {
+ break;
+ }
+ subframeheader->wasted_bits = 0;
+
+ t = miniflac_bitreader_read(br,1);
+ if(t == 0) { /* no wasted bits, we're done */
+ subframeheader->state = MINIFLAC_SUBFRAME_HEADER_RESERVEBIT1;
+ return MINIFLAC_OK;
+ }
+ subframeheader->state = MINIFLAC_SUBFRAME_HEADER_UNARY;
+ }
+ /* fall-through */
+ case MINIFLAC_SUBFRAME_HEADER_UNARY: {
+ while(!miniflac_bitreader_fill(br,1)) {
+ subframeheader->wasted_bits++;
+ t = miniflac_bitreader_read(br,1);
+
+ if(t == 1) {
+ /* no more wasted bits, we're done */
+ subframeheader->state = MINIFLAC_SUBFRAME_HEADER_RESERVEBIT1;
+ return MINIFLAC_OK;
+ }
+ }
+ }
+ /* fall-through */
+ default: break;
+ }
+ return MINIFLAC_CONTINUE;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_lpc_init(miniflac_subframe_lpc_t* l) {
+ unsigned int i;
+ l->pos = 0;
+ l->precision = 0;
+ l->shift = 0;
+ l->coeff = 0;
+ for(i = 0; i < 32; i++) {
+ l->coefficients[i] = 0;
+ }
+ l->state = MINIFLAC_SUBFRAME_LPC_PRECISION;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_lpc_decode(miniflac_subframe_lpc_t* l, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps, miniflac_residual_t* residual, uint8_t predictor_order) {
+ int32_t sample;
+ int64_t temp;
+ int64_t prediction;
+ uint32_t i,j;
+ MINIFLAC_RESULT r;
+
+ while(l->pos < predictor_order) {
+ if(miniflac_bitreader_fill(br,bps)) return MINIFLAC_CONTINUE;
+ sample = (int32_t) miniflac_bitreader_read_signed(br,bps);
+ if(output != NULL) {
+ output[l->pos] = sample;
+ }
+ l->pos++;
+ l->state = MINIFLAC_SUBFRAME_LPC_PRECISION;
+ }
+
+ if(l->state == MINIFLAC_SUBFRAME_LPC_PRECISION) {
+ if(miniflac_bitreader_fill(br,4)) return MINIFLAC_CONTINUE;
+ l->precision = miniflac_bitreader_read(br,4) + 1;
+ l->state = MINIFLAC_SUBFRAME_LPC_SHIFT;
+ }
+
+ if(l->state == MINIFLAC_SUBFRAME_LPC_SHIFT) {
+ if(miniflac_bitreader_fill(br,5)) return MINIFLAC_CONTINUE;
+ temp = miniflac_bitreader_read_signed(br,5);
+ if(temp < 0) temp = 0;
+ l->shift = temp;
+ l->state = MINIFLAC_SUBFRAME_LPC_COEFF;
+ }
+
+ if(l->state == MINIFLAC_SUBFRAME_LPC_COEFF) {
+ while(l->coeff < predictor_order) {
+ if(miniflac_bitreader_fill(br,l->precision)) return MINIFLAC_CONTINUE;
+ sample = (int32_t) miniflac_bitreader_read_signed(br,l->precision);
+ l->coefficients[l->coeff++] = sample;
+ }
+ }
+
+ r = miniflac_residual_decode(residual,br,&l->pos,block_size,predictor_order,output);
+ if(r != MINIFLAC_OK) return r;
+
+ if(output != NULL) {
+ for(i=predictor_order;icoefficients[j];
+ prediction += temp;
+ }
+ prediction >>= l->shift;
+ prediction += output[i];
+ output[i] = prediction;
+ }
+ }
+
+ return MINIFLAC_OK;
+}
+
+MINIFLAC_PRIVATE
+void
+miniflac_subframe_verbatim_init(miniflac_subframe_verbatim_t* c) {
+ c->pos = 0;
+ c->state = MINIFLAC_SUBFRAME_VERBATIM_DECODE;
+}
+
+MINIFLAC_PRIVATE
+MINIFLAC_RESULT
+miniflac_subframe_verbatim_decode(miniflac_subframe_verbatim_t* c, miniflac_bitreader_t* br, int32_t* output, uint32_t block_size, uint8_t bps) {
+ int32_t sample;
+
+ while(c->pos < block_size) {
+ if(miniflac_bitreader_fill(br,bps)) return MINIFLAC_CONTINUE;
+ sample = (int32_t) miniflac_bitreader_read_signed(br,bps);
+ if(output != NULL) {
+ output[c->pos] = sample;
+ }
+ c->pos++;
+ }
+
+ c->pos = 0;
+ return MINIFLAC_OK;
+
+}
+
+#endif
diff --git a/src/codecs/CMakeLists.txt b/src/codecs/CMakeLists.txt
index 748e1440..d42c7426 100644
--- a/src/codecs/CMakeLists.txt
+++ b/src/codecs/CMakeLists.txt
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
- SRCS "codec.cpp" "mad.cpp" "foxenflac.cpp" "opus.cpp" "vorbis.cpp"
+ SRCS "codec.cpp" "mad.cpp" "miniflac.cpp" "opus.cpp" "vorbis.cpp"
"source_buffer.cpp"
INCLUDE_DIRS "include"
- REQUIRES "result" "span" "libmad" "libfoxenflac" "tremor" "opusfile" "memory")
+ REQUIRES "result" "span" "libmad" "miniflac" "tremor" "opusfile" "memory")
target_compile_options("${COMPONENT_LIB}" PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/codecs/codec.cpp b/src/codecs/codec.cpp
index 3610dea8..d81d4b05 100644
--- a/src/codecs/codec.cpp
+++ b/src/codecs/codec.cpp
@@ -9,8 +9,8 @@
#include
#include
-#include "foxenflac.hpp"
#include "mad.hpp"
+#include "miniflac.hpp"
#include "opus.hpp"
#include "types.hpp"
#include "vorbis.hpp"
@@ -41,7 +41,7 @@ auto CreateCodecForType(StreamType type) -> std::optional {
case StreamType::kVorbis:
return new TremorVorbisDecoder();
case StreamType::kFlac:
- return new FoxenFlacDecoder();
+ return new MiniFlacDecoder();
case StreamType::kOpus:
return new XiphOpusDecoder();
default:
diff --git a/src/codecs/foxenflac.cpp b/src/codecs/foxenflac.cpp
deleted file mode 100644
index 1fd95cd1..00000000
--- a/src/codecs/foxenflac.cpp
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2023 jacqueline
- *
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-#include "foxenflac.hpp"
-#include
-#include
-
-#include
-
-#include "esp_log.h"
-#include "foxen/flac.h"
-#include "sample.hpp"
-
-namespace codecs {
-
-[[maybe_unused]] static const char kTag[] = "flac";
-
-FoxenFlacDecoder::FoxenFlacDecoder()
- : input_(),
- buffer_(),
- flac_(fx_flac_init(
- heap_caps_malloc(fx_flac_size(FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, 2),
- MALLOC_CAP_SPIRAM),
- FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ,
- 2)) {}
-
-FoxenFlacDecoder::~FoxenFlacDecoder() {
- free(flac_);
-}
-
-auto FoxenFlacDecoder::OpenStream(std::shared_ptr input)
- -> cpp::result {
- input_ = input;
-
- bool eof = false;
- fx_flac_state_t state;
- do {
- eof = buffer_.Refill(input_.get());
- buffer_.ConsumeBytes([&](cpp::span buf) -> size_t {
- uint32_t bytes_used = buf.size();
- state =
- fx_flac_process(flac_, reinterpret_cast(buf.data()),
- &bytes_used, NULL, NULL);
- return bytes_used;
- });
- } while (state != FLAC_END_OF_METADATA && !eof);
-
- if (state != FLAC_END_OF_METADATA) {
- if (state == FLAC_ERR) {
- return cpp::fail(Error::kMalformedData);
- } else {
- return cpp::fail(Error::kOutOfInput);
- }
- }
-
- int64_t channels = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_CHANNELS);
- int64_t fs = fx_flac_get_streaminfo(flac_, FLAC_KEY_SAMPLE_RATE);
- if (channels == FLAC_INVALID_METADATA_KEY ||
- fs == FLAC_INVALID_METADATA_KEY) {
- return cpp::fail(Error::kMalformedData);
- }
-
- OutputFormat format{
- .num_channels = static_cast(channels),
- .sample_rate_hz = static_cast(fs),
- };
-
- uint64_t num_samples = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_SAMPLES);
- if (num_samples > 0) {
- format.total_samples = num_samples * channels;
- }
-
- return format;
-}
-
-auto FoxenFlacDecoder::DecodeTo(cpp::span output)
- -> cpp::result {
- bool is_eof = buffer_.Refill(input_.get());
-
- cpp::span output32{reinterpret_cast(output.data()),
- output.size() / 2};
- uint32_t samples_written = output32.size();
-
- fx_flac_state_t state;
- buffer_.ConsumeBytes([&](cpp::span buf) -> size_t {
- uint32_t bytes_read = buf.size_bytes();
- state = fx_flac_process(flac_, reinterpret_cast(buf.data()),
- &bytes_read, output32.data(), &samples_written);
- return bytes_read;
- });
- if (state == FLAC_ERR) {
- return cpp::fail(Error::kMalformedData);
- }
-
- for (size_t i = 0; i < samples_written; i++) {
- output[i] = output32[i] >> 16;
- }
-
- return OutputInfo{.samples_written = samples_written,
- .is_stream_finished = samples_written == 0 && is_eof};
-}
-
-auto FoxenFlacDecoder::SeekTo(size_t target) -> cpp::result {
- return {};
-}
-
-} // namespace codecs
diff --git a/src/codecs/include/foxenflac.hpp b/src/codecs/include/miniflac.hpp
similarity index 66%
rename from src/codecs/include/foxenflac.hpp
rename to src/codecs/include/miniflac.hpp
index 7522d967..d57b08a3 100644
--- a/src/codecs/include/foxenflac.hpp
+++ b/src/codecs/include/miniflac.hpp
@@ -6,6 +6,7 @@
#pragma once
+#include
#include
#include
#include
@@ -13,7 +14,7 @@
#include
#include
-#include "foxen/flac.h"
+#include "miniflac.h"
#include "sample.hpp"
#include "source_buffer.hpp"
#include "span.hpp"
@@ -22,10 +23,10 @@
namespace codecs {
-class FoxenFlacDecoder : public ICodec {
+class MiniFlacDecoder : public ICodec {
public:
- FoxenFlacDecoder();
- ~FoxenFlacDecoder();
+ MiniFlacDecoder();
+ ~MiniFlacDecoder();
auto OpenStream(std::shared_ptr input)
-> cpp::result override;
@@ -35,14 +36,16 @@ class FoxenFlacDecoder : public ICodec {
auto SeekTo(std::size_t target_sample) -> cpp::result override;
- FoxenFlacDecoder(const FoxenFlacDecoder&) = delete;
- FoxenFlacDecoder& operator=(const FoxenFlacDecoder&) = delete;
+ MiniFlacDecoder(const MiniFlacDecoder&) = delete;
+ MiniFlacDecoder& operator=(const MiniFlacDecoder&) = delete;
private:
std::shared_ptr input_;
SourceBuffer buffer_;
- fx_flac_t* flac_;
+ std::unique_ptr flac_;
+ std::array samples_by_channel_;
+ std::optional current_sample_;
};
} // namespace codecs
diff --git a/src/codecs/miniflac.cpp b/src/codecs/miniflac.cpp
new file mode 100644
index 00000000..cc261f75
--- /dev/null
+++ b/src/codecs/miniflac.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2023 jacqueline
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "miniflac.hpp"
+#include
+#include
+
+#include
+
+#include "esp_heap_caps.h"
+#include "esp_log.h"
+#include "miniflac.h"
+#include "result.hpp"
+#include "sample.hpp"
+
+namespace codecs {
+
+[[maybe_unused]] static const char kTag[] = "flac";
+
+static constexpr size_t kMaxFrameSize = 4608;
+
+MiniFlacDecoder::MiniFlacDecoder()
+ : input_(),
+ buffer_(),
+ flac_(reinterpret_cast(
+ heap_caps_malloc(sizeof(miniflac_t),
+ MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))),
+ current_sample_() {
+ miniflac_init(flac_.get(), MINIFLAC_CONTAINER_UNKNOWN);
+ for (int i = 0; i < samples_by_channel_.size(); i++) {
+ // Full decoded frames too big to fit in internal ram :(
+ samples_by_channel_[i] = reinterpret_cast(
+ heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), MALLOC_CAP_SPIRAM));
+ }
+}
+
+MiniFlacDecoder::~MiniFlacDecoder() {
+ for (int i = 0; i < samples_by_channel_.size(); i++) {
+ heap_caps_free(samples_by_channel_[i]);
+ }
+}
+
+auto MiniFlacDecoder::OpenStream(std::shared_ptr input)
+ -> cpp::result {
+ input_ = input;
+
+ MINIFLAC_RESULT res;
+ auto read_until_result = [&](auto fn) {
+ while (true) {
+ bool eof = buffer_.Refill(input_.get());
+ buffer_.ConsumeBytes(fn);
+ if (res == MINIFLAC_CONTINUE && !eof) {
+ continue;
+ }
+ break;
+ }
+ };
+
+ uint32_t sample_rate = 0;
+
+ read_until_result([&](cpp::span buf) -> size_t {
+ uint32_t bytes_used = 0;
+ res = miniflac_streaminfo_sample_rate(
+ flac_.get(), reinterpret_cast(buf.data()),
+ buf.size_bytes(), &bytes_used, &sample_rate);
+ return bytes_used;
+ });
+
+ if (res != MINIFLAC_OK) {
+ return cpp::fail(Error::kMalformedData);
+ }
+
+ uint8_t channels = 0;
+
+ read_until_result([&](cpp::span buf) -> size_t {
+ uint32_t bytes_used = 0;
+ res = miniflac_streaminfo_channels(
+ flac_.get(), reinterpret_cast(buf.data()),
+ buf.size_bytes(), &bytes_used, &channels);
+ return bytes_used;
+ });
+
+ if (res != MINIFLAC_OK) {
+ return cpp::fail(Error::kMalformedData);
+ }
+
+ uint64_t total_samples = 0;
+
+ read_until_result([&](cpp::span buf) -> size_t {
+ uint32_t bytes_used = 0;
+ res = miniflac_streaminfo_total_samples(
+ flac_.get(), reinterpret_cast(buf.data()),
+ buf.size_bytes(), &bytes_used, &total_samples);
+ return bytes_used;
+ });
+
+ if (res != MINIFLAC_OK) {
+ return cpp::fail(Error::kMalformedData);
+ }
+
+ if (channels == 0 || channels > 2) {
+ return cpp::fail(Error::kMalformedData);
+ }
+
+ OutputFormat format{
+ .num_channels = static_cast(channels),
+ .sample_rate_hz = static_cast(sample_rate),
+ .total_samples = total_samples * channels,
+ };
+
+ return format;
+}
+
+auto MiniFlacDecoder::DecodeTo(cpp::span output)
+ -> cpp::result {
+ bool is_eof = false;
+
+ if (!current_sample_) {
+ MINIFLAC_RESULT res = MINIFLAC_CONTINUE;
+ while (res == MINIFLAC_CONTINUE && !is_eof) {
+ is_eof = buffer_.Refill(input_.get());
+ buffer_.ConsumeBytes([&](cpp::span buf) -> size_t {
+ // FIXME: We should do a miniflac_sync first, in order to check that
+ // our sample buffers have enough space for the next frame.
+ uint32_t bytes_read = 0;
+ res = miniflac_decode(
+ flac_.get(), reinterpret_cast(buf.data()),
+ buf.size_bytes(), &bytes_read, samples_by_channel_.data());
+ return bytes_read;
+ });
+ }
+
+ if (res == MINIFLAC_OK) {
+ current_sample_ = 0;
+ } else if (is_eof) {
+ return OutputInfo{
+ .samples_written = 0,
+ .is_stream_finished = true,
+ };
+ } else {
+ return cpp::fail(Error::kMalformedData);
+ }
+ }
+
+ size_t samples_written = 0;
+ if (current_sample_) {
+ const uint8_t shift = flac_->frame.header.bps - 16;
+
+ while (*current_sample_ < flac_->frame.header.block_size) {
+ if (samples_written + flac_->frame.header.channels >= output.size()) {
+ // We can't fit the next full PCM frame into the buffer.
+ return OutputInfo{.samples_written = samples_written,
+ .is_stream_finished = false};
+ }
+
+ for (int channel = 0; channel < flac_->frame.header.channels; channel++) {
+ output[samples_written++] = sample::FromSigned(
+ samples_by_channel_[channel][*current_sample_] >> shift, 16);
+ }
+ (*current_sample_)++;
+ }
+ }
+
+ current_sample_.reset();
+ return OutputInfo{.samples_written = samples_written,
+ .is_stream_finished = samples_written == 0 && is_eof};
+}
+
+auto MiniFlacDecoder::SeekTo(size_t target) -> cpp::result {
+ return {};
+}
+
+} // namespace codecs
diff --git a/src/database/track.cpp b/src/database/track.cpp
index acd479f1..58097cef 100644
--- a/src/database/track.cpp
+++ b/src/database/track.cpp
@@ -203,7 +203,7 @@ auto TrackTags::disc() const -> const std::optional& {
}
auto TrackTags::disc(const std::string_view s) -> void {
- disc_ = std::stoi({s.data(), s.size()});
+ disc_ = std::strtol(s.data(), nullptr, 10);
}
auto TrackTags::track() const -> const std::optional& {
@@ -211,7 +211,7 @@ auto TrackTags::track() const -> const std::optional& {
}
auto TrackTags::track(const std::string_view s) -> void {
- track_ = std::stoi({s.data(), s.size()});
+ track_ = std::strtol(s.data(), nullptr, 10);
}
auto TrackTags::albumOrder() const -> uint32_t {
diff --git a/tools/cmake/common.cmake b/tools/cmake/common.cmake
index 62e91837..545124b7 100644
--- a/tools/cmake/common.cmake
+++ b/tools/cmake/common.cmake
@@ -16,7 +16,6 @@ list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/esp-idf-lua")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/fatfs")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/komihash")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/libcppbor")
-list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/libfoxenflac")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/libmad")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/libtags")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/lua-linenoise")
@@ -24,6 +23,7 @@ list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/lua-term")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/luavgl")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/lvgl")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/millershuffle")
+list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/miniflac")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/ogg")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/opusfile")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{PROJ_PATH}/lib/result")