Path: blob/a-new-beginning/SharedDependencies/Sources/libchdr/flac.c
2 views
/* license:BSD-3-Clause1* copyright-holders:Aaron Giles2***************************************************************************34flac.c56FLAC compression wrappers78***************************************************************************/910#include <assert.h>11#include <string.h>12#include "flac.h"1314/***************************************************************************15* FLAC DECODER16***************************************************************************17*/1819static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);20FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes);21static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);22static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);23static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);24FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);25static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);2627/* getters (valid after reset) */28static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; }29static uint8_t channels(flac_decoder *decoder) { return decoder->channels; }30static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }31static uint32_t total_samples(flac_decoder *decoder) { return FLAC__stream_decoder_get_total_samples(decoder->decoder); }32static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); }33static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); }3435/*-------------------------------------------------36* flac_decoder - constructor37*-------------------------------------------------38*/3940void flac_decoder_init(flac_decoder *decoder)41{42decoder->decoder = FLAC__stream_decoder_new();43decoder->sample_rate = 0;44decoder->channels = 0;45decoder->bits_per_sample = 0;46decoder->compressed_offset = 0;47decoder->compressed_start = NULL;48decoder->compressed_length = 0;49decoder->compressed2_start = NULL;50decoder->compressed2_length = 0;51decoder->uncompressed_offset = 0;52decoder->uncompressed_length = 0;53decoder->uncompressed_swap = 0;54}5556/*-------------------------------------------------57* flac_decoder - destructor58*-------------------------------------------------59*/6061void flac_decoder_free(flac_decoder* decoder)62{63if ((decoder != NULL) && (decoder->decoder != NULL))64FLAC__stream_decoder_delete(decoder->decoder);65}6667/*-------------------------------------------------68* reset - reset state with the original69* parameters70*-------------------------------------------------71*/7273static int flac_decoder_internal_reset(flac_decoder* decoder)74{75decoder->compressed_offset = 0;76if (FLAC__stream_decoder_init_stream(decoder->decoder,77&flac_decoder_read_callback_static,78NULL,79&flac_decoder_tell_callback_static,80NULL,81NULL,82&flac_decoder_write_callback_static,83&flac_decoder_metadata_callback_static,84&flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK)85return 0;86return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder);87}8889/*-------------------------------------------------90* reset - reset state with new memory parameters91* and a custom-generated header92*-------------------------------------------------93*/9495int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)96{97/* modify the template header with our parameters */98static const uint8_t s_header_template[0x2a] =99{1000x66, 0x4C, 0x61, 0x43, /* +00: 'fLaC' stream header */1010x80, /* +04: metadata block type 0 (STREAMINFO), */102/* flagged as last block */1030x00, 0x00, 0x22, /* +05: metadata block length = 0x22 */1040x00, 0x00, /* +08: minimum block size */1050x00, 0x00, /* +0A: maximum block size */1060x00, 0x00, 0x00, /* +0C: minimum frame size (0 == unknown) */1070x00, 0x00, 0x00, /* +0F: maximum frame size (0 == unknown) */1080x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */109/* numchannels (2), sample bits (16), */110/* samples in stream (0 == unknown) */1110x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */1120x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* +2A: start of stream data */113};114memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));115decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8;116decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff;117decoder->custom_header[0x12] = sample_rate >> 12;118decoder->custom_header[0x13] = sample_rate >> 4;119decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);120121/* configure the header ahead of the provided buffer */122decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header);123decoder->compressed_length = sizeof(decoder->custom_header);124decoder->compressed2_start = (const FLAC__byte *)(buffer);125decoder->compressed2_length = length;126return flac_decoder_internal_reset(decoder);127}128129/*-------------------------------------------------130* decode_interleaved - decode to an interleaved131* sound stream132*-------------------------------------------------133*/134135int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)136{137/* configure the uncompressed buffer */138memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));139decoder->uncompressed_start[0] = samples;140decoder->uncompressed_offset = 0;141decoder->uncompressed_length = num_samples;142decoder->uncompressed_swap = swap_endian;143144/* loop until we get everything we want */145while (decoder->uncompressed_offset < decoder->uncompressed_length)146if (!FLAC__stream_decoder_process_single(decoder->decoder))147return 0;148return 1;149}150151#if 0152/*-------------------------------------------------153* decode - decode to an multiple independent154* data streams155*-------------------------------------------------156*/157158bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)159{160/* make sure we don't have too many channels */161int chans = channels();162if (chans > ARRAY_LENGTH(m_uncompressed_start))163return false;164165/* configure the uncompressed buffer */166memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));167for (int curchan = 0; curchan < chans; curchan++)168m_uncompressed_start[curchan] = samples[curchan];169m_uncompressed_offset = 0;170m_uncompressed_length = num_samples;171m_uncompressed_swap = swap_endian;172173/* loop until we get everything we want */174while (m_uncompressed_offset < m_uncompressed_length)175if (!FLAC__stream_decoder_process_single(m_decoder))176return false;177return true;178}179#endif180181/*-------------------------------------------------182* finish - finish up the decode183*-------------------------------------------------184*/185186uint32_t flac_decoder_finish(flac_decoder* decoder)187{188/* get the final decoding position and move forward */189FLAC__uint64 position = 0;190FLAC__stream_decoder_get_decode_position(decoder->decoder, &position);191FLAC__stream_decoder_finish(decoder->decoder);192193/* adjust position if we provided the header */194if (position == 0)195return 0;196if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header))197position -= decoder->compressed_length;198return position;199}200201/*-------------------------------------------------202* read_callback - handle reads from the input203* stream204*-------------------------------------------------205*/206207#define MIN(x, y) ((x) < (y) ? (x) : (y))208209FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)210{211return flac_decoder_read_callback(client_data, buffer, bytes);212}213214FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes)215{216flac_decoder* decoder = (flac_decoder*)client_data;217218uint32_t expected = *bytes;219220/* copy from primary buffer first */221uint32_t outputpos = 0;222if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length)223{224uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);225memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);226outputpos += bytes_to_copy;227decoder->compressed_offset += bytes_to_copy;228}229230/* once we're out of that, copy from the secondary buffer */231if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)232{233uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));234memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);235outputpos += bytes_to_copy;236decoder->compressed_offset += bytes_to_copy;237}238*bytes = outputpos;239240/* return based on whether we ran out of data */241return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;242}243244/*-------------------------------------------------245* metadata_callback - handle STREAMINFO metadata246*-------------------------------------------------247*/248249void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)250{251flac_decoder *fldecoder;252/* ignore all but STREAMINFO metadata */253if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)254return;255256/* parse out the data we care about */257fldecoder = (flac_decoder *)(client_data);258fldecoder->sample_rate = metadata->data.stream_info.sample_rate;259fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample;260fldecoder->channels = metadata->data.stream_info.channels;261}262263/*-------------------------------------------------264* tell_callback - handle requests to find out265* where in the input stream we are266*-------------------------------------------------267*/268269FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)270{271*absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset;272return FLAC__STREAM_DECODER_TELL_STATUS_OK;273}274275/*-------------------------------------------------276* write_callback - handle writes to the output277* stream278*-------------------------------------------------279*/280281FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)282{283return flac_decoder_write_callback(client_data, frame, buffer);284}285286FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])287{288int sampnum, chan;289int shift, blocksize;290flac_decoder * decoder = (flac_decoder *)client_data;291292assert(frame->header.channels == channels(decoder));293294/* interleaved case */295shift = decoder->uncompressed_swap ? 8 : 0;296blocksize = frame->header.blocksize;297if (decoder->uncompressed_start[1] == NULL)298{299int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels;300for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)301for (chan = 0; chan < frame->header.channels; chan++)302*dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift));303}304305/* non-interleaved case */306else307{308for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++)309for (chan = 0; chan < frame->header.channels; chan++)310if (decoder->uncompressed_start[chan] != NULL)311decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) );312}313return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;314}315316/**317* @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)318*319* @brief -------------------------------------------------320* error_callback - handle errors (ignore them)321* -------------------------------------------------.322*323* @param decoder The decoder.324* @param status The status.325* @param [in,out] client_data If non-null, information describing the client.326*/327328void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)329{330}331332333