Initial revision
diff --git a/src/flac/Makefile b/src/flac/Makefile
new file mode 100644
index 0000000..ea58b13
--- /dev/null
+++ b/src/flac/Makefile
@@ -0,0 +1,16 @@
+#
+# GNU makefile
+#
+
+PROGRAM_NAME = flac
+INCLUDES = -I./include -I../../include
+LIBS = -lFLAC -lm
+
+OBJS = \
+ decode.o \
+ encode.o \
+ main.o
+
+include ../../build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/flac/Makefile.vc b/src/flac/Makefile.vc
new file mode 100644
index 0000000..e0d7cdf
--- /dev/null
+++ b/src/flac/Makefile.vc
@@ -0,0 +1,25 @@
+!include <win32.mak>
+
+!IFDEF DEBUG
+.c.obj:
+ $(cc) $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -YX /Od /D "_DEBUG" $<
+!else
+.c.obj:
+ $(cc) $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -YX /O2 -DNODEBUG $<
+!endif
+
+C_FILES= \
+ decode.c \
+ encode.c \
+ main.c
+
+OBJS= $(C_FILES:.c=.obj)
+
+all: flac.exe
+
+flac.exe: $(OBJS)
+ link.exe /libpath:"..\..\obj\lib" -out:../../obj/bin/$*.exe $(OBJS) libFLAC.lib
+
+clean:
+ -del *.obj *.pch
+ -del ..\..\obj\bin\flac.exe
diff --git a/src/flac/decode.c b/src/flac/decode.c
new file mode 100644
index 0000000..b8dfca0
--- /dev/null
+++ b/src/flac/decode.c
@@ -0,0 +1,377 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+#include <stdio.h> /* for FILE */
+#include <string.h> /* for strcmp() */
+#include "FLAC/all.h"
+#include "decode.h"
+
+typedef struct {
+ FILE *fout;
+ bool abort_flag;
+ bool is_wave_out;
+ bool is_big_endian;
+ bool is_unsigned_samples;
+ uint64 total_samples;
+ unsigned bps;
+ unsigned channels;
+ unsigned sample_rate;
+ bool verbose;
+ uint64 skip;
+ uint64 samples_processed;
+ unsigned frame_counter;
+} stream_info_struct;
+
+static FLAC__FileDecoder *decoder;
+static bool is_big_endian_host;
+
+/* local routines */
+static bool init(const char *infile, stream_info_struct *stream_info);
+static bool write_little_endian_uint16(FILE *f, uint16 val);
+static bool write_little_endian_uint32(FILE *f, uint32 val);
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
+static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+static void print_stats(const stream_info_struct *stream_info);
+
+int decode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip)
+{
+ stream_info_struct stream_info;
+
+ decoder = 0;
+ stream_info.abort_flag = false;
+ stream_info.is_wave_out = true;
+ stream_info.verbose = verbose;
+ stream_info.skip = skip;
+ stream_info.samples_processed = 0;
+ stream_info.frame_counter = 0;
+
+ if(0 == strcmp(outfile, "-")) {
+ stream_info.fout = stdout;
+ }
+ else {
+ if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
+ fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
+ return false;
+ }
+ }
+
+ if(!init(infile, &stream_info))
+ goto wav_abort_;
+
+ if(skip > 0) {
+ if(!FLAC__file_decoder_process_metadata(decoder)) {
+ fprintf(stderr, "ERROR during decoding\n");
+ goto wav_abort_;
+ }
+ if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
+ fprintf(stderr, "ERROR seeking while skipping bytes in input file %s\n", infile);
+ goto wav_abort_;
+ }
+ if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
+ fprintf(stderr, "ERROR during decodingg\n");
+ goto wav_abort_;
+ }
+ if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
+ fprintf(stderr, "ERROR during decodinggg\n");
+ goto wav_abort_;
+ }
+ }
+ else {
+ if(!FLAC__file_decoder_process_whole_file(decoder)) {
+ fprintf(stderr, "ERROR during decoding\n");
+ goto wav_abort_;
+ }
+ if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
+ fprintf(stderr, "ERROR during decodingg, state=%u\n", decoder->state);
+ goto wav_abort_;
+ }
+ }
+
+ if(decoder) {
+ if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder);
+ print_stats(&stream_info);
+ FLAC__file_decoder_free_instance(decoder);
+ }
+ fclose(stream_info.fout);
+ if(verbose)
+ printf("\n");
+ return 0;
+wav_abort_:
+ if(decoder) {
+ if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder);
+ FLAC__file_decoder_free_instance(decoder);
+ }
+ fclose(stream_info.fout);
+ unlink(outfile);
+ return 1;
+}
+
+int decode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples)
+{
+ stream_info_struct stream_info;
+
+ decoder = 0;
+ stream_info.abort_flag = false;
+ stream_info.is_wave_out = false;
+ stream_info.is_big_endian = is_big_endian;
+ stream_info.is_unsigned_samples = is_unsigned_samples;
+ stream_info.verbose = verbose;
+ stream_info.skip = skip;
+ stream_info.samples_processed = 0;
+ stream_info.frame_counter = 0;
+
+ if(0 == strcmp(outfile, "-")) {
+ stream_info.fout = stdout;
+ }
+ else {
+ if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
+ fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
+ return false;
+ }
+ }
+
+ if(!init(infile, &stream_info))
+ goto raw_abort_;
+
+ if(skip > 0) {
+ if(!FLAC__file_decoder_process_metadata(decoder)) {
+ fprintf(stderr, "ERROR during decoding\n");
+ goto raw_abort_;
+ }
+ if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
+ fprintf(stderr, "ERROR seeking while skipping bytes in input file %s\n", infile);
+ goto raw_abort_;
+ }
+ if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
+ fprintf(stderr, "ERROR during decodingg\n");
+ goto raw_abort_;
+ }
+ if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
+ fprintf(stderr, "ERROR during decodinggg\n");
+ goto raw_abort_;
+ }
+ }
+ else {
+ if(!FLAC__file_decoder_process_whole_file(decoder)) {
+ fprintf(stderr, "ERROR during decoding\n");
+ goto raw_abort_;
+ }
+ if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
+ fprintf(stderr, "ERROR during decodingg\n");
+ goto raw_abort_;
+ }
+ }
+
+ if(decoder) {
+ if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder);
+ print_stats(&stream_info);
+ FLAC__file_decoder_free_instance(decoder);
+ }
+ fclose(stream_info.fout);
+ if(verbose)
+ printf("\n");
+ return 0;
+raw_abort_:
+ if(decoder) {
+ if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder);
+ FLAC__file_decoder_free_instance(decoder);
+ }
+ fclose(stream_info.fout);
+ unlink(outfile);
+ return 1;
+}
+
+bool init(const char *infile, stream_info_struct *stream_info)
+{
+ uint32 test = 1;
+
+ is_big_endian_host = (*((byte*)(&test)))? false : true;
+
+ decoder = FLAC__file_decoder_get_new_instance();
+ if(0 == decoder) {
+ fprintf(stderr, "ERROR creating the decoder instance\n");
+ return false;
+ }
+
+ if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, stream_info) != FLAC__FILE_DECODER_OK) {
+ fprintf(stderr, "ERROR initializing decoder, state = %d\n", decoder->state);
+ return false;
+ }
+
+ return true;
+}
+
+bool write_little_endian_uint16(FILE *f, uint16 val)
+{
+ byte *b = (byte*)(&val);
+ if(is_big_endian_host) {
+ byte tmp;
+ tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+ }
+ return fwrite(b, 1, 2, f) == 2;
+}
+
+bool write_little_endian_uint32(FILE *f, uint32 val)
+{
+ byte *b = (byte*)(&val);
+ if(is_big_endian_host) {
+ byte tmp;
+ tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+ tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+ }
+ return fwrite(b, 1, 4, f) == 4;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
+{
+ stream_info_struct *stream_info = (stream_info_struct *)client_data;
+ FILE *fout = stream_info->fout;
+ unsigned bps = stream_info->bps, channels = stream_info->channels;
+ bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian);
+ bool is_unsigned_samples = (stream_info->is_wave_out? bps==8 : stream_info->is_unsigned_samples);
+ unsigned wide_samples = header->blocksize, wide_sample, sample, channel, byte;
+ static signed char scbuffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * ((FLAC__MAX_BITS_PER_SAMPLE+7)>>3)]; /* WATCHOUT: can be up to 2 megs */
+ unsigned char *ucbuffer = (unsigned char *)scbuffer;
+ signed short *ssbuffer = (signed short *)scbuffer;
+ unsigned short *usbuffer = (unsigned short *)scbuffer;
+
+ (void)decoder;
+
+ if(stream_info->abort_flag)
+ return FLAC__STREAM_DECODER_WRITE_ABORT;
+
+ stream_info->samples_processed += wide_samples;
+ stream_info->frame_counter++;
+
+ if(stream_info->verbose && !(stream_info->frame_counter & 0x1f))
+ print_stats(stream_info);
+
+ if(bps == 8) {
+ if(is_unsigned_samples) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ ucbuffer[sample] = buffer[channel][wide_sample] + 128;
+ }
+ else {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ scbuffer[sample] = buffer[channel][wide_sample];
+ }
+ if(fwrite(ucbuffer, 1, sample, fout) != sample)
+ return FLAC__STREAM_DECODER_WRITE_ABORT;
+ }
+ else { /* bps == 16 */
+ if(is_unsigned_samples) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ usbuffer[sample] = buffer[channel][wide_sample] + 32768;
+ }
+ else {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ ssbuffer[sample] = buffer[channel][wide_sample];
+ }
+ if(is_big_endian != is_big_endian_host) {
+ unsigned char tmp;
+ for(byte = 0; byte < sample<<1; byte += 2) {
+ tmp = ucbuffer[byte];
+ ucbuffer[byte] = ucbuffer[byte+1];
+ ucbuffer[byte+1] = tmp;
+ }
+ }
+ if(fwrite(usbuffer, 2, sample, fout) != sample)
+ return FLAC__STREAM_DECODER_WRITE_ABORT;
+ }
+ return FLAC__STREAM_DECODER_WRITE_CONTINUE;
+}
+
+void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+ stream_info_struct *stream_info = (stream_info_struct *)client_data;
+ (void)decoder;
+ if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
+ stream_info->total_samples = metadata->data.encoding.total_samples - stream_info->skip;
+ stream_info->bps = metadata->data.encoding.bits_per_sample;
+ stream_info->channels = metadata->data.encoding.channels;
+ stream_info->sample_rate = metadata->data.encoding.sample_rate;
+
+ if(stream_info->bps != 8 && stream_info->bps != 16) {
+ fprintf(stderr, "ERROR: bits per sample is not 8 or 16\n");
+ stream_info->abort_flag = true;
+ return;
+ }
+
+ /* write the WAVE headers if necessary */
+ if(stream_info->is_wave_out) {
+ uint64 data_size = stream_info->total_samples * stream_info->channels * ((stream_info->bps+7)/8);
+ if(data_size >= 0xFFFFFFDC) {
+ fprintf(stderr, "ERROR: stream is too big for a wave file\n");
+ stream_info->abort_flag = true;
+ return;
+ }
+ if(fwrite("RIFF", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
+ if(!write_little_endian_uint32(stream_info->fout, (uint32)(data_size+36))) stream_info->abort_flag = true; /* filesize-8 */
+ if(fwrite("WAVEfmt ", 1, 8, stream_info->fout) != 8) stream_info->abort_flag = true;
+ if(fwrite("\020\000\000\000", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; /* chunk size = 16 */
+ if(fwrite("\001\000", 1, 2, stream_info->fout) != 2) stream_info->abort_flag = true; /* compression code == 1 */
+ if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels))) stream_info->abort_flag = true;
+ if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate)) stream_info->abort_flag = true;
+ if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate * stream_info->channels * ((stream_info->bps+7) / 8))) stream_info->abort_flag = true; /* @@@ or is it (sample_rate*channels*bps) / 8 ??? */
+ if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels * ((stream_info->bps+7) / 8)))) stream_info->abort_flag = true; /* block align */
+ if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->bps))) stream_info->abort_flag = true; /* bits per sample */
+ if(fwrite("data", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
+ if(!write_little_endian_uint32(stream_info->fout, (uint32)data_size)) stream_info->abort_flag = true; /* data size */
+ }
+ }
+}
+
+void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ stream_info_struct *stream_info = (stream_info_struct *)client_data;
+ (void)decoder;
+ fprintf(stderr, "*** Got error code %d\n", status);
+ stream_info->abort_flag = true;
+}
+
+void print_stats(const stream_info_struct *stream_info)
+{
+ if(stream_info->verbose) {
+ printf("\rwrote %u of %u samples, %6.2f%% complete",
+ (unsigned)stream_info->samples_processed,
+ (unsigned)stream_info->total_samples,
+#ifdef _MSC_VER
+ /* with VC++ you have to spoon feed it the casting */
+ (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0
+#else
+ (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0
+#endif
+ );
+ fflush(stdout);
+ }
+}
diff --git a/src/flac/decode.h b/src/flac/decode.h
new file mode 100644
index 0000000..8c23485
--- /dev/null
+++ b/src/flac/decode.h
@@ -0,0 +1,25 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef flac__decode_h
+#define flac__decode_h
+
+int decode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip);
+int decode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples);
+
+#endif
diff --git a/src/flac/encode.c b/src/flac/encode.c
new file mode 100644
index 0000000..151dbde
--- /dev/null
+++ b/src/flac/encode.c
@@ -0,0 +1,587 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+#include <stdio.h> /* for FILE */
+#include <string.h> /* for strcmp() */
+#include "FLAC/all.h"
+#include "encode.h"
+
+#define CHUNK_OF_SAMPLES 2048
+
+typedef struct {
+ FILE *fout;
+ const char *outfile;
+ FLAC__Encoder *encoder;
+ bool verbose;
+ uint64 unencoded_size;
+ uint64 total_samples_to_encode;
+ uint64 bytes_written;
+ uint64 samples_written;
+ unsigned current_frame;
+} encoder_wrapper_struct;
+
+static bool is_big_endian_host;
+
+static unsigned char ucbuffer[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*(FLAC__MAX_BITS_PER_SAMPLE>>3)];
+static signed char *scbuffer = (signed char *)ucbuffer;
+static uint16 *usbuffer = (uint16 *)ucbuffer;
+static int16 *ssbuffer = (int16 *)ucbuffer;
+
+static int32 in[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES];
+static int32 *input[FLAC__MAX_CHANNELS];
+
+/* local routines */
+static bool init(encoder_wrapper_struct *encoder_wrapper);
+static bool init_encoder(bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, encoder_wrapper_struct *encoder_wrapper);
+static void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps);
+static FLAC__EncoderWriteStatus write_callback(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+static void metadata_callback(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void print_stats(const encoder_wrapper_struct *encoder_wrapper);
+static bool read_little_endian_uint16(FILE *f, uint16 *val, bool eof_ok);
+static bool read_little_endian_uint32(FILE *f, uint32 *val, bool eof_ok);
+
+int encode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision)
+{
+ encoder_wrapper_struct encoder_wrapper;
+ FILE *fin;
+ bool is_unsigned_samples;
+ unsigned channels, bps, sample_rate, data_bytes;
+ size_t bytes_per_wide_sample, bytes_read;
+ uint16 x;
+ uint32 xx;
+
+ encoder_wrapper.encoder = 0;
+ encoder_wrapper.verbose = verbose;
+ encoder_wrapper.bytes_written = 0;
+ encoder_wrapper.samples_written = 0;
+ encoder_wrapper.outfile = outfile;
+
+ if(0 == strcmp(infile, "-")) {
+ fin = stdin;
+ }
+ else {
+ if(0 == (fin = fopen(infile, "rb"))) {
+ fprintf(stderr, "ERROR: can't open input file %s\n", infile);
+ return false;
+ }
+ }
+ if(0 == strcmp(outfile, "-")) {
+ encoder_wrapper.fout = stdout;
+ }
+ else {
+ if(0 == (encoder_wrapper.fout = fopen(outfile, "wb"))) {
+ fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
+ fclose(fin);
+ return false;
+ }
+ }
+
+ if(!init(&encoder_wrapper))
+ goto wav_abort_;
+
+ /*
+ * check the RIFF chunk
+ */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ if(xx != 0x46464952) { /* "RIFF" */
+ fprintf(stderr, "ERROR: no RIFF header\n");
+ goto wav_abort_;
+ }
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+
+ /*
+ * now process the WAVE chunk
+ */
+ if(!read_little_endian_uint32(fin, &xx, true))
+ goto wav_end_;
+ if(xx != 0x45564157) { /* "WAVE" */
+ fprintf(stderr, "ERROR: no WAVE header\n");
+ goto wav_abort_;
+ }
+
+ /* do the format sub-chunk */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ if(xx != 0x20746d66) { /* "fmt " */
+ fprintf(stderr, "ERROR: no format sub-chunk\n");
+ goto wav_abort_;
+ }
+ /* fmt chunk size */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ if(xx != 16) {
+ fprintf(stderr, "ERROR: unsupported chunk\n");
+ goto wav_abort_;
+ }
+ /* compression code */
+ if(!read_little_endian_uint16(fin, &x, false))
+ goto wav_abort_;
+ if(x != 1) {
+ fprintf(stderr, "ERROR: unsupported compression type %u\n", (unsigned)x);
+ goto wav_abort_;
+ }
+ /* number of channels */
+ if(!read_little_endian_uint16(fin, &x, false))
+ goto wav_abort_;
+ if(x == 0 || x > FLAC__MAX_CHANNELS) {
+ fprintf(stderr, "ERROR: unsupported number channels %u\n", (unsigned)x);
+ goto wav_abort_;
+ }
+ channels = x;
+ /* sample rate */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ if(xx == 0 || xx > FLAC__MAX_SAMPLE_RATE) {
+ fprintf(stderr, "ERROR: unsupported sample rate %u\n", (unsigned)xx);
+ goto wav_abort_;
+ }
+ sample_rate = xx;
+ /* avg bytes per second (ignored) */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ /* block align (ignored) */
+ if(!read_little_endian_uint16(fin, &x, false))
+ goto wav_abort_;
+ /* bits per sample */
+ if(!read_little_endian_uint16(fin, &x, false))
+ goto wav_abort_;
+ if(x != 8 && x != 16) {
+ fprintf(stderr, "ERROR: unsupported bits per sample %u\n", (unsigned)x);
+ goto wav_abort_;
+ }
+ bps = x;
+ is_unsigned_samples = (x == 8);
+
+ /* do the data sub-chunk */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ if(xx != 0x61746164) { /* "data" */
+ fprintf(stderr, "ERROR: no data sub-chunk\n");
+ goto wav_abort_;
+ }
+ /* data size */
+ if(!read_little_endian_uint32(fin, &xx, false))
+ goto wav_abort_;
+ data_bytes = xx;
+
+ if(!init_encoder(lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, blocksize, qlp_coeff_precision, channels, bps, sample_rate, &encoder_wrapper))
+ goto wav_abort_;
+
+ bytes_per_wide_sample = channels * (bps >> 3);
+
+ if(-1 == fseek(fin, bytes_per_wide_sample * (unsigned)skip, SEEK_CUR)) {
+ fprintf(stderr, "ERROR seeking while skipping samples in input file %s\n", infile);
+ goto wav_abort_;
+ }
+
+ encoder_wrapper.total_samples_to_encode = data_bytes / bytes_per_wide_sample - skip;
+ encoder_wrapper.unencoded_size = encoder_wrapper.total_samples_to_encode * bytes_per_wide_sample + 44; /* 44 for the size of the WAV headers */
+
+ while(data_bytes > 0) {
+ bytes_read = fread(ucbuffer, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample, fin);
+ if(bytes_read == 0) {
+ if(ferror(fin)) {
+ fprintf(stderr, "ERROR reading from %s\n", infile);
+ goto wav_abort_;
+ }
+ else if(feof(fin))
+ break;
+ }
+ else if(bytes_read % bytes_per_wide_sample != 0) {
+ fprintf(stderr, "ERROR, got partial sample from input file %s\n", infile);
+ goto wav_abort_;
+ }
+ else {
+ unsigned wide_samples = bytes_read / bytes_per_wide_sample;
+ format_input(wide_samples, false, is_unsigned_samples, channels, bps);
+ if(!FLAC__encoder_process(encoder_wrapper.encoder, input, wide_samples)) {
+ fprintf(stderr, "ERROR during encoding, state = %d\n", encoder_wrapper.encoder->state);
+ goto wav_abort_;
+ }
+ data_bytes -= bytes_read;
+ }
+ }
+
+wav_end_:
+ if(encoder_wrapper.encoder) {
+ if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED)
+ FLAC__encoder_finish(encoder_wrapper.encoder);
+ FLAC__encoder_free_instance(encoder_wrapper.encoder);
+ }
+ if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) {
+ print_stats(&encoder_wrapper);
+ printf("\n");
+ }
+ fclose(fin);
+ return 0;
+wav_abort_:
+ if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0)
+ printf("\n");
+ if(encoder_wrapper.encoder) {
+ if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED)
+ FLAC__encoder_finish(encoder_wrapper.encoder);
+ FLAC__encoder_free_instance(encoder_wrapper.encoder);
+ }
+ fclose(fin);
+ unlink(outfile);
+ return 1;
+}
+
+int encode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned sample_rate)
+{
+ encoder_wrapper_struct encoder_wrapper;
+ FILE *fin;
+ size_t bytes_read;
+ const size_t bytes_per_wide_sample = channels * (bps >> 3);
+
+ encoder_wrapper.encoder = 0;
+ encoder_wrapper.verbose = verbose;
+ encoder_wrapper.bytes_written = 0;
+ encoder_wrapper.samples_written = 0;
+ encoder_wrapper.outfile = outfile;
+
+ if(0 == strcmp(infile, "-")) {
+ fin = stdin;
+ }
+ else {
+ if(0 == (fin = fopen(infile, "rb"))) {
+ fprintf(stderr, "ERROR: can't open input file %s\n", infile);
+ return false;
+ }
+ }
+ if(0 == strcmp(outfile, "-")) {
+ encoder_wrapper.fout = stdout;
+ }
+ else {
+ if(0 == (encoder_wrapper.fout = fopen(outfile, "wb"))) {
+ fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
+ fclose(fin);
+ return false;
+ }
+ }
+
+ if(!init(&encoder_wrapper))
+ goto raw_abort_;
+
+ if(!init_encoder(lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, blocksize, qlp_coeff_precision, channels, bps, sample_rate, &encoder_wrapper))
+ goto raw_abort_;
+
+ /* get the file length */
+ if(0 != fseek(fin, 0, SEEK_END)) {
+ encoder_wrapper.total_samples_to_encode = encoder_wrapper.unencoded_size = 0;
+ }
+ else {
+ long filesize;
+ fflush(fin);
+ if(-1 == (filesize = ftell(fin))) {
+ encoder_wrapper.total_samples_to_encode = encoder_wrapper.unencoded_size = 0;
+ }
+ else {
+ encoder_wrapper.unencoded_size = filesize - skip * bytes_per_wide_sample;
+ encoder_wrapper.total_samples_to_encode = filesize / bytes_per_wide_sample - skip;
+ }
+ }
+
+ if(-1 == fseek(fin, bytes_per_wide_sample * (unsigned)skip, SEEK_SET)) {
+ fprintf(stderr, "ERROR seeking while skipping samples in input file %s\n", infile);
+ goto raw_abort_;
+ }
+
+ while(!feof(fin)) {
+ bytes_read = fread(ucbuffer, sizeof(unsigned char), CHUNK_OF_SAMPLES * bytes_per_wide_sample, fin);
+ if(bytes_read == 0) {
+ if(ferror(fin)) {
+ fprintf(stderr, "ERROR reading from %s\n", infile);
+ goto raw_abort_;
+ }
+ }
+ else if(bytes_read % bytes_per_wide_sample != 0) {
+ fprintf(stderr, "ERROR, got partial sample from input file %s\n", infile);
+ goto raw_abort_;
+ }
+ else {
+ unsigned wide_samples = bytes_read / bytes_per_wide_sample;
+ format_input(wide_samples, is_big_endian, is_unsigned_samples, channels, bps);
+ if(!FLAC__encoder_process(encoder_wrapper.encoder, input, wide_samples)) {
+ fprintf(stderr, "ERROR during encoding, state = %d\n", encoder_wrapper.encoder->state);
+ goto raw_abort_;
+ }
+ }
+ }
+
+ if(encoder_wrapper.encoder) {
+ if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED)
+ FLAC__encoder_finish(encoder_wrapper.encoder);
+ FLAC__encoder_free_instance(encoder_wrapper.encoder);
+ }
+ if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) {
+ print_stats(&encoder_wrapper);
+ printf("\n");
+ }
+ fclose(fin);
+ return 0;
+raw_abort_:
+ if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0)
+ printf("\n");
+ if(encoder_wrapper.encoder) {
+ if(encoder_wrapper.encoder->state != FLAC__ENCODER_UNINITIALIZED)
+ FLAC__encoder_finish(encoder_wrapper.encoder);
+ FLAC__encoder_free_instance(encoder_wrapper.encoder);
+ }
+ fclose(fin);
+ unlink(outfile);
+ return 1;
+}
+
+bool init(encoder_wrapper_struct *encoder_wrapper)
+{
+ unsigned i;
+ uint32 test = 1;
+
+ is_big_endian_host = (*((byte*)(&test)))? false : true;
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+ input[i] = &(in[i][0]);
+
+ encoder_wrapper->encoder = FLAC__encoder_get_new_instance();
+ if(0 == encoder_wrapper->encoder) {
+ fprintf(stderr, "ERROR creating the encoder instance\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool init_encoder(bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, encoder_wrapper_struct *encoder_wrapper)
+{
+ if(channels != 2 || bps > 16)
+ do_mid_side = false;
+
+ encoder_wrapper->encoder->streamable_subset = !lax;
+ encoder_wrapper->encoder->channels = channels;
+ encoder_wrapper->encoder->bits_per_sample = bps;
+ encoder_wrapper->encoder->sample_rate = sample_rate;
+ encoder_wrapper->encoder->blocksize = blocksize;
+ encoder_wrapper->encoder->qlp_coeff_precision = qlp_coeff_precision;
+ encoder_wrapper->encoder->max_lpc_order = max_lpc_order;
+ encoder_wrapper->encoder->do_mid_side_stereo = do_mid_side;
+ encoder_wrapper->encoder->do_exhaustive_model_search = do_exhaustive_model_search;
+ encoder_wrapper->encoder->do_qlp_coeff_prec_search = do_qlp_coeff_prec_search;
+ encoder_wrapper->encoder->rice_optimization_level = rice_optimization_level;
+
+ if(FLAC__encoder_init(encoder_wrapper->encoder, write_callback, metadata_callback, encoder_wrapper) != FLAC__ENCODER_OK) {
+ fprintf(stderr, "ERROR initializing encoder, state = %d\n", encoder_wrapper->encoder->state);
+ return false;
+ }
+
+ return true;
+}
+
+void format_input(unsigned wide_samples, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps)
+{
+ unsigned wide_sample, sample, channel, byte;
+
+ if(bps == 8) {
+ if(is_unsigned_samples) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ input[channel][wide_sample] = (int32)ucbuffer[sample] - 128;
+ }
+ else {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ input[channel][wide_sample] = (int32)scbuffer[sample];
+ }
+ }
+ else {
+ if(is_big_endian != is_big_endian_host) {
+ unsigned char tmp;
+ const unsigned bytes = wide_samples * channels * (bps >> 3);
+ for(byte = 0; byte < bytes; byte += 2) {
+ tmp = ucbuffer[byte];
+ ucbuffer[byte] = ucbuffer[byte+1];
+ ucbuffer[byte+1] = tmp;
+ }
+ }
+ if(is_unsigned_samples) {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ input[channel][wide_sample] = (int32)usbuffer[sample] - 32768;
+ }
+ else {
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ input[channel][wide_sample] = (int32)ssbuffer[sample];
+ }
+ }
+}
+
+FLAC__EncoderWriteStatus write_callback(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+ encoder_wrapper_struct *encoder_wrapper = (encoder_wrapper_struct *)client_data;
+ unsigned mask = (encoder->do_exhaustive_model_search || encoder->do_qlp_coeff_prec_search)? 0x07 : 0x1f;
+
+ encoder_wrapper->bytes_written += bytes;
+ encoder_wrapper->samples_written += samples;
+ encoder_wrapper->current_frame = current_frame;
+
+ if(samples && encoder_wrapper->verbose && encoder_wrapper->total_samples_to_encode > 0 && !(current_frame & mask))
+ print_stats(encoder_wrapper);
+
+ if(fwrite(buffer, sizeof(byte), bytes, encoder_wrapper->fout) == bytes)
+ return FLAC__ENCODER_WRITE_OK;
+ else
+ return FLAC__ENCODER_WRITE_FATAL_ERROR;
+}
+
+void metadata_callback(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+ encoder_wrapper_struct *encoder_wrapper = (encoder_wrapper_struct *)client_data;
+ byte b;
+ FILE *f;
+ const uint64 samples = metadata->data.encoding.total_samples;
+ const unsigned min_framesize = metadata->data.encoding.min_framesize;
+ const unsigned max_framesize = metadata->data.encoding.max_framesize;
+
+ (void)encoder; /* silence compiler warning about unused parameter */
+
+ if(encoder_wrapper->fout == stdout)
+ return;
+
+ fclose(encoder_wrapper->fout);
+ if(0 == (f = fopen(encoder_wrapper->outfile, "r+b")))
+ return;
+
+ /* all this is based on intimate knowledge of the stream header
+ * layout, but a change to the header format that would break this
+ * would also break all streams encoded in the previous format.
+ */
+
+ if(-1 == fseek(f, 21, SEEK_SET)) goto framesize_;
+ if(fread(&b, 1, 1, f) != 1) goto framesize_;
+ if(-1 == fseek(f, 21, SEEK_SET)) goto framesize_;
+ b = (b & 0xf0) | (byte)((samples >> 32) & 0x0F);
+ if(fwrite(&b, 1, 1, f) != 1) goto framesize_;
+ b = (byte)((samples >> 24) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto framesize_;
+ b = (byte)((samples >> 16) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto framesize_;
+ b = (byte)((samples >> 8) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto framesize_;
+ b = (byte)(samples & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto framesize_;
+
+framesize_:
+ if(-1 == fseek(f, 12, SEEK_SET)) goto end_;
+ b = (byte)((min_framesize >> 16) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto end_;
+ b = (byte)((min_framesize >> 8) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto end_;
+ b = (byte)(min_framesize & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto end_;
+ b = (byte)((max_framesize >> 16) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto end_;
+ b = (byte)((max_framesize >> 8) & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto end_;
+ b = (byte)(max_framesize & 0xFF);
+ if(fwrite(&b, 1, 1, f) != 1) goto end_;
+end_:
+ fclose(encoder_wrapper->fout);
+ return;
+}
+
+void print_stats(const encoder_wrapper_struct *encoder_wrapper)
+{
+#ifdef _MSC_VER
+ /* with VC++ you have to spoon feed it the casting */
+ double progress = (double)(int64)encoder_wrapper->samples_written / (double)(int64)encoder_wrapper->total_samples_to_encode;
+#else
+ double progress = (double)encoder_wrapper->samples_written / (double)encoder_wrapper->total_samples_to_encode;
+#endif
+ printf("\r%0.2f%% complete: frame %u, wrote %u bytes, %u of %u samples, ratio = %5.3f",
+ progress * 100.0, encoder_wrapper->current_frame,
+ (unsigned)encoder_wrapper->bytes_written, (unsigned)encoder_wrapper->samples_written, (unsigned)encoder_wrapper->total_samples_to_encode,
+#ifdef _MSC_VER
+ /* with VC++ you have to spoon feed it the casting */
+ (double)(int64)encoder_wrapper->bytes_written / ((double)(int64)encoder_wrapper->unencoded_size * progress)
+#else
+ (double)encoder_wrapper->bytes_written / ((double)encoder_wrapper->unencoded_size * progress)
+#endif
+ );
+ fflush(stdout);
+}
+
+bool read_little_endian_uint16(FILE *f, uint16 *val, bool eof_ok)
+{
+ size_t bytes_read = fread(val, 1, 2, f);
+
+ if(bytes_read == 0) {
+ if(!eof_ok) {
+ fprintf(stderr, "ERROR: unexpected EOF\n");
+ return false;
+ }
+ else
+ return true;
+ }
+ else if(bytes_read < 2) {
+ fprintf(stderr, "ERROR: unexpected EOF\n");
+ return false;
+ }
+ else {
+ if(is_big_endian_host) {
+ byte tmp, *b = (byte*)val;
+ tmp = b[1]; b[1] = b[0]; b[0] = tmp;
+ }
+ return true;
+ }
+}
+
+bool read_little_endian_uint32(FILE *f, uint32 *val, bool eof_ok)
+{
+ size_t bytes_read = fread(val, 1, 4, f);
+
+ if(bytes_read == 0) {
+ if(!eof_ok) {
+ fprintf(stderr, "ERROR: unexpected EOF\n");
+ return false;
+ }
+ else
+ return true;
+ }
+ else if(bytes_read < 4) {
+ fprintf(stderr, "ERROR: unexpected EOF\n");
+ return false;
+ }
+ else {
+ if(is_big_endian_host) {
+ byte tmp, *b = (byte*)val;
+ tmp = b[3]; b[3] = b[0]; b[0] = tmp;
+ tmp = b[2]; b[2] = b[1]; b[1] = tmp;
+ }
+ return true;
+ }
+}
diff --git a/src/flac/encode.h b/src/flac/encode.h
new file mode 100644
index 0000000..74a1f1e
--- /dev/null
+++ b/src/flac/encode.h
@@ -0,0 +1,27 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef flac__encode_h
+#define flac__encode_h
+
+#include "FLAC/ordinals.h"
+
+int encode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision);
+int encode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool lax, bool do_mid_side, bool do_exhaustive_model_search, bool do_qlp_coeff_prec_search, unsigned rice_optimization_level, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, bool is_big_endian, bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned sample_rate);
+
+#endif
diff --git a/src/flac/main.c b/src/flac/main.c
new file mode 100644
index 0000000..b7cba20
--- /dev/null
+++ b/src/flac/main.c
@@ -0,0 +1,338 @@
+/* flac - Command-line FLAC encoder/decoder
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/all.h"
+#include "decode.h"
+#include "encode.h"
+
+static int usage(const char *message, ...);
+
+int main(int argc, char *argv[])
+{
+ int i;
+ bool verbose = true, lax = false, mode_decode = false, do_mid_side = true, do_exhaustive_model_search = false, do_qlp_coeff_prec_search = false;
+ unsigned max_lpc_order = 8;
+ unsigned qlp_coeff_precision = 0;
+ uint64 skip = 0;
+ int format_is_wave = -1, format_is_big_endian = -1, format_is_unsigned_samples = false;
+ int format_channels = -1, format_bps = -1, format_sample_rate = -1;
+ int blocksize = -1, rice_optimization_level = -1;
+
+ if(argc <= 1)
+ return usage(0);
+
+ /* get the options */
+ for(i = 1; i < argc; i++) {
+ if(argv[i][0] != '-' || argv[i][1] == 0)
+ break;
+ if(0 == strcmp(argv[i], "-d"))
+ mode_decode = true;
+ else if(0 == strcmp(argv[i], "-s"))
+ verbose = false;
+ else if(0 == strcmp(argv[i], "-s-"))
+ verbose = true;
+ else if(0 == strcmp(argv[i], "--skip"))
+ skip = (uint64)atoi(argv[++i]); /* takes a pretty damn big file to overflow atoi() here, but it could happen */
+ else if(0 == strcmp(argv[i], "--lax"))
+ lax = true;
+ else if(0 == strcmp(argv[i], "--lax-"))
+ lax = false;
+ else if(0 == strcmp(argv[i], "-b"))
+ blocksize = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-e"))
+ do_exhaustive_model_search = true;
+ else if(0 == strcmp(argv[i], "-e-"))
+ do_exhaustive_model_search = false;
+ else if(0 == strcmp(argv[i], "-l"))
+ max_lpc_order = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-m"))
+ do_mid_side = true;
+ else if(0 == strcmp(argv[i], "-m-"))
+ do_mid_side = false;
+ else if(0 == strcmp(argv[i], "-p"))
+ do_qlp_coeff_prec_search = true;
+ else if(0 == strcmp(argv[i], "-p-"))
+ do_qlp_coeff_prec_search = false;
+ else if(0 == strcmp(argv[i], "-q"))
+ qlp_coeff_precision = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-r"))
+ rice_optimization_level = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-fb"))
+ format_is_big_endian = true;
+ else if(0 == strcmp(argv[i], "-fl"))
+ format_is_big_endian = false;
+ else if(0 == strcmp(argv[i], "-fc"))
+ format_channels = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-fp"))
+ format_bps = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-fs"))
+ format_sample_rate = atoi(argv[++i]);
+ else if(0 == strcmp(argv[i], "-fu"))
+ format_is_unsigned_samples = true;
+ else if(0 == strcmp(argv[i], "-fr"))
+ format_is_wave = false;
+ else if(0 == strcmp(argv[i], "-fw"))
+ format_is_wave = true;
+ else if(0 == strcmp(argv[i], "-0")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = false;
+ qlp_coeff_precision = 0;
+ rice_optimization_level = 0;
+ max_lpc_order = 0;
+ }
+ else if(0 == strcmp(argv[i], "-1")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = true;
+ qlp_coeff_precision = 0;
+ rice_optimization_level = 0;
+ max_lpc_order = 0;
+ }
+ else if(0 == strcmp(argv[i], "-2")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = true;
+ qlp_coeff_precision = 0;
+ max_lpc_order = 0;
+ }
+ else if(0 == strcmp(argv[i], "-4")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = false;
+ qlp_coeff_precision = 0;
+ rice_optimization_level = 0;
+ max_lpc_order = 8;
+ }
+ else if(0 == strcmp(argv[i], "-5")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = true;
+ qlp_coeff_precision = 0;
+ rice_optimization_level = 0;
+ max_lpc_order = 8;
+ }
+ else if(0 == strcmp(argv[i], "-6")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = true;
+ qlp_coeff_precision = 0;
+ max_lpc_order = 8;
+ }
+ else if(0 == strcmp(argv[i], "-8")) {
+ do_exhaustive_model_search = false;
+ do_mid_side = true;
+ qlp_coeff_precision = 0;
+ max_lpc_order = 32;
+ }
+ else if(0 == strcmp(argv[i], "-9")) {
+ do_exhaustive_model_search = true;
+ do_mid_side = true;
+ do_qlp_coeff_prec_search = true;
+ rice_optimization_level = 99;
+ max_lpc_order = 32;
+ }
+ else if(isdigit((int)(argv[i][1]))) {
+ return usage("ERROR: compression level '%s' is still reserved\n", argv[i]);
+ }
+ else {
+ return usage("ERROR: invalid option '%s'\n", argv[i]);
+ }
+ }
+ if(i + 2 != argc)
+ return usage("ERROR: invalid arguments (more/less than 2 filenames?)\n");
+
+ /* tweak options based on the filenames; validate the values */
+ if(!mode_decode) {
+ if(format_is_wave < 0) {
+ if(strstr(argv[i], ".wav") == argv[i] + (strlen(argv[i]) - strlen(".wav")))
+ format_is_wave = true;
+ else
+ format_is_wave = false;
+ }
+ if(!format_is_wave) {
+ if(format_is_big_endian < 0 || format_channels < 0 || format_bps < 0 || format_sample_rate < 0)
+ return usage("ERROR: for encoding a raw file you must specify { -fb or -fl }, -fc, -fp, and -fs\n");
+ }
+ if(blocksize < 0) {
+ if(max_lpc_order == 0)
+ blocksize = 1152;
+ else
+ blocksize = 4608;
+ }
+ if(rice_optimization_level < 0) {
+ if(blocksize <= 1152)
+ rice_optimization_level = 4;
+ else if(blocksize <= 2304)
+ rice_optimization_level = 4;
+ else if(blocksize <= 4608)
+ rice_optimization_level = 4;
+ else
+ rice_optimization_level = 5;
+ }
+ }
+ else {
+ if(format_is_wave < 0) {
+ if(strstr(argv[i+1], ".wav") == argv[i+1] + (strlen(argv[i+1]) - strlen(".wav")))
+ format_is_wave = true;
+ else
+ format_is_wave = false;
+ }
+ if(!format_is_wave) {
+ if(format_is_big_endian < 0)
+ return usage("ERROR: for decoding to a raw file you must specify -fb or -fl\n");
+ }
+ }
+
+ assert(blocksize >= 0 || mode_decode);
+
+ if(format_channels >= 0) {
+ if(format_channels == 0 || (unsigned)format_channels > FLAC__MAX_CHANNELS)
+ return usage("ERROR: invalid number of channels '%u', must be > 0 and <= %u\n", format_channels, FLAC__MAX_CHANNELS);
+ }
+ if(format_bps >= 0) {
+ if(format_bps != 8 && format_bps != 16)
+ return usage("ERROR: invalid bits per sample '%u' (must be 8 or 16)\n", format_bps);
+ }
+ if(format_sample_rate >= 0) {
+ if(format_sample_rate == 0 || (unsigned)format_sample_rate > FLAC__MAX_SAMPLE_RATE)
+ return usage("ERROR: invalid sample rate '%u', must be > 0 and <= %u\n", format_sample_rate, FLAC__MAX_SAMPLE_RATE);
+ }
+ if(!mode_decode && ((unsigned)blocksize < FLAC__MIN_BLOCK_SIZE || (unsigned)blocksize > FLAC__MAX_BLOCK_SIZE)) {
+ return usage("ERROR: invalid blocksize '%u', must be >= %u and <= %u\n", (unsigned)blocksize, FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE);
+ }
+ if(qlp_coeff_precision > 0 && qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION) {
+ return usage("ERROR: invalid value for -q '%u', must be 0 or >= %u\n", qlp_coeff_precision, FLAC__MIN_QLP_COEFF_PRECISION);
+ }
+
+ /* turn off verbosity if the output stream is going to stdout */
+ if(0 == strcmp(argv[i+1], "-"))
+ verbose = false;
+
+ if(verbose) {
+ printf("\n");
+ printf("flac v%u.%u, Copyright (C) 2000 Josh Coalson\n", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION);
+ printf("flac comes with ABSOLUTELY NO WARRANTY. This is free software, and you are\n");
+ printf("welcome to redistribute it under certain conditions. Type `flac' for details.\n\n");
+
+ if(!mode_decode) {
+ printf("options:%s -b %u%s -l %u%s%s -q %u -r %u\n",
+ lax?" --lax":"", (unsigned)blocksize, do_mid_side?" -m":"", max_lpc_order,
+ do_exhaustive_model_search?" -e":"", do_qlp_coeff_prec_search?" -p":"",
+ qlp_coeff_precision, (unsigned)rice_optimization_level
+ );
+ }
+ }
+
+ if(mode_decode)
+ if(format_is_wave)
+ return decode_wav(argv[i], argv[i+1], verbose, skip);
+ else
+ return decode_raw(argv[i], argv[i+1], verbose, skip, format_is_big_endian, format_is_unsigned_samples);
+ else
+ if(format_is_wave)
+ return encode_wav(argv[i], argv[i+1], verbose, skip, lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, (unsigned)blocksize, qlp_coeff_precision);
+ else
+ return encode_raw(argv[i], argv[i+1], verbose, skip, lax, do_mid_side, do_exhaustive_model_search, do_qlp_coeff_prec_search, rice_optimization_level, max_lpc_order, (unsigned)blocksize, qlp_coeff_precision, format_is_big_endian, format_is_unsigned_samples, format_channels, format_bps, format_sample_rate);
+
+ return 0;
+}
+
+int usage(const char *message, ...)
+{
+ va_list args;
+
+ if(message) {
+ fprintf(stderr, message);
+ fprintf(stderr, "\n");
+ va_start(args, message);
+
+ (void) vfprintf(stderr, message, args);
+
+ va_end(args);
+
+ }
+ printf("==============================================================================\n");
+ printf("flac - Command-line FLAC encoder/decoder version %u.%u\n", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION);
+ printf("Copyright (C) 2000 Josh Coalson\n");
+ printf("\n");
+ printf("This program is free software; you can redistribute it and/or\n");
+ printf("modify it under the terms of the GNU General Public License\n");
+ printf("as published by the Free Software Foundation; either version 2\n");
+ printf("of the License, or (at your option) any later version.\n");
+ printf("\n");
+ printf("This program is distributed in the hope that it will be useful,\n");
+ printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+ printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
+ printf("GNU General Public License for more details.\n");
+ printf("\n");
+ printf("You should have received a copy of the GNU General Public License\n");
+ printf("along with this program; if not, write to the Free Software\n");
+ printf("Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n");
+ printf("==============================================================================\n");
+ printf("Usage:\n");
+ printf(" flac [options] infile outfile\n");
+ printf("\n");
+ printf("For encoding:\n");
+ printf(" infile may be a PCM RIFF WAVE file or raw samples\n");
+ printf(" outfile will be in FLAC format\n");
+ printf("For decoding, the reverse will be true\n");
+ printf("\n");
+ printf("infile may be - for stdin, outfile may be - for stdout\n");
+ printf("\n");
+ printf("If the unencoded filename ends with '.wav' or -fw is used, it's assumed to be\n");
+ printf("RIFF WAVE. Otherwise, it's assumed to be raw samples and you have to specify\n");
+ printf("all the format options. You can force a .wav file to be treated as a raw file\n");
+ printf("using -fr.\n");
+ printf("\n");
+ printf("generic options:\n");
+ printf(" -d : decode (default behavior is encode)\n");
+ printf(" -s : silent (do not write runtime encode/decode statistics to stdout)\n");
+ printf(" --skip samples : can be used both for encoding and decoding\n");
+ printf("encoding options:\n");
+ printf(" --lax : allow encoder to generate non-Subset files\n");
+ printf(" -b blocksize : default is 1152 for -l 0, else 4608; should be 192/576/1152/2304/4608 (unless --lax is used)\n");
+ printf(" -m : try mid-side coding for each frame (stereo input only)\n");
+ printf(" -0 .. -9 : fastest compression .. highest compression, default is -6\n");
+ printf(" these are synonyms for other options:\n");
+ printf(" -0 : synonymous with -l 0\n");
+ printf(" -1 : synonymous with -l 0 -m\n");
+ printf(" -2 : synonymous with -l 0 -m -r # (# is automatically determined by the block size)\n");
+ printf(" -3 : reserved\n");
+ printf(" -4 : synonymous with -l 8\n");
+ printf(" -5 : synonymous with -l 8 -m\n");
+ printf(" -6 : synonymous with -l 8 -m -r # (# is automatically determined by the block size)\n");
+ printf(" -7 : reserved\n");
+ printf(" -8 : synonymous with -l 32 -m -r # (# is automatically determined by the block size)\n");
+ printf(" -9 : synonymous with -l 32 -m -e -r 99 -p (very slow!)\n");
+ printf(" -e : do exhaustive model search (expensive!)\n");
+ printf(" -l max_lpc_order : 0 => use only fixed predictors\n");
+ printf(" -p : do exhaustive search of LP coefficient quantization (expensive!); overrides -q\n");
+ printf(" -q bits : precision of the quantized linear-predictor coefficients, 0 => let encoder decide (min is %u, default is -q 0)\n", FLAC__MIN_QLP_COEFF_PRECISION);
+ printf(" -r level : rice parameter optimization level (level is 0..99, 0 => none, default is -r 0, above 4 doesn't usually help much)\n");
+ printf(" -m-, -e-, -p-, --lax- can all be used to turn off a particular option\n");
+ printf("format options:\n");
+ printf(" -fb | -fl : big-endian | little-endian byte order\n");
+ printf(" -fc channels\n");
+ printf(" -fp bits_per_sample\n");
+ printf(" -fs sample_rate : in Hz\n");
+ printf(" -fu : unsigned samples (default is signed)\n");
+ printf(" -fr : force to raw format (even if filename ends in .wav)\n");
+ printf(" -fw : force to RIFF WAVE\n");
+ return 1;
+}
diff --git a/src/libFLAC/Makefile b/src/libFLAC/Makefile
new file mode 100644
index 0000000..f6662a3
--- /dev/null
+++ b/src/libFLAC/Makefile
@@ -0,0 +1,22 @@
+#
+# GNU makefile
+#
+
+LIB_NAME = libFLAC
+INCLUDES = -I./include -I../../include
+DEBUG_CFLAGS = -DFLAC_OVERFLOW_DETECT
+
+OBJS = \
+ bitbuffer.o \
+ crc.o \
+ encoder.o \
+ encoder_framing.o \
+ file_decoder.o \
+ fixed.o \
+ format.o \
+ lpc.o \
+ stream_decoder.o
+
+include ../../build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/libFLAC/Makefile.vc b/src/libFLAC/Makefile.vc
new file mode 100644
index 0000000..5bccf54
--- /dev/null
+++ b/src/libFLAC/Makefile.vc
@@ -0,0 +1,31 @@
+!include <win32.mak>
+
+!IFDEF DEBUG
+.c.obj:
+ $(cc) /D FLAC_OVERFLOW_DETECT /GX $(cdebug) $(cflags) /I "..\..\include" /I ".\include" -DSTRICT -YX /Od /D "_DEBUG" $<
+!else
+.c.obj:
+ $(cc) $(cdebug) $(cflags) /O2 /I "..\..\include" /I ".\include" -DSTRICT -YX -DNODEBUG $<
+!endif
+
+C_FILES= \
+ bitbuffer.c \
+ crc.c \
+ encoder.c \
+ encoder_framing.c \
+ file_decoder.c \
+ fixed.c \
+ format.c \
+ lpc.c \
+ stream_decoder.c
+
+OBJS= $(C_FILES:.c=.obj)
+
+all: libFLAC.lib
+
+libFLAC.lib: $(OBJS)
+ link.exe -lib -out:../../obj/lib/$*.lib $(OBJS)
+
+clean:
+ -del *.obj *.pch
+ -del ..\..\obj\lib\libFLAC.lib ..\..\obj\lib\libFLAC.pdb
diff --git a/src/libFLAC/bitbuffer.c b/src/libFLAC/bitbuffer.c
new file mode 100644
index 0000000..5f618a9
--- /dev/null
+++ b/src/libFLAC/bitbuffer.c
@@ -0,0 +1,962 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy(), memset() */
+#include "private/bitbuffer.h"
+
+static const unsigned FLAC__BITBUFFER_DEFAULT_CAPACITY = 65536; /* bytes */
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static bool bitbuffer_resize_(FLAC__BitBuffer *bb, unsigned new_capacity)
+{
+ byte *new_buffer;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ if(bb->capacity == new_capacity)
+ return true;
+
+ new_buffer = (byte*)malloc(sizeof(byte) * new_capacity);
+ if(new_buffer == 0)
+ return false;
+ memset(new_buffer, 0, new_capacity);
+ memcpy(new_buffer, bb->buffer, sizeof(byte)*min(bb->bytes+(bb->bits?1:0), new_capacity));
+ if(new_capacity < bb->bytes+(bb->bits?1:0)) {
+ bb->bytes = new_capacity;
+ bb->bits = 0;
+ bb->total_bits = (new_capacity<<3);
+ }
+ if(new_capacity < bb->consumed_bytes+(bb->consumed_bits?1:0)) {
+ bb->consumed_bytes = new_capacity;
+ bb->consumed_bits = 0;
+ bb->total_consumed_bits = (new_capacity<<3);
+ }
+ bb->buffer = new_buffer;
+ bb->capacity = new_capacity;
+ return true;
+}
+
+static bool bitbuffer_grow_(FLAC__BitBuffer *bb, unsigned min_bytes_to_add)
+{
+ unsigned new_capacity;
+
+ assert(min_bytes_to_add > 0);
+
+ new_capacity = max(bb->capacity * 4, bb->capacity + min_bytes_to_add);
+ return bitbuffer_resize_(bb, new_capacity);
+}
+
+static bool bitbuffer_ensure_size_(FLAC__BitBuffer *bb, unsigned bits_to_add)
+{
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+ if((bb->capacity<<3) < bb->total_bits + bits_to_add)
+ return bitbuffer_grow_(bb, (bits_to_add>>3)+2);
+ else
+ return true;
+}
+
+static bool bitbuffer_read_from_client_(FLAC__BitBuffer *bb, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ unsigned bytes;
+
+ /* first shift the unconsumed buffer data toward the front as much as possible */
+ if(bb->total_consumed_bits >= 8) {
+ unsigned l = 0, r = bb->consumed_bytes, r_end = bb->bytes;
+ for( ; r < r_end; l++, r++)
+ bb->buffer[l] = bb->buffer[r];
+ for( ; l < r_end; l++)
+ bb->buffer[l] = 0;
+ bb->bytes -= bb->consumed_bytes;
+ bb->total_bits -= (bb->consumed_bytes<<3);
+ bb->consumed_bytes = 0;
+ bb->total_consumed_bits = bb->consumed_bits;
+ }
+ /* grow if we need to */
+ if(bb->capacity <= 1) {
+ if(!bitbuffer_resize_(bb, 16))
+ return false;
+ }
+ /* finally, read in some data; if OK, go back to read_bit_, else fail */
+ bytes = bb->capacity - bb->bytes;
+ if(!read_callback(bb->buffer+bb->bytes, &bytes, client_data))
+ return false;
+ bb->bytes += bytes;
+ bb->total_bits += (bytes<<3);
+ return true;
+}
+
+void FLAC__bitbuffer_init(FLAC__BitBuffer *bb)
+{
+ assert(bb != 0);
+ bb->buffer = 0;
+ bb->capacity = 0;
+ bb->bytes = bb->bits = bb->total_bits = 0;
+ bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0;
+}
+
+bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const byte buffer[], unsigned bytes)
+{
+ assert(bb != 0);
+ FLAC__bitbuffer_init(bb);
+ if(bytes == 0)
+ return true;
+ else {
+ assert(buffer != 0);
+ bb->buffer = (byte*)malloc(sizeof(byte)*bytes);
+ if(bb->buffer == 0)
+ return false;
+ memcpy(bb->buffer, buffer, sizeof(byte)*bytes);
+ bb->capacity = bb->bytes = bytes;
+ bb->bits = 0;
+ bb->total_bits = (bytes<<3);
+ bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0;
+ return true;
+ }
+}
+
+bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src)
+{
+ static byte mask_[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+ unsigned bits_to_add = src->total_bits - src->total_consumed_bits;
+ assert(dest != 0);
+ assert(src != 0);
+
+ if(bits_to_add == 0)
+ return true;
+ if(dest->bits != src->consumed_bits)
+ return false;
+ if(!bitbuffer_ensure_size_(dest, bits_to_add))
+ return false;
+ if(dest->bits == 0) {
+ memcpy(dest->buffer+dest->bytes, src->buffer+src->consumed_bytes, src->bytes-src->consumed_bytes + ((src->bits)? 1:0));
+ }
+ else if(dest->bits + bits_to_add > 8) {
+ dest->buffer[dest->bytes] <<= (8 - dest->bits);
+ dest->buffer[dest->bytes] |= (src->buffer[src->consumed_bytes] & mask_[8-dest->bits]);
+ memcpy(dest->buffer+dest->bytes+1, src->buffer+src->consumed_bytes+1, src->bytes-src->consumed_bytes-1 + ((src->bits)? 1:0));
+ }
+ else {
+ dest->buffer[dest->bytes] <<= bits_to_add;
+ dest->buffer[dest->bytes] |= (src->buffer[src->consumed_bytes] & mask_[bits_to_add]);
+ }
+ dest->bits = src->bits;
+ dest->total_bits += bits_to_add;
+ dest->bytes = dest->total_bits / 8;
+
+ return true;
+}
+
+void FLAC__bitbuffer_free(FLAC__BitBuffer *bb)
+{
+ assert(bb != 0);
+ if(bb->buffer != 0)
+ free(bb->buffer);
+ bb->buffer = 0;
+ bb->capacity = 0;
+ bb->bytes = bb->bits = bb->total_bits = 0;
+ bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0;
+}
+
+bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb)
+{
+ if(bb->buffer == 0) {
+ bb->capacity = FLAC__BITBUFFER_DEFAULT_CAPACITY;
+ bb->buffer = (byte*)malloc(sizeof(byte) * bb->capacity);
+ if(bb->buffer == 0)
+ return false;
+ memset(bb->buffer, 0, bb->capacity);
+ }
+ else {
+ memset(bb->buffer, 0, bb->bytes + (bb->bits?1:0));
+ }
+ bb->bytes = bb->bits = bb->total_bits = 0;
+ bb->consumed_bytes = bb->consumed_bits = bb->total_consumed_bits = 0;
+ return true;
+}
+
+bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src)
+{
+ if(dest->capacity < src->capacity)
+ if(!bitbuffer_resize_(dest, src->capacity))
+ return false;
+ memcpy(dest->buffer, src->buffer, sizeof(byte)*min(src->capacity, src->bytes+1));
+ dest->bytes = src->bytes;
+ dest->bits = src->bits;
+ dest->total_bits = src->total_bits;
+ dest->consumed_bytes = src->consumed_bytes;
+ dest->consumed_bits = src->consumed_bits;
+ dest->total_consumed_bits = src->total_consumed_bits;
+ return true;
+}
+
+bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits)
+{
+ unsigned n, k;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ if(bits == 0)
+ return true;
+ if(!bitbuffer_ensure_size_(bb, bits))
+ return false;
+ bb->total_bits += bits;
+ while(bits > 0) {
+ n = min(8 - bb->bits, bits);
+ k = bits - n;
+ bb->buffer[bb->bytes] <<= n;
+ bits -= n;
+ bb->bits += n;
+ if(bb->bits == 8) {
+ bb->bytes++;
+ bb->bits = 0;
+ }
+ }
+ return true;
+}
+
+bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, uint32 val, unsigned bits)
+{
+ static uint32 mask[] = {
+ 0,
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+ 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+ 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+ 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+ 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+ 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+ 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+ 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+ };
+ unsigned n, k;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(bits <= 32);
+ if(bits == 0)
+ return true;
+ if(!bitbuffer_ensure_size_(bb, bits))
+ return false;
+ val &= mask[bits];
+ bb->total_bits += bits;
+ while(bits > 0) {
+ n = 8 - bb->bits;
+ if(n == 8) { /* i.e. bb->bits == 0 */
+ if(bits < 8) {
+ bb->buffer[bb->bytes] = val;
+ bb->bits = bits;
+ break;
+ }
+ else if(bits == 8) {
+ bb->buffer[bb->bytes++] = val;
+ break;
+ }
+ else {
+ k = bits - 8;
+ bb->buffer[bb->bytes++] = val >> k;
+ val &= (~(0xffffffff << k));
+ bits -= 8;
+ }
+ }
+ else if(bits <= n) {
+ bb->buffer[bb->bytes] <<= bits;
+ bb->buffer[bb->bytes] |= val;
+ if(bits == n) {
+ bb->bytes++;
+ bb->bits = 0;
+ }
+ else
+ bb->bits += bits;
+ break;
+ }
+ else {
+ k = bits - n;
+ bb->buffer[bb->bytes] <<= n;
+ bb->buffer[bb->bytes] |= (val>>k);
+ val &= (~(0xffffffff << k));
+ bits -= n;
+ bb->bytes++;
+ bb->bits = 0;
+ }
+ }
+
+ return true;
+}
+
+bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, int32 val, unsigned bits)
+{
+ return FLAC__bitbuffer_write_raw_uint32(bb, (uint32)val, bits);
+}
+
+bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, uint64 val, unsigned bits)
+{
+ static uint64 mask[] = {
+ 0,
+ 0x0000000000000001, 0x0000000000000003, 0x0000000000000007, 0x000000000000000F,
+ 0x000000000000001F, 0x000000000000003F, 0x000000000000007F, 0x00000000000000FF,
+ 0x00000000000001FF, 0x00000000000003FF, 0x00000000000007FF, 0x0000000000000FFF,
+ 0x0000000000001FFF, 0x0000000000003FFF, 0x0000000000007FFF, 0x000000000000FFFF,
+ 0x000000000001FFFF, 0x000000000003FFFF, 0x000000000007FFFF, 0x00000000000FFFFF,
+ 0x00000000001FFFFF, 0x00000000003FFFFF, 0x00000000007FFFFF, 0x0000000000FFFFFF,
+ 0x0000000001FFFFFF, 0x0000000003FFFFFF, 0x0000000007FFFFFF, 0x000000000FFFFFFF,
+ 0x000000001FFFFFFF, 0x000000003FFFFFFF, 0x000000007FFFFFFF, 0x00000000FFFFFFFF,
+ 0x00000001FFFFFFFF, 0x00000003FFFFFFFF, 0x00000007FFFFFFFF, 0x0000000FFFFFFFFF,
+ 0x0000001FFFFFFFFF, 0x0000003FFFFFFFFF, 0x0000007FFFFFFFFF, 0x000000FFFFFFFFFF,
+ 0x000001FFFFFFFFFF, 0x000003FFFFFFFFFF, 0x000007FFFFFFFFFF, 0x00000FFFFFFFFFFF,
+ 0x00001FFFFFFFFFFF, 0x00003FFFFFFFFFFF, 0x00007FFFFFFFFFFF, 0x0000FFFFFFFFFFFF,
+ 0x0001FFFFFFFFFFFF, 0x0003FFFFFFFFFFFF, 0x0007FFFFFFFFFFFF, 0x000FFFFFFFFFFFFF,
+ 0x001FFFFFFFFFFFFF, 0x003FFFFFFFFFFFFF, 0x007FFFFFFFFFFFFF, 0x00FFFFFFFFFFFFFF,
+ 0x01FFFFFFFFFFFFFF, 0x03FFFFFFFFFFFFFF, 0x07FFFFFFFFFFFFFF, 0x0FFFFFFFFFFFFFFF,
+ 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
+ };
+ unsigned n, k;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(bits <= 64);
+ if(bits == 0)
+ return true;
+ if(!bitbuffer_ensure_size_(bb, bits))
+ return false;
+ val &= mask[bits];
+ bb->total_bits += bits;
+ while(bits > 0) {
+ if(bb->bits == 0) {
+ if(bits < 8) {
+ bb->buffer[bb->bytes] = val;
+ bb->bits = bits;
+ break;
+ }
+ else if(bits == 8) {
+ bb->buffer[bb->bytes++] = val;
+ break;
+ }
+ else {
+ k = bits - 8;
+ bb->buffer[bb->bytes++] = val >> k;
+ val &= (~(0xffffffffffffffff << k));
+ bits -= 8;
+ }
+ }
+ else {
+ n = min(8 - bb->bits, bits);
+ k = bits - n;
+ bb->buffer[bb->bytes] <<= n;
+ bb->buffer[bb->bytes] |= (val>>k);
+ val &= (~(0xffffffffffffffff << k));
+ bits -= n;
+ bb->bits += n;
+ if(bb->bits == 8) {
+ bb->bytes++;
+ bb->bits = 0;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, int64 val, unsigned bits)
+{
+ return FLAC__bitbuffer_write_raw_uint64(bb, (uint64)val, bits);
+}
+
+bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter)
+{
+ unsigned bits, msbs;
+ uint32 pattern;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ /* init pattern with sign bit */
+ if(val < 0) {
+ pattern = 1;
+ val = -val;
+ }
+ else
+ pattern = 0;
+
+ msbs = val >> parameter;
+ bits = 2 + parameter + msbs;
+
+ if(bits <= 32) {
+ pattern = (pattern << parameter) | (val & ((1<<parameter)-1));
+ pattern = (pattern << (msbs+1)) | 1;
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, bits))
+ return false;
+ }
+ else {
+ /* write the sign bit */
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, 1))
+ return false;
+ /* write the binary LSBs */
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, val & ((1<<parameter)-1), parameter))
+ return false;
+ /* write the unary MSBs */
+ if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+ return false;
+ /* write the end bit */
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1))
+ return false;
+ }
+ return true;
+}
+
+bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, bool *overflow)
+{
+ unsigned bits, msbs;
+ uint32 pattern;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ *overflow = false;
+
+ /* init pattern with sign bit */
+ if(val < 0) {
+ pattern = 1;
+ val = -val;
+ }
+ else
+ pattern = 0;
+
+ msbs = val >> parameter;
+ bits = 2 + parameter + msbs;
+
+ if(bits <= 32) {
+ pattern = (pattern << parameter) | (val & ((1<<parameter)-1));
+ pattern = (pattern << (msbs+1)) | 1;
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, bits))
+ return false;
+ }
+ else if(bits > max_bits) {
+ *overflow = true;
+ return true;
+ }
+ else {
+ /* write the sign bit */
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, pattern, 1))
+ return false;
+ /* write the binary LSBs */
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, val & ((1<<parameter)-1), parameter))
+ return false;
+ /* write the unary MSBs */
+ if(!FLAC__bitbuffer_write_zeroes(bb, msbs))
+ return false;
+ /* write the end bit */
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, 1, 1))
+ return false;
+ }
+ return true;
+}
+
+bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, uint32 val)
+{
+ bool ok = 1;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(!(val & 0x80000000)); /* this version only handles 31 bits */
+
+ if(val < 0x80) {
+ return FLAC__bitbuffer_write_raw_uint32(bb, val, 8);
+ }
+ else if(val < 0x800) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (val>>6), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x10000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (val>>12), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x200000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (val>>18), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x4000000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (val>>24), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>18)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8);
+ }
+ else {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (val>>30), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>24)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>18)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (val&0x3F), 8);
+ }
+
+ return ok;
+}
+
+bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, uint64 val)
+{
+ bool ok = 1;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(!(val & 0xFFFFFFF000000000)); /* this version only handles 36 bits */
+
+ if(val < 0x80) {
+ return FLAC__bitbuffer_write_raw_uint32(bb, (uint32)val, 8);
+ }
+ else if(val < 0x800) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xC0 | (uint32)(val>>6), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x10000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xE0 | (uint32)(val>>12), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x200000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF0 | (uint32)(val>>18), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x4000000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xF8 | (uint32)(val>>24), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x80000000) {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFC | (uint32)(val>>30), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>24)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8);
+ }
+ else {
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0xFE, 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>30)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>24)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitbuffer_write_raw_uint32(bb, 0x80 | (uint32)(val&0x3F), 8);
+ }
+
+ return ok;
+}
+
+bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb)
+{
+ /* 0-pad to byte boundary */
+ if(bb->bits != 0)
+ return FLAC__bitbuffer_write_zeroes(bb, 8 - bb->bits);
+ else
+ return true;
+}
+
+bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
+
+ /* to avoid a drastic speed penalty we don't:
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+ assert(bb->bits == 0);
+ */
+
+read_bit_:
+ if(bb->total_consumed_bits < bb->total_bits) {
+ *val = (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0;
+ return true;
+ }
+ else {
+ if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+ return false;
+ goto read_bit_;
+ }
+}
+
+bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
+
+ /* to avoid a drastic speed penalty we don't:
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+ assert(bb->bits == 0);
+ */
+
+read_bit_:
+ if(bb->total_consumed_bits < bb->total_bits) {
+ *val = (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0;
+ bb->consumed_bits++;
+ if(bb->consumed_bits == 8) {
+ bb->consumed_bytes++;
+ bb->consumed_bits = 0;
+ }
+ bb->total_consumed_bits++;
+ return true;
+ }
+ else {
+ if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+ return false;
+ goto read_bit_;
+ }
+}
+
+bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
+
+ /* to avoid a drastic speed penalty we don't:
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+ assert(bb->bits == 0);
+ */
+
+read_bit_:
+ if(bb->total_consumed_bits < bb->total_bits) {
+ *val <<= 1;
+ *val |= (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0;
+ bb->consumed_bits++;
+ if(bb->consumed_bits == 8) {
+ bb->consumed_bytes++;
+ bb->consumed_bits = 0;
+ }
+ bb->total_consumed_bits++;
+ return true;
+ }
+ else {
+ if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+ return false;
+ goto read_bit_;
+ }
+}
+
+bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ static byte mask[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
+
+ /* to avoid a drastic speed penalty we don't:
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+ assert(bb->bits == 0);
+ */
+
+read_bit_:
+ if(bb->total_consumed_bits < bb->total_bits) {
+ *val <<= 1;
+ *val |= (bb->buffer[bb->consumed_bytes] & mask[bb->consumed_bits])? 1 : 0;
+ bb->consumed_bits++;
+ if(bb->consumed_bits == 8) {
+ bb->consumed_bytes++;
+ bb->consumed_bits = 0;
+ }
+ bb->total_consumed_bits++;
+ return true;
+ }
+ else {
+ if(!bitbuffer_read_from_client_(bb, read_callback, client_data))
+ return false;
+ goto read_bit_;
+ }
+}
+
+bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, uint32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ unsigned i;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(bits <= 32);
+
+ *val = 0;
+ for(i = 0; i < bits; i++) {
+ if(!FLAC__bitbuffer_read_bit_to_uint32(bb, val, read_callback, client_data))
+ return false;
+ }
+ return true;
+}
+
+bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, int32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ unsigned i;
+ uint32 x;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(bits <= 32);
+
+ x = 0;
+ for(i = 0; i < bits; i++) {
+ if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &x, read_callback, client_data))
+ return false;
+ }
+ /* fix the sign */
+ i = 32 - bits;
+ if(i) {
+ x <<= i;
+ *val = (int32)x;
+ *val >>= i;
+ }
+ else
+ *val = (int32)x;
+
+ return true;
+}
+
+bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, uint64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ unsigned i;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(bits <= 64);
+
+ *val = 0;
+ for(i = 0; i < bits; i++) {
+ if(!FLAC__bitbuffer_read_bit_to_uint64(bb, val, read_callback, client_data))
+ return false;
+ }
+ return true;
+}
+
+bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, int64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ unsigned i;
+ uint64 x;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ assert(bits <= 64);
+
+ x = 0;
+ for(i = 0; i < bits; i++) {
+ if(!FLAC__bitbuffer_read_bit_to_uint64(bb, &x, read_callback, client_data))
+ return false;
+ }
+ /* fix the sign */
+ i = 64 - bits;
+ if(i) {
+ x <<= i;
+ *val = (int64)x;
+ *val >>= i;
+ }
+ else
+ *val = (int64)x;
+
+ return true;
+}
+
+bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data)
+{
+ uint32 sign = 0, lsbs, msbs = 0;
+ unsigned bit;
+
+ assert(bb != 0);
+ assert(bb->buffer != 0);
+
+ /* read the sign bit */
+ if(!FLAC__bitbuffer_read_bit_to_uint32(bb, &sign, read_callback, client_data))
+ return false;
+ /* read the binary LSBs */
+ if(!FLAC__bitbuffer_read_raw_uint32(bb, &lsbs, parameter, read_callback, client_data))
+ return false;
+ /* read the unary MSBs and end bit */
+ while(1) {
+ if(!FLAC__bitbuffer_read_bit(bb, &bit, read_callback, client_data))
+ return false;
+ if(bit)
+ break;
+ else
+ msbs++;
+ }
+ /* compose the value */
+ *val = (msbs << parameter) | lsbs;
+ if(sign)
+ *val = -(*val);
+
+ return true;
+}
+
+/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */
+bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen)
+{
+ uint32 v = 0;
+ uint32 x;
+ unsigned i;
+
+ if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (byte)x;
+ if(!(x & 0x80)) { /* 0xxxxxxx */
+ v = x;
+ i = 0;
+ }
+ else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+ v = x & 0x07;
+ i = 3;
+ }
+ else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+ v = x & 0x03;
+ i = 4;
+ }
+ else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+ v = x & 0x01;
+ i = 5;
+ }
+ else
+ goto invalid_;
+ for( ; i; i--) {
+ if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (byte)x;
+ if(!(x & 0x80) || (x & 0x40)) /* 10xxxxxx */
+ goto invalid_;
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ *val = v;
+ return true;
+invalid_:
+ *val = 0xffffffff;
+ return true;
+}
+
+/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */
+bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen)
+{
+ uint64 v = 0;
+ uint32 x;
+ unsigned i;
+
+ if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (byte)x;
+ if(!(x & 0x80)) { /* 0xxxxxxx */
+ v = x;
+ i = 0;
+ }
+ else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+ v = x & 0x07;
+ i = 3;
+ }
+ else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+ v = x & 0x03;
+ i = 4;
+ }
+ else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+ v = x & 0x01;
+ i = 5;
+ }
+ else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */
+ v = 0;
+ i = 6;
+ }
+ else
+ goto invalid_;
+ for( ; i; i--) {
+ if(!FLAC__bitbuffer_read_raw_uint32(bb, &x, 8, read_callback, client_data))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (byte)x;
+ if(!(x & 0x80) || (x & 0x40)) /* 10xxxxxx */
+ goto invalid_;
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ *val = v;
+ return true;
+invalid_:
+ *val = 0xffffffff;
+ return true;
+}
+
+void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out)
+{
+ unsigned i, j;
+ if(bb == 0) {
+ fprintf(out, "bitbuffer is NULL\n");
+ }
+ else {
+ fprintf(out, "bitbuffer: capacity=%u bytes=%u bits=%u total_bits=%u consumed: bytes=%u, bits=%u, total_bits=%u\n", bb->capacity, bb->bytes, bb->bits, bb->total_bits, bb->consumed_bytes, bb->consumed_bits, bb->total_consumed_bits);
+ for(i = 0; i < bb->bytes; i++) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < 8; j++)
+ if(i*8+j < bb->total_consumed_bits)
+ fprintf(out, ".");
+ else
+ fprintf(out, "%01u", bb->buffer[i] & (1 << (8-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ if(bb->bits > 0) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < bb->bits; j++)
+ if(i*8+j < bb->total_consumed_bits)
+ fprintf(out, ".");
+ else
+ fprintf(out, "%01u", bb->buffer[i] & (1 << (bb->bits-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ }
+}
diff --git a/src/libFLAC/crc.c b/src/libFLAC/crc.c
new file mode 100644
index 0000000..7f6cbd2
--- /dev/null
+++ b/src/libFLAC/crc.c
@@ -0,0 +1,65 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "private/crc.h"
+
+byte FLAC__crc8(const byte *data, const unsigned len)
+{
+ static byte const 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
+ };
+ unsigned i;
+ byte crc = 0;
+
+ for(i = 0; i < len; i++)
+ crc = crc8_table_[crc ^ *data++];
+
+ return crc;
+}
diff --git a/src/libFLAC/encoder.c b/src/libFLAC/encoder.c
new file mode 100644
index 0000000..2a6fffa
--- /dev/null
+++ b/src/libFLAC/encoder.c
@@ -0,0 +1,900 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#include "FLAC/encoder.h"
+#include "private/bitbuffer.h"
+#include "private/encoder_framing.h"
+#include "private/fixed.h"
+#include "private/lpc.h"
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+#ifdef RICE_BITS
+#undef RICE_BITS
+#endif
+#define RICE_BITS(value, parameter) (2 + (parameter) + (((unsigned)((value) < 0? -(value) : (value))) >> (parameter)))
+
+typedef struct FLAC__EncoderPrivate {
+ unsigned input_capacity; /* current size (in samples) of the signal and residual buffers */
+ int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */
+ int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */
+ real *real_signal[FLAC__MAX_CHANNELS]; /* the floating-point version of the input signal */
+ real *real_signal_mid_side[2]; /* the floating-point version of the mid-side input signal (stereo only) */
+ int32 *residual[2]; /* where the candidate and best subframe residual signals will be stored */
+ unsigned best_residual; /* index into the above */
+ FLAC__BitBuffer frame; /* the current frame being worked on */
+ FLAC__BitBuffer frame_mid_side; /* special parallel workspace for the mid-side coded version of the current frame */
+ FLAC__BitBuffer frame_left_side; /* special parallel workspace for the left-side coded version of the current frame */
+ FLAC__BitBuffer frame_right_side; /* special parallel workspace for the right-side coded version of the current frame */
+ FLAC__SubframeHeader best_subframe, candidate_subframe;
+ bool current_frame_can_do_mid_side; /* encoder sets this false when any given sample of a frame's side channel exceeds 16 bits */
+ FLAC__StreamMetaData metadata;
+ unsigned current_sample_number;
+ unsigned current_frame_number;
+ FLAC__EncoderWriteStatus (*write_callback)(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
+ void (*metadata_callback)(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data);
+ void *client_data;
+} FLAC__EncoderPrivate;
+
+static bool encoder_resize_buffers_(FLAC__Encoder *encoder, unsigned new_size);
+static bool encoder_process_frame_(FLAC__Encoder *encoder, bool is_last_frame);
+static bool encoder_process_subframes_(FLAC__Encoder *encoder, bool is_last_frame, const FLAC__FrameHeader *frame_header, unsigned channels, const int32 *integer_signal[], const real *real_signal[], FLAC__BitBuffer *bitbuffer);
+static unsigned encoder_evaluate_constant_subframe_(const int32 signal, unsigned bits_per_sample, FLAC__SubframeHeader *subframe);
+static unsigned encoder_evaluate_fixed_subframe_(const int32 signal[], int32 residual[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe);
+static unsigned encoder_evaluate_lpc_subframe_(const int32 signal[], int32 residual[], const real lp_coeff[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned qlp_coeff_precision, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe);
+static unsigned encoder_evaluate_verbatim_subframe_(unsigned blocksize, unsigned bits_per_sample, FLAC__SubframeHeader *subframe);
+static unsigned encoder_find_best_partition_order_(int32 residual[], unsigned residual_samples, unsigned predictor_order, unsigned rice_parameter, unsigned max_partition_order, unsigned *best_partition_order, unsigned best_parameters[]);
+static bool encoder_generate_constant_subframe_(const FLAC__SubframeHeader *header, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer);
+static bool encoder_generate_fixed_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer);
+static bool encoder_generate_lpc_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer);
+static bool encoder_generate_verbatim_subframe_(const FLAC__SubframeHeader *header, const int32 signal[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer);
+static void encoder_promote_candidate_subframe_(FLAC__Encoder *encoder);
+static bool encoder_set_partitioned_rice_(const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameter, const unsigned partition_order, unsigned parameters[], unsigned *bits);
+
+
+bool encoder_resize_buffers_(FLAC__Encoder *encoder, unsigned new_size)
+{
+ bool ok;
+ unsigned i;
+ int32 *previous_is, *current_is;
+ real *previous_rs, *current_rs;
+ int32 *residual;
+
+ assert(new_size > 0);
+ assert(encoder->state == FLAC__ENCODER_OK);
+ assert(encoder->guts->current_sample_number == 0);
+
+ /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */
+ if(new_size <= encoder->guts->input_capacity)
+ return true;
+
+ ok = 1;
+ if(ok) {
+ for(i = 0; ok && i < encoder->channels; i++) {
+ /* integer version of the signal */
+ previous_is = encoder->guts->integer_signal[i];
+ current_is = (int32*)malloc(sizeof(int32) * new_size);
+ if(0 == current_is) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ ok = 0;
+ }
+ else {
+ encoder->guts->integer_signal[i] = current_is;
+ if(previous_is != 0)
+ free(previous_is);
+ }
+ /* real version of the signal */
+ previous_rs = encoder->guts->real_signal[i];
+ current_rs = (real*)malloc(sizeof(real) * new_size);
+ if(0 == current_rs) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ ok = 0;
+ }
+ else {
+ encoder->guts->real_signal[i] = current_rs;
+ if(previous_rs != 0)
+ free(previous_rs);
+ }
+ }
+ }
+ if(ok) {
+ for(i = 0; ok && i < 2; i++) {
+ /* integer version of the signal */
+ previous_is = encoder->guts->integer_signal_mid_side[i];
+ current_is = (int32*)malloc(sizeof(int32) * new_size);
+ if(0 == current_is) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ ok = 0;
+ }
+ else {
+ encoder->guts->integer_signal_mid_side[i] = current_is;
+ if(previous_is != 0)
+ free(previous_is);
+ }
+ /* real version of the signal */
+ previous_rs = encoder->guts->real_signal_mid_side[i];
+ current_rs = (real*)malloc(sizeof(real) * new_size);
+ if(0 == current_rs) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ ok = 0;
+ }
+ else {
+ encoder->guts->real_signal_mid_side[i] = current_rs;
+ if(previous_rs != 0)
+ free(previous_rs);
+ }
+ }
+ }
+ if(ok) {
+ for(i = 0; i < 2; i++) {
+ residual = (int32*)malloc(sizeof(int32) * new_size);
+ if(0 == residual) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ ok = 0;
+ }
+ else {
+ if(encoder->guts->residual[i] != 0)
+ free(encoder->guts->residual[i]);
+ encoder->guts->residual[i] = residual;
+ }
+ }
+ }
+ if(ok)
+ encoder->guts->input_capacity = new_size;
+
+ return ok;
+}
+
+FLAC__Encoder *FLAC__encoder_get_new_instance()
+{
+ FLAC__Encoder *encoder = (FLAC__Encoder*)malloc(sizeof(FLAC__Encoder));
+ if(encoder != 0) {
+ encoder->state = FLAC__ENCODER_UNINITIALIZED;
+ encoder->guts = 0;
+ }
+ return encoder;
+}
+
+void FLAC__encoder_free_instance(FLAC__Encoder *encoder)
+{
+ assert(encoder != 0);
+ free(encoder);
+}
+
+FLAC__EncoderState FLAC__encoder_init(FLAC__Encoder *encoder, FLAC__EncoderWriteStatus (*write_callback)(const FLAC__Encoder *encoder, const byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data), void (*metadata_callback)(const FLAC__Encoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data), void *client_data)
+{
+ unsigned i;
+
+ assert(sizeof(int) >= 4); /* we want to die right away if this is not true */
+ assert(encoder != 0);
+ assert(write_callback != 0);
+ assert(metadata_callback != 0);
+ assert(encoder->state == FLAC__ENCODER_UNINITIALIZED);
+ assert(encoder->guts == 0);
+
+ encoder->state = FLAC__ENCODER_OK;
+
+ if(encoder->channels == 0 || encoder->channels > FLAC__MAX_CHANNELS)
+ return encoder->state = FLAC__ENCODER_INVALID_NUMBER_OF_CHANNELS;
+
+ if(encoder->do_mid_side_stereo && encoder->channels != 2)
+ return encoder->state = FLAC__ENCODER_MID_SIDE_CHANNELS_MISMATCH;
+
+ if(encoder->do_mid_side_stereo && encoder->bits_per_sample > 16)
+ return encoder->state = FLAC__ENCODER_MID_SIDE_SAMPLE_SIZE_MISMATCH;
+
+ if(encoder->bits_per_sample == 0 || encoder->bits_per_sample > FLAC__MAX_BITS_PER_SAMPLE)
+ return encoder->state = FLAC__ENCODER_INVALID_BITS_PER_SAMPLE;
+
+ if(encoder->sample_rate == 0 || encoder->sample_rate > FLAC__MAX_SAMPLE_RATE)
+ return encoder->state = FLAC__ENCODER_INVALID_SAMPLE_RATE;
+
+ if(encoder->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->blocksize > FLAC__MAX_BLOCK_SIZE)
+ return encoder->state = FLAC__ENCODER_INVALID_BLOCK_SIZE;
+
+ if(encoder->blocksize < encoder->max_lpc_order)
+ return encoder->state = FLAC__ENCODER_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER;
+
+ if(encoder->qlp_coeff_precision == 0) {
+ if(encoder->bits_per_sample < 16) {
+ /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */
+ /* @@@ until then we'll make a guess */
+ encoder->qlp_coeff_precision = max(5, 2 + encoder->bits_per_sample / 2);
+ }
+ else if(encoder->bits_per_sample == 16) {
+ if(encoder->blocksize <= 192)
+ encoder->qlp_coeff_precision = 7;
+ else if(encoder->blocksize <= 384)
+ encoder->qlp_coeff_precision = 8;
+ else if(encoder->blocksize <= 576)
+ encoder->qlp_coeff_precision = 9;
+ else if(encoder->blocksize <= 1152)
+ encoder->qlp_coeff_precision = 10;
+ else if(encoder->blocksize <= 2304)
+ encoder->qlp_coeff_precision = 11;
+ else if(encoder->blocksize <= 4608)
+ encoder->qlp_coeff_precision = 12;
+ else
+ encoder->qlp_coeff_precision = 13;
+ }
+ else {
+ encoder->qlp_coeff_precision = min(13, 8*sizeof(int32) - encoder->bits_per_sample - 1);
+ }
+ }
+ else if(encoder->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->qlp_coeff_precision + encoder->bits_per_sample >= 8*sizeof(uint32))
+ return encoder->state = FLAC__ENCODER_INVALID_QLP_COEFF_PRECISION;
+
+ if(encoder->streamable_subset) {
+ if(encoder->bits_per_sample != 8 && encoder->bits_per_sample != 12 && encoder->bits_per_sample != 16 && encoder->bits_per_sample != 20 && encoder->bits_per_sample != 24)
+ return encoder->state = FLAC__ENCODER_NOT_STREAMABLE;
+ if(encoder->sample_rate > 655350)
+ return encoder->state = FLAC__ENCODER_NOT_STREAMABLE;
+ }
+
+ if(encoder->rice_optimization_level >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ encoder->rice_optimization_level = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
+
+ encoder->guts = (FLAC__EncoderPrivate*)malloc(sizeof(FLAC__EncoderPrivate));
+ if(encoder->guts == 0)
+ return encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+
+ encoder->guts->input_capacity = 0;
+ for(i = 0; i < encoder->channels; i++) {
+ encoder->guts->integer_signal[i] = 0;
+ encoder->guts->real_signal[i] = 0;
+ }
+ for(i = 0; i < 2; i++) {
+ encoder->guts->integer_signal_mid_side[i] = 0;
+ encoder->guts->real_signal_mid_side[i] = 0;
+ }
+ encoder->guts->residual[0] = 0;
+ encoder->guts->residual[1] = 0;
+ encoder->guts->best_residual = 0;
+ encoder->guts->current_frame_can_do_mid_side = true;
+ encoder->guts->current_sample_number = 0;
+ encoder->guts->current_frame_number = 0;
+
+ if(!encoder_resize_buffers_(encoder, encoder->blocksize)) {
+ /* the above function sets the state for us in case of an error */
+ return encoder->state;
+ }
+ FLAC__bitbuffer_init(&encoder->guts->frame);
+ encoder->guts->write_callback = write_callback;
+ encoder->guts->metadata_callback = metadata_callback;
+ encoder->guts->client_data = client_data;
+
+ /*
+ * write the stream header
+ */
+ if(!FLAC__bitbuffer_clear(&encoder->guts->frame))
+ return encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(&encoder->guts->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN))
+ return encoder->state = FLAC__ENCODER_FRAMING_ERROR;
+
+ encoder->guts->metadata.type = FLAC__METADATA_TYPE_ENCODING;
+ encoder->guts->metadata.is_last = true;
+ encoder->guts->metadata.length = FLAC__STREAM_METADATA_ENCODING_LENGTH;
+ encoder->guts->metadata.data.encoding.min_blocksize = encoder->blocksize; /* this encoder uses the same blocksize for the whole stream */
+ encoder->guts->metadata.data.encoding.max_blocksize = encoder->blocksize;
+ encoder->guts->metadata.data.encoding.min_framesize = 0; /* we don't know this yet; have to fill it in later */
+ encoder->guts->metadata.data.encoding.max_framesize = 0; /* we don't know this yet; have to fill it in later */
+ encoder->guts->metadata.data.encoding.sample_rate = encoder->sample_rate;
+ encoder->guts->metadata.data.encoding.channels = encoder->channels;
+ encoder->guts->metadata.data.encoding.bits_per_sample = encoder->bits_per_sample;
+ encoder->guts->metadata.data.encoding.total_samples = 0; /* we don't know this yet; have to fill it in later */
+ if(!FLAC__add_metadata_block(&encoder->guts->metadata, &encoder->guts->frame))
+ return encoder->state = FLAC__ENCODER_FRAMING_ERROR;
+
+ assert(encoder->guts->frame.bits == 0); /* assert that we're byte-aligned before writing */
+ assert(encoder->guts->frame.total_consumed_bits == 0); /* assert that no reading of the buffer was done */
+ if(encoder->guts->write_callback(encoder, encoder->guts->frame.buffer, encoder->guts->frame.bytes, 0, encoder->guts->current_frame_number, encoder->guts->client_data) != FLAC__ENCODER_WRITE_OK)
+ return encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_WRITING;
+
+ /* now that the metadata block is written, we can init this to an absurdly-high value */
+ encoder->guts->metadata.data.encoding.min_framesize = (1u << FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN) - 1;
+
+ return encoder->state;
+}
+
+void FLAC__encoder_finish(FLAC__Encoder *encoder)
+{
+ unsigned i;
+
+ assert(encoder != 0);
+ if(encoder->state == FLAC__ENCODER_UNINITIALIZED)
+ return;
+ if(encoder->guts->current_sample_number != 0) {
+ encoder->blocksize = encoder->guts->current_sample_number;
+ encoder_process_frame_(encoder, true); /* true => is last frame */
+ }
+ encoder->guts->metadata_callback(encoder, &encoder->guts->metadata, encoder->guts->client_data);
+ if(encoder->guts != 0) {
+ for(i = 0; i < encoder->channels; i++) {
+ if(encoder->guts->integer_signal[i] != 0) {
+ free(encoder->guts->integer_signal[i]);
+ encoder->guts->integer_signal[i] = 0;
+ }
+ if(encoder->guts->real_signal[i] != 0) {
+ free(encoder->guts->real_signal[i]);
+ encoder->guts->real_signal[i] = 0;
+ }
+ }
+ for(i = 0; i < 2; i++) {
+ if(encoder->guts->integer_signal_mid_side[i] != 0) {
+ free(encoder->guts->integer_signal_mid_side[i]);
+ encoder->guts->integer_signal_mid_side[i] = 0;
+ }
+ if(encoder->guts->real_signal_mid_side[i] != 0) {
+ free(encoder->guts->real_signal_mid_side[i]);
+ encoder->guts->real_signal_mid_side[i] = 0;
+ }
+ }
+ for(i = 0; i < 2; i++) {
+ if(encoder->guts->residual[i] != 0) {
+ free(encoder->guts->residual[i]);
+ encoder->guts->residual[i] = 0;
+ }
+ }
+ FLAC__bitbuffer_free(&encoder->guts->frame);
+ free(encoder->guts);
+ encoder->guts = 0;
+ }
+ encoder->state = FLAC__ENCODER_UNINITIALIZED;
+}
+
+bool FLAC__encoder_process(FLAC__Encoder *encoder, const int32 *buf[], unsigned samples)
+{
+ unsigned i, j, channel;
+ int32 x, mid, side;
+ const bool ms = encoder->do_mid_side_stereo && encoder->channels == 2;
+ const int32 min_side = -((int64)1 << (encoder->bits_per_sample-1));
+ const int32 max_side = ((int64)1 << (encoder->bits_per_sample-1)) - 1;
+
+ assert(encoder != 0);
+ assert(encoder->state == FLAC__ENCODER_OK);
+
+ j = 0;
+ do {
+ for(i = encoder->guts->current_sample_number; i < encoder->blocksize && j < samples; i++, j++) {
+ for(channel = 0; channel < encoder->channels; channel++) {
+ x = buf[channel][j];
+ encoder->guts->integer_signal[channel][i] = x;
+ encoder->guts->real_signal[channel][i] = (real)x;
+ }
+ if(ms && encoder->guts->current_frame_can_do_mid_side) {
+ side = buf[0][j] - buf[1][j];
+ if(side < min_side || side > max_side) {
+ encoder->guts->current_frame_can_do_mid_side = false;
+ }
+ else {
+ mid = (buf[0][j] + buf[1][j]) >> 1; /* NOTE: not the same as divide-by-two ! */
+ encoder->guts->integer_signal_mid_side[0][i] = mid;
+ encoder->guts->integer_signal_mid_side[1][i] = side;
+ encoder->guts->real_signal_mid_side[0][i] = (real)mid;
+ encoder->guts->real_signal_mid_side[1][i] = (real)side;
+ }
+ }
+ encoder->guts->current_sample_number++;
+ }
+ if(i == encoder->blocksize) {
+ if(!encoder_process_frame_(encoder, false)) /* false => not last frame */
+ return false;
+ }
+ } while(j < samples);
+
+ return true;
+}
+
+/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */
+bool FLAC__encoder_process_interleaved(FLAC__Encoder *encoder, const int32 buf[], unsigned samples)
+{
+ unsigned i, j, k, channel;
+ int32 x, left = 0, mid, side;
+ const bool ms = encoder->do_mid_side_stereo && encoder->channels == 2;
+ const int32 min_side = -((int64)1 << (encoder->bits_per_sample-1));
+ const int32 max_side = ((int64)1 << (encoder->bits_per_sample-1)) - 1;
+
+ assert(encoder != 0);
+ assert(encoder->state == FLAC__ENCODER_OK);
+
+ j = k = 0;
+ do {
+ for(i = encoder->guts->current_sample_number; i < encoder->blocksize && j < samples; i++, j++, k++) {
+ for(channel = 0; channel < encoder->channels; channel++, k++) {
+ x = buf[k];
+ encoder->guts->integer_signal[channel][i] = x;
+ encoder->guts->real_signal[channel][i] = (real)x;
+ if(ms && encoder->guts->current_frame_can_do_mid_side) {
+ if(channel == 0) {
+ left = x;
+ }
+ else {
+ side = left - x;
+ if(side < min_side || side > max_side) {
+ encoder->guts->current_frame_can_do_mid_side = false;
+ }
+ else {
+ mid = (left + x) >> 1; /* NOTE: not the same as divide-by-two ! */
+ encoder->guts->integer_signal_mid_side[0][i] = mid;
+ encoder->guts->integer_signal_mid_side[1][i] = side;
+ encoder->guts->real_signal_mid_side[0][i] = (real)mid;
+ encoder->guts->real_signal_mid_side[1][i] = (real)side;
+ }
+ }
+ }
+ }
+ encoder->guts->current_sample_number++;
+ }
+ if(i == encoder->blocksize) {
+ if(!encoder_process_frame_(encoder, false)) /* false => not last frame */
+ return false;
+ }
+ } while(j < samples);
+
+ return true;
+}
+
+bool encoder_process_frame_(FLAC__Encoder *encoder, bool is_last_frame)
+{
+ FLAC__FrameHeader frame_header;
+ FLAC__BitBuffer *smallest_frame;
+
+ assert(encoder->state == FLAC__ENCODER_OK);
+
+ /*
+ * First do a normal encoding pass
+ */
+ frame_header.blocksize = encoder->blocksize;
+ frame_header.sample_rate = encoder->sample_rate;
+ frame_header.channels = encoder->channels;
+ frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
+ frame_header.bits_per_sample = encoder->bits_per_sample;
+ frame_header.number.frame_number = encoder->guts->current_frame_number;
+
+ if(!FLAC__bitbuffer_clear(&encoder->guts->frame)) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame)) {
+ encoder->state = FLAC__ENCODER_FRAMING_ERROR;
+ return false;
+ }
+
+ if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, encoder->guts->integer_signal, encoder->guts->real_signal, &encoder->guts->frame))
+ return false;
+
+ smallest_frame = &encoder->guts->frame;
+
+ /*
+ * Now try a mid-side version if necessary; otherwise, just use the previous step's frame
+ */
+ if(encoder->do_mid_side_stereo && encoder->guts->current_frame_can_do_mid_side) {
+ int32 *integer_signal[2];
+ real *real_signal[2];
+
+ assert(encoder->channels == 2);
+
+ /* mid-side */
+ frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+ if(!FLAC__bitbuffer_clear(&encoder->guts->frame_mid_side)) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame_mid_side)) {
+ encoder->state = FLAC__ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ integer_signal[0] = encoder->guts->integer_signal_mid_side[0]; /* mid channel */
+ integer_signal[1] = encoder->guts->integer_signal_mid_side[1]; /* side channel */
+ real_signal[0] = encoder->guts->real_signal_mid_side[0]; /* mid channel */
+ real_signal[1] = encoder->guts->real_signal_mid_side[1]; /* side channel */
+ if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, integer_signal, real_signal, &encoder->guts->frame_mid_side))
+ return false;
+ if(encoder->guts->frame_mid_side.total_bits < smallest_frame->total_bits)
+ smallest_frame = &encoder->guts->frame_mid_side;
+
+ /* left-side */
+ frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+ if(!FLAC__bitbuffer_clear(&encoder->guts->frame_left_side)) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame_left_side)) {
+ encoder->state = FLAC__ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ integer_signal[0] = encoder->guts->integer_signal[0]; /* left channel */
+ integer_signal[1] = encoder->guts->integer_signal_mid_side[1]; /* side channel */
+ real_signal[0] = encoder->guts->real_signal[0]; /* left channel */
+ real_signal[1] = encoder->guts->real_signal_mid_side[1]; /* side channel */
+ if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, integer_signal, real_signal, &encoder->guts->frame_left_side))
+ return false;
+ if(encoder->guts->frame_left_side.total_bits < smallest_frame->total_bits)
+ smallest_frame = &encoder->guts->frame_left_side;
+
+ /* right-side */
+ frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+ if(!FLAC__bitbuffer_clear(&encoder->guts->frame_right_side)) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__frame_add_header(&frame_header, encoder->streamable_subset, is_last_frame, &encoder->guts->frame_right_side)) {
+ encoder->state = FLAC__ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ integer_signal[0] = encoder->guts->integer_signal_mid_side[1]; /* side channel */
+ integer_signal[1] = encoder->guts->integer_signal[1]; /* right channel */
+ real_signal[0] = encoder->guts->real_signal_mid_side[1]; /* side channel */
+ real_signal[1] = encoder->guts->real_signal[1]; /* right channel */
+ if(!encoder_process_subframes_(encoder, is_last_frame, &frame_header, encoder->channels, integer_signal, real_signal, &encoder->guts->frame_right_side))
+ return false;
+ if(encoder->guts->frame_right_side.total_bits < smallest_frame->total_bits)
+ smallest_frame = &encoder->guts->frame_right_side;
+ }
+
+ /*
+ * Zero-pad the frame to a byte_boundary
+ */
+ if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(smallest_frame)) {
+ encoder->state = FLAC__ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ /*
+ * Write it
+ */
+ assert(smallest_frame->bits == 0); /* assert that we're byte-aligned before writing */
+ assert(smallest_frame->total_consumed_bits == 0); /* assert that no reading of the buffer was done */
+ if(encoder->guts->write_callback(encoder, smallest_frame->buffer, smallest_frame->bytes, encoder->blocksize, encoder->guts->current_frame_number, encoder->guts->client_data) != FLAC__ENCODER_WRITE_OK) {
+ encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_WRITING;
+ return false;
+ }
+
+ /*
+ * Get ready for the next frame
+ */
+ encoder->guts->current_frame_can_do_mid_side = true;
+ encoder->guts->current_sample_number = 0;
+ encoder->guts->current_frame_number++;
+ encoder->guts->metadata.data.encoding.total_samples += (uint64)encoder->blocksize;
+ encoder->guts->metadata.data.encoding.min_framesize = min(smallest_frame->bytes, encoder->guts->metadata.data.encoding.min_framesize);
+ encoder->guts->metadata.data.encoding.max_framesize = max(smallest_frame->bytes, encoder->guts->metadata.data.encoding.max_framesize);
+
+ return true;
+}
+
+bool encoder_process_subframes_(FLAC__Encoder *encoder, bool is_last_frame, const FLAC__FrameHeader *frame_header, unsigned channels, const int32 *integer_signal[], const real *real_signal[], FLAC__BitBuffer *frame)
+{
+ real fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+ real lpc_residual_bits_per_sample;
+ real autoc[FLAC__MAX_LPC_ORDER+1];
+ real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER];
+ real lpc_error[FLAC__MAX_LPC_ORDER];
+ unsigned channel;
+ unsigned min_lpc_order, max_lpc_order, lpc_order;
+ unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
+ unsigned max_partition_order;
+ unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
+ unsigned rice_parameter;
+ unsigned candidate_bits, best_bits;
+
+ if(is_last_frame) {
+ max_partition_order = 0;
+ }
+ else {
+ unsigned limit = 0, b = encoder->blocksize;
+ while(!(b & 1)) {
+ limit++;
+ b >>= 1;
+ }
+ max_partition_order = min(encoder->rice_optimization_level, limit);
+ }
+
+ for(channel = 0; channel < channels; channel++) {
+ /* verbatim subframe is the baseline against which we measure other compressed subframes */
+ best_bits = encoder_evaluate_verbatim_subframe_(frame_header->blocksize, frame_header->bits_per_sample, &(encoder->guts->best_subframe));
+
+ if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
+ /* check for constant subframe */
+ guess_fixed_order = FLAC__fixed_compute_best_predictor(integer_signal[channel]+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+ if(fixed_residual_bits_per_sample[1] == 0.0) {
+ candidate_bits = encoder_evaluate_constant_subframe_(integer_signal[channel][0], frame_header->bits_per_sample, &(encoder->guts->candidate_subframe));
+ if(candidate_bits < best_bits) {
+ encoder_promote_candidate_subframe_(encoder);
+ best_bits = candidate_bits;
+ }
+ }
+ else {
+ /* encode fixed */
+ if(encoder->do_exhaustive_model_search) {
+ min_fixed_order = 0;
+ max_fixed_order = FLAC__MAX_FIXED_ORDER;
+ }
+ else {
+ min_fixed_order = max_fixed_order = guess_fixed_order;
+ }
+ for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) {
+ if(fixed_residual_bits_per_sample[fixed_order] >= (real)frame_header->bits_per_sample)
+ continue; /* don't even try */
+ rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (unsigned)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0;
+ if(rice_parameter >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ rice_parameter = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN) - 1;
+ candidate_bits = encoder_evaluate_fixed_subframe_(integer_signal[channel], encoder->guts->residual[!encoder->guts->best_residual], frame_header->blocksize, frame_header->bits_per_sample, fixed_order, rice_parameter, max_partition_order, &(encoder->guts->candidate_subframe));
+ if(candidate_bits < best_bits) {
+ encoder_promote_candidate_subframe_(encoder);
+ best_bits = candidate_bits;
+ }
+ }
+
+ /* encode lpc */
+ if(encoder->max_lpc_order > 0) {
+ if(encoder->max_lpc_order >= frame_header->blocksize)
+ max_lpc_order = frame_header->blocksize-1;
+ else
+ max_lpc_order = encoder->max_lpc_order;
+ if(max_lpc_order > 0) {
+ FLAC__lpc_compute_autocorrelation(real_signal[channel], frame_header->blocksize, max_lpc_order+1, autoc);
+ FLAC__lpc_compute_lp_coefficients(autoc, max_lpc_order, lp_coeff, lpc_error);
+ if(encoder->do_exhaustive_model_search) {
+ min_lpc_order = 1;
+ }
+ else {
+ unsigned guess_lpc_order = FLAC__lpc_compute_best_order(lpc_error, max_lpc_order, frame_header->blocksize, frame_header->bits_per_sample);
+ min_lpc_order = max_lpc_order = guess_lpc_order;
+ }
+ if(encoder->do_qlp_coeff_prec_search) {
+ min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
+ max_qlp_coeff_precision = 32 - frame_header->bits_per_sample - 1;
+ }
+ else {
+ min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->qlp_coeff_precision;
+ }
+ for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) {
+ lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize);
+ if(lpc_residual_bits_per_sample >= (real)frame_header->bits_per_sample)
+ continue; /* don't even try */
+ rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0;
+ if(rice_parameter >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ rice_parameter = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN) - 1;
+ for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) {
+ candidate_bits = encoder_evaluate_lpc_subframe_(integer_signal[channel], encoder->guts->residual[!encoder->guts->best_residual], lp_coeff[lpc_order-1], frame_header->blocksize, frame_header->bits_per_sample, lpc_order, qlp_coeff_precision, rice_parameter, max_partition_order, &(encoder->guts->candidate_subframe));
+ if(candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */
+ if(candidate_bits < best_bits) {
+ encoder_promote_candidate_subframe_(encoder);
+ best_bits = candidate_bits;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* add the best subframe */
+ switch(encoder->guts->best_subframe.type) {
+ case FLAC__SUBFRAME_TYPE_CONSTANT:
+ if(!encoder_generate_constant_subframe_(&(encoder->guts->best_subframe), frame_header->bits_per_sample, frame)) {
+ encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING;
+ return false;
+ }
+ break;
+ case FLAC__SUBFRAME_TYPE_FIXED:
+ if(!encoder_generate_fixed_subframe_(&(encoder->guts->best_subframe), encoder->guts->residual[encoder->guts->best_residual], frame_header->blocksize, frame_header->bits_per_sample, frame)) {
+ encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING;
+ return false;
+ }
+ break;
+ case FLAC__SUBFRAME_TYPE_LPC:
+ if(!encoder_generate_lpc_subframe_(&(encoder->guts->best_subframe), encoder->guts->residual[encoder->guts->best_residual], frame_header->blocksize, frame_header->bits_per_sample, frame)) {
+ encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING;
+ return false;
+ }
+ break;
+ case FLAC__SUBFRAME_TYPE_VERBATIM:
+ if(!encoder_generate_verbatim_subframe_(&(encoder->guts->best_subframe), integer_signal[channel], frame_header->blocksize, frame_header->bits_per_sample, frame)) {
+ encoder->state = FLAC__ENCODER_FATAL_ERROR_WHILE_ENCODING;
+ return false;
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+unsigned encoder_evaluate_constant_subframe_(const int32 signal, unsigned bits_per_sample, FLAC__SubframeHeader *subframe)
+{
+ subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT;
+ subframe->data.constant.value = signal;
+
+ return 8 + bits_per_sample;
+}
+
+unsigned encoder_evaluate_fixed_subframe_(const int32 signal[], int32 residual[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe)
+{
+ unsigned i, residual_bits;
+ const unsigned residual_samples = blocksize - order;
+
+ FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
+
+ subframe->type = FLAC__SUBFRAME_TYPE_FIXED;
+
+ subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+
+ residual_bits = encoder_find_best_partition_order_(residual, residual_samples, order, rice_parameter, max_partition_order, &subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.parameters);
+
+ subframe->data.fixed.order = order;
+ for(i = 0; i < order; i++)
+ subframe->data.fixed.warmup[i] = signal[i];
+
+ return 8 + (order * bits_per_sample) + residual_bits;
+}
+
+unsigned encoder_evaluate_lpc_subframe_(const int32 signal[], int32 residual[], const real lp_coeff[], unsigned blocksize, unsigned bits_per_sample, unsigned order, unsigned qlp_coeff_precision, unsigned rice_parameter, unsigned max_partition_order, FLAC__SubframeHeader *subframe)
+{
+ int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+ unsigned i, residual_bits;
+ int quantization, ret;
+ const unsigned residual_samples = blocksize - order;
+
+ ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, bits_per_sample, qlp_coeff, &quantization);
+ if(ret != 0)
+ return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */
+
+ FLAC__lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+
+ subframe->type = FLAC__SUBFRAME_TYPE_LPC;
+
+ subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+
+ residual_bits = encoder_find_best_partition_order_(residual, residual_samples, order, rice_parameter, max_partition_order, &subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.parameters);
+
+ subframe->data.lpc.order = order;
+ subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision;
+ subframe->data.lpc.quantization_level = quantization;
+ memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(int32)*FLAC__MAX_LPC_ORDER);
+ for(i = 0; i < order; i++)
+ subframe->data.lpc.warmup[i] = signal[i];
+
+ return 8 + 9 + (order * (qlp_coeff_precision + bits_per_sample)) + residual_bits;
+}
+
+unsigned encoder_evaluate_verbatim_subframe_(unsigned blocksize, unsigned bits_per_sample, FLAC__SubframeHeader *subframe)
+{
+ subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+ return 8 + (blocksize * bits_per_sample);
+}
+
+unsigned encoder_find_best_partition_order_(int32 residual[], unsigned residual_samples, unsigned predictor_order, unsigned rice_parameter, unsigned max_partition_order, unsigned *best_partition_order, unsigned best_parameters[])
+{
+ unsigned residual_bits, best_residual_bits = 0;
+ unsigned partition_order;
+ unsigned best_parameters_index = 0, parameters[2][1 << FLAC__MAX_RICE_PARTITION_ORDER];
+
+ for(partition_order = 0; partition_order <= max_partition_order; partition_order++) {
+ if(!encoder_set_partitioned_rice_(residual, residual_samples, predictor_order, rice_parameter, partition_order, parameters[!best_parameters_index], &residual_bits)) {
+ assert(best_residual_bits != 0);
+ break;
+ }
+ if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
+ best_residual_bits = residual_bits;
+ *best_partition_order = partition_order;
+ best_parameters_index = !best_parameters_index;
+ }
+ }
+ memcpy(best_parameters, parameters[best_parameters_index], sizeof(unsigned)*(1<<(*best_partition_order)));
+
+ return best_residual_bits;
+}
+
+bool encoder_generate_constant_subframe_(const FLAC__SubframeHeader *header, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer)
+{
+ assert(header->type == FLAC__SUBFRAME_TYPE_CONSTANT);
+ return FLAC__subframe_add_constant(bits_per_sample, header, bitbuffer);
+}
+
+bool encoder_generate_fixed_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer)
+{
+ assert(header->type == FLAC__SUBFRAME_TYPE_FIXED);
+ return FLAC__subframe_add_fixed(residual, blocksize - header->data.fixed.order, bits_per_sample, header, bitbuffer);
+}
+
+bool encoder_generate_lpc_subframe_(const FLAC__SubframeHeader *header, int32 residual[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer)
+{
+ assert(header->type == FLAC__SUBFRAME_TYPE_LPC);
+ return FLAC__subframe_add_lpc(residual, blocksize - header->data.lpc.order, bits_per_sample, header, bitbuffer);
+}
+
+bool encoder_generate_verbatim_subframe_(const FLAC__SubframeHeader *header, const int32 signal[], unsigned blocksize, unsigned bits_per_sample, FLAC__BitBuffer *bitbuffer)
+{
+ assert(header->type == FLAC__SUBFRAME_TYPE_VERBATIM);
+#ifdef NDEBUG
+ (void)header; /* silence compiler warning about unused parameter */
+#endif
+ return FLAC__subframe_add_verbatim(signal, blocksize, bits_per_sample, bitbuffer);
+}
+
+void encoder_promote_candidate_subframe_(FLAC__Encoder *encoder)
+{
+ assert(encoder->state == FLAC__ENCODER_OK);
+ encoder->guts->best_subframe = encoder->guts->candidate_subframe;
+ encoder->guts->best_residual = !encoder->guts->best_residual;
+}
+
+bool encoder_set_partitioned_rice_(const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameter, const unsigned partition_order, unsigned parameters[], unsigned *bits)
+{
+ unsigned bits_ = 2 + 3;
+
+ if(partition_order == 0) {
+ unsigned i;
+ parameters[0] = rice_parameter;
+ bits_ += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+ for(i = 0; i < residual_samples; i++)
+ bits_ += RICE_BITS(residual[i], rice_parameter);
+ }
+ else {
+ unsigned i, j, k = 0, k_last = 0, z;
+ unsigned mean;
+ unsigned parameter, partition_samples;
+ const unsigned max_parameter = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN) - 1;
+ for(i = 0; i < (1u<<partition_order); i++) {
+ partition_samples = (residual_samples+predictor_order) >> partition_order;
+ if(i == 0) {
+ if(partition_samples <= predictor_order)
+ return false;
+ else
+ partition_samples -= predictor_order;
+ }
+ mean = partition_samples >> 1;
+ for(j = 0; j < partition_samples; j++, k++)
+ mean += ((residual[k] < 0)? (unsigned)(-residual[k]) : (unsigned)residual[k]);
+ mean /= partition_samples;
+ z = 0x80000000;
+ for(j = 0; j < 32; j++, z >>= 1)
+ if(mean & z)
+ break;
+ parameter = j > 31? 0 : 32 - j - 1;
+ if(parameter > max_parameter)
+ parameter = max_parameter;
+ parameters[i] = parameter;
+ bits_ += FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+ for(j = k_last; j < k; j++)
+ bits_ += RICE_BITS(residual[j], parameter);
+ k_last = k;
+ }
+ }
+
+ *bits = bits_;
+ return true;
+}
diff --git a/src/libFLAC/encoder_framing.c b/src/libFLAC/encoder_framing.c
new file mode 100644
index 0000000..69201d7
--- /dev/null
+++ b/src/libFLAC/encoder_framing.c
@@ -0,0 +1,340 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include "private/encoder_framing.h"
+#include "private/crc.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static bool subframe_add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method);
+static bool subframe_add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned partition_order);
+
+bool FLAC__add_metadata_block(const FLAC__StreamMetaData *metadata, FLAC__BitBuffer *bb)
+{
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
+ return false;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
+ return false;
+
+ assert(metadata->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->length, FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+
+ switch(metadata->type) {
+ case FLAC__METADATA_TYPE_ENCODING:
+ assert(metadata->data.encoding.min_blocksize < (1u << FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.min_blocksize, FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN))
+ return false;
+ assert(metadata->data.encoding.max_blocksize < (1u << FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.max_blocksize, FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN))
+ return false;
+ assert(metadata->data.encoding.min_framesize < (1u << FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.min_framesize, FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN))
+ return false;
+ assert(metadata->data.encoding.max_framesize < (1u << FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.max_framesize, FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN))
+ return false;
+ assert(metadata->data.encoding.sample_rate > 0);
+ assert(metadata->data.encoding.sample_rate < (1u << FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.sample_rate, FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN))
+ return false;
+ assert(metadata->data.encoding.channels > 0);
+ assert(metadata->data.encoding.channels <= (1u << FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.channels-1, FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN))
+ return false;
+ assert(metadata->data.encoding.bits_per_sample > 0);
+ assert(metadata->data.encoding.bits_per_sample <= (1u << FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN));
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, metadata->data.encoding.bits_per_sample-1, FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN))
+ return false;
+ if(!FLAC__bitbuffer_write_raw_uint64(bb, metadata->data.encoding.total_samples, FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN))
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+
+ return true;
+}
+
+bool FLAC__frame_add_header(const FLAC__FrameHeader *header, bool streamable_subset, bool is_last_block, FLAC__BitBuffer *bb)
+{
+ unsigned u, crc_start, blocksize_hint, sample_rate_hint;
+ byte crc;
+
+ assert(bb->bits == 0); /* assert that we're byte-aligned before writing */
+
+ crc_start = bb->bytes;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
+ return false;
+
+ assert(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE);
+ blocksize_hint = 0;
+ switch(header->blocksize) {
+ case 192: u = 1; break;
+ case 576: u = 2; break;
+ case 1152: u = 3; break;
+ case 2304: u = 4; break;
+ case 4608: u = 5; break;
+ default:
+ if(streamable_subset || is_last_block) {
+ if(header->blocksize <= 0x100)
+ blocksize_hint = u = 6;
+ else
+ blocksize_hint = u = 7;
+ }
+ else
+ u = 0;
+ break;
+ }
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN))
+ return false;
+
+ assert(header->sample_rate > 0 && header->sample_rate < (1u << FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN));
+ sample_rate_hint = 0;
+ switch(header->sample_rate) {
+ case 8000: u = 4; break;
+ case 16000: u = 5; break;
+ case 22050: u = 6; break;
+ case 24000: u = 7; break;
+ case 32000: u = 8; break;
+ case 44100: u = 9; break;
+ case 48000: u = 10; break;
+ case 96000: u = 11; break;
+ default:
+ if(streamable_subset) {
+ if(header->sample_rate % 1000 == 0)
+ sample_rate_hint = u = 12;
+ else if(header->sample_rate % 10 == 0)
+ sample_rate_hint = u = 14;
+ else
+ sample_rate_hint = u = 13;
+ }
+ else
+ u = 0;
+ break;
+ }
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN))
+ return false;
+
+ assert(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS);
+ switch(header->channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ u = header->channels - 1;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ assert(header->channels == 2);
+ u = 8;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ assert(header->channels == 2);
+ u = 9;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ assert(header->channels == 2);
+ u = 10;
+ break;
+ default:
+ assert(0);
+ }
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN))
+ return false;
+
+ assert(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN));
+ switch(header->bits_per_sample) {
+ case 8 : u = 1; break;
+ case 12: u = 2; break;
+ case 16: u = 4; break;
+ case 20: u = 5; break;
+ case 24: u = 6; break;
+ default: u = 0; break;
+ }
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
+ return false;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
+ return false;
+
+ if(!FLAC__bitbuffer_write_utf8_uint32(bb, header->number.frame_number))
+ return false;
+
+ if(blocksize_hint)
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, header->blocksize-1, (blocksize_hint==6)? 8:16))
+ return false;
+
+ switch(sample_rate_hint) {
+ case 12:
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 1000, 8))
+ return false;
+ break;
+ case 13:
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate, 16))
+ return false;
+ break;
+ case 14:
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, header->sample_rate / 10, 16))
+ return false;
+ break;
+ }
+
+ /* write the CRC */
+ assert(bb->buffer[crc_start] == 0xff); /* MAGIC NUMBER for the first byte of the sync code */
+ assert(bb->bits == 0); /* assert that we're byte-aligned */
+ crc = FLAC__crc8(bb->buffer+crc_start, bb->bytes-crc_start);
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, crc, FLAC__FRAME_HEADER_CRC8_LEN))
+ return false;
+
+ return true;
+}
+
+bool FLAC__subframe_add_constant(unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb)
+{
+ bool ok;
+
+ ok =
+ FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_CONSTANT, FLAC__SUBFRAME_HEADER_TYPE_LEN) &&
+ FLAC__bitbuffer_write_raw_int32(bb, subframe->data.constant.value, bits_per_sample)
+ ;
+
+ return ok;
+}
+
+bool FLAC__subframe_add_fixed(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb)
+{
+ unsigned i;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_FIXED | (subframe->data.fixed.order<<1), FLAC__SUBFRAME_HEADER_TYPE_LEN))
+ return false;
+
+ for(i = 0; i < subframe->data.fixed.order; i++)
+ if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.fixed.warmup[i], bits_per_sample))
+ return false;
+
+ if(!subframe_add_entropy_coding_method_(bb, &subframe->data.fixed.entropy_coding_method))
+ return false;
+ switch(subframe->data.fixed.entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!subframe_add_residual_partitioned_rice_(bb, residual, residual_samples, subframe->data.fixed.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.parameters, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order))
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+
+ return true;
+}
+
+bool FLAC__subframe_add_lpc(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb)
+{
+ unsigned i;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_LPC | ((subframe->data.lpc.order-1)<<1), FLAC__SUBFRAME_HEADER_TYPE_LEN))
+ return false;
+
+ for(i = 0; i < subframe->data.lpc.order; i++)
+ if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.lpc.warmup[i], bits_per_sample))
+ return false;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, subframe->data.lpc.qlp_coeff_precision-1, FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN))
+ return false;
+ if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.lpc.quantization_level, FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN))
+ return false;
+ for(i = 0; i < subframe->data.lpc.order; i++)
+ if(!FLAC__bitbuffer_write_raw_int32(bb, subframe->data.lpc.qlp_coeff[i], subframe->data.lpc.qlp_coeff_precision))
+ return false;
+
+ if(!subframe_add_entropy_coding_method_(bb, &subframe->data.lpc.entropy_coding_method))
+ return false;
+ switch(subframe->data.lpc.entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!subframe_add_residual_partitioned_rice_(bb, residual, residual_samples, subframe->data.lpc.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.parameters, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order))
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+
+ return true;
+}
+
+bool FLAC__subframe_add_verbatim(const int32 signal[], unsigned samples, unsigned bits_per_sample, FLAC__BitBuffer *bb)
+{
+ unsigned i;
+
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, FLAC__SUBFRAME_HEADER_TYPE_VERBATIM, FLAC__SUBFRAME_HEADER_TYPE_LEN))
+ return false;
+
+ for(i = 0; i < samples; i++)
+ if(!FLAC__bitbuffer_write_raw_int32(bb, signal[i], bits_per_sample))
+ return false;
+
+ return true;
+}
+
+bool subframe_add_entropy_coding_method_(FLAC__BitBuffer *bb, const FLAC__EntropyCodingMethod *method)
+{
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+ return false;
+ switch(method->type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+ return true;
+}
+
+bool subframe_add_residual_partitioned_rice_(FLAC__BitBuffer *bb, const int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned partition_order)
+{
+ if(partition_order == 0) {
+ unsigned i;
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, rice_parameters[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ return false;
+ for(i = 0; i < residual_samples; i++) {
+ if(!FLAC__bitbuffer_write_rice_signed(bb, residual[i], rice_parameters[0]))
+ return false;
+ }
+ return true;
+ }
+ else {
+ unsigned i, j, k = 0, k_last = 0;
+ unsigned partition_samples;
+ for(i = 0; i < (1u<<partition_order); i++) {
+ if(!FLAC__bitbuffer_write_raw_uint32(bb, rice_parameters[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ return false;
+ partition_samples = (residual_samples+predictor_order) >> partition_order;
+ if(i == 0)
+ partition_samples -= predictor_order;
+ k += partition_samples;
+ for(j = k_last; j < k; j++)
+ if(!FLAC__bitbuffer_write_rice_signed(bb, residual[j], rice_parameters[i]))
+ return false;
+ k_last = k;
+ }
+ return true;
+ }
+}
diff --git a/src/libFLAC/file_decoder.c b/src/libFLAC/file_decoder.c
new file mode 100644
index 0000000..aed796c
--- /dev/null
+++ b/src/libFLAC/file_decoder.c
@@ -0,0 +1,403 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for strcmp() */
+#include "FLAC/file_decoder.h"
+#include "protected/stream_decoder.h"
+
+typedef struct FLAC__FileDecoderPrivate {
+ FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
+ void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+ void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+ void *client_data;
+ FILE *file;
+ FLAC__StreamDecoder *stream;
+ /* the rest of these are only used for seeking: */
+ FLAC__StreamMetaData_Encoding metadata; /* we keep this around so we can figure out how to seek quickly */
+ FLAC__FrameHeader last_frame_header; /* holds the info of the last frame we seeked to */
+ uint64 target_sample;
+} FLAC__FileDecoderPrivate;
+
+static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+static bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample);
+
+FLAC__FileDecoder *FLAC__file_decoder_get_new_instance()
+{
+ FLAC__FileDecoder *decoder = (FLAC__FileDecoder*)malloc(sizeof(FLAC__FileDecoder));
+ if(decoder != 0) {
+ decoder->state = FLAC__FILE_DECODER_UNINITIALIZED;
+ decoder->guts = 0;
+ }
+ return decoder;
+}
+
+void FLAC__file_decoder_free_instance(FLAC__FileDecoder *decoder)
+{
+ free(decoder);
+}
+
+FLAC__FileDecoderState FLAC__file_decoder_init(
+ FLAC__FileDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data),
+ void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data),
+ void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data),
+ void *client_data
+)
+{
+ assert(sizeof(int) >= 4); /* we want to die right away if this is not true */
+ assert(decoder != 0);
+ assert(write_callback != 0);
+ assert(metadata_callback != 0);
+ assert(error_callback != 0);
+ assert(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED);
+ assert(decoder->guts == 0);
+
+ decoder->state = FLAC__FILE_DECODER_OK;
+
+ decoder->guts = (FLAC__FileDecoderPrivate*)malloc(sizeof(FLAC__FileDecoderPrivate));
+ if(decoder->guts == 0)
+ return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR;
+
+ decoder->guts->write_callback = write_callback;
+ decoder->guts->metadata_callback = metadata_callback;
+ decoder->guts->error_callback = error_callback;
+ decoder->guts->client_data = client_data;
+ decoder->guts->stream = 0;
+
+ if(0 == strcmp(filename, "-"))
+ decoder->guts->file = stdin;
+ else
+ decoder->guts->file = fopen(filename, "rb");
+ if(decoder->guts->file == 0)
+ return decoder->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE;
+
+ decoder->guts->stream = FLAC__stream_decoder_get_new_instance();
+ if(FLAC__stream_decoder_init(decoder->guts->stream, read_callback_, write_callback_, metadata_callback_, error_callback_, decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+ return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; /* this is based on internal knowledge of FLAC__stream_decoder_init() */
+
+ return decoder->state;
+}
+
+void FLAC__file_decoder_finish(FLAC__FileDecoder *decoder)
+{
+ assert(decoder != 0);
+ if(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED)
+ return;
+ if(decoder->guts != 0) {
+ if(decoder->guts->file != 0 && decoder->guts->file != stdin)
+ fclose(decoder->guts->file);
+ if(decoder->guts->stream != 0) {
+ FLAC__stream_decoder_finish(decoder->guts->stream);
+ FLAC__stream_decoder_free_instance(decoder->guts->stream);
+ }
+ free(decoder->guts);
+ decoder->guts = 0;
+ }
+ decoder->state = FLAC__FILE_DECODER_UNINITIALIZED;
+}
+
+bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder)
+{
+ bool ret;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
+ return true;
+
+ assert(decoder->state == FLAC__FILE_DECODER_OK);
+
+ ret = FLAC__stream_decoder_process_whole_stream(decoder->guts->stream);
+ if(!ret)
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+
+ return ret;
+}
+
+bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder)
+{
+ bool ret;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
+ return true;
+
+ assert(decoder->state == FLAC__FILE_DECODER_OK);
+
+ ret = FLAC__stream_decoder_process_metadata(decoder->guts->stream);
+ if(!ret)
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+
+ return ret;
+}
+
+bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder)
+{
+ bool ret;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
+ return true;
+
+ assert(decoder->state == FLAC__FILE_DECODER_OK);
+
+ ret = FLAC__stream_decoder_process_one_frame(decoder->guts->stream);
+ if(!ret)
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+
+ return ret;
+}
+
+bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder)
+{
+ bool ret;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
+ return true;
+
+ assert(decoder->state == FLAC__FILE_DECODER_OK);
+
+ ret = FLAC__stream_decoder_process_remaining_frames(decoder->guts->stream);
+ if(!ret)
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+
+ return ret;
+}
+
+bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, uint64 sample)
+{
+ long filesize;
+
+ assert(decoder != 0);
+ assert(decoder->state == FLAC__FILE_DECODER_OK);
+
+ decoder->state = FLAC__FILE_DECODER_SEEKING;
+
+ if(!FLAC__stream_decoder_reset(decoder->guts->stream)) {
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+ return false;
+ }
+ /* get the file length */
+ if(0 != fseek(decoder->guts->file, 0, SEEK_END)) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ fflush(decoder->guts->file);
+ if(-1 == (filesize = ftell(decoder->guts->file))) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ /* rewind */
+ if(0 != fseek(decoder->guts->file, 0, SEEK_SET)) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!FLAC__stream_decoder_process_metadata(decoder->guts->stream)) {
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+ return false;
+ }
+ if(sample > decoder->guts->metadata.total_samples) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+
+ return seek_to_absolute_sample_(decoder, filesize, sample);
+}
+
+FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data)
+{
+ FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+ (void)decoder;
+ if(feof(file_decoder->guts->file)) {
+ file_decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
+ return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
+ }
+ else if(*bytes > 0) {
+ size_t bytes_read = fread(buffer, sizeof(byte), *bytes, file_decoder->guts->file);
+ if(bytes_read == 0) {
+ if(feof(file_decoder->guts->file)) {
+ file_decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
+ return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_ABORT;
+ }
+ else {
+ *bytes = (unsigned)bytes_read;
+ return FLAC__STREAM_DECODER_READ_CONTINUE;
+ }
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
+{
+ FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+ (void)decoder;
+
+ if(file_decoder->state == FLAC__FILE_DECODER_SEEKING) {
+ uint64 this_frame_sample = header->number.sample_number;
+ uint64 next_frame_sample = this_frame_sample + (uint64)header->blocksize;
+ uint64 target_sample = file_decoder->guts->target_sample;
+
+ file_decoder->guts->last_frame_header = *header; /* save the header in the guts */
+ if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
+ unsigned delta = (unsigned)(target_sample - this_frame_sample);
+ /* kick out of seek mode */
+ file_decoder->state = FLAC__FILE_DECODER_OK;
+ /* shift out the samples before target_sample */
+ if(delta > 0) {
+ unsigned channel;
+ const int32 *newbuffer[FLAC__MAX_CHANNELS];
+ for(channel = 0; channel < header->channels; channel++)
+ newbuffer[channel] = buffer[channel] + delta;
+ file_decoder->guts->last_frame_header.blocksize -= delta;
+ file_decoder->guts->last_frame_header.number.sample_number += (uint64)delta;
+ /* write the relevant samples */
+ return file_decoder->guts->write_callback(file_decoder, &file_decoder->guts->last_frame_header, newbuffer, file_decoder->guts->client_data);
+ }
+ else {
+ /* write the relevant samples */
+ return file_decoder->guts->write_callback(file_decoder, header, buffer, file_decoder->guts->client_data);
+ }
+ }
+ else {
+ return FLAC__STREAM_DECODER_WRITE_CONTINUE;
+ }
+ }
+ else {
+ return file_decoder->guts->write_callback(file_decoder, header, buffer, file_decoder->guts->client_data);
+ }
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+ FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+ (void)decoder;
+
+ if(metadata->type == FLAC__METADATA_TYPE_ENCODING)
+ file_decoder->guts->metadata = metadata->data.encoding;
+ if(file_decoder->state != FLAC__FILE_DECODER_SEEKING)
+ file_decoder->guts->metadata_callback(file_decoder, metadata, file_decoder->guts->client_data);
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
+ (void)decoder;
+
+ if(file_decoder->state != FLAC__FILE_DECODER_SEEKING)
+ file_decoder->guts->error_callback(file_decoder, status, file_decoder->guts->client_data);
+}
+
+bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample)
+{
+ long l, r, pos, last_pos = -1;
+ unsigned approx_bytes_per_frame;
+ uint64 last_frame_sample = 0xffffffffffffffff;
+ bool needs_seek;
+ const bool is_variable_blocksize_stream = (decoder->guts->metadata.min_blocksize != decoder->guts->metadata.max_blocksize);
+
+ if(!is_variable_blocksize_stream) {
+ /* we are just guessing here, but we want to guess high, not low */
+ /* note there are no () around 'decoder->guts->metadata.bits_per_sample/8' to keep precision up since it's an integer calulation */
+ approx_bytes_per_frame = decoder->guts->metadata.min_blocksize * decoder->guts->metadata.channels * decoder->guts->metadata.bits_per_sample/8 + 64;
+ }
+ else
+ approx_bytes_per_frame = 1152 * decoder->guts->metadata.channels * decoder->guts->metadata.bits_per_sample/8 + 64;
+
+ /* Now we need to use the metadata and the filelength to search to the frame with the correct sample */
+ if(-1 == (l = ftell(decoder->guts->file))) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ l -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream);
+#ifdef _MSC_VER
+ /* with VC++ you have to spoon feed it the casting */
+ pos = l + (long)((double)(int64)target_sample / (double)(int64)decoder->guts->metadata.total_samples * (double)(filesize-l+1)) - approx_bytes_per_frame;
+#else
+ pos = l + (long)((double)target_sample / (double)decoder->guts->metadata.total_samples * (double)(filesize-l+1)) - approx_bytes_per_frame;
+#endif
+ r = filesize - ((decoder->guts->metadata.channels * decoder->guts->metadata.bits_per_sample * FLAC__MAX_BLOCK_SIZE) / 8 + 64);
+ if(pos >= r)
+ pos = r-1;
+ if(pos < l)
+ pos = l;
+ needs_seek = true;
+
+ decoder->guts->target_sample = target_sample;
+ while(1) {
+ if(needs_seek) {
+ if(-1 == fseek(decoder->guts->file, pos, SEEK_SET)) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!FLAC__stream_decoder_flush(decoder->guts->stream)) {
+ decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
+ return false;
+ }
+ }
+ if(!FLAC__stream_decoder_process_one_frame(decoder->guts->stream)) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ /* our write callback will change the state when it gets to the target frame */
+ if(decoder->state != FLAC__FILE_DECODER_SEEKING) {
+ break;
+ }
+ else { /* we need to narrow the search */
+ uint64 this_frame_sample = decoder->guts->last_frame_header.number.sample_number;
+ if(this_frame_sample == last_frame_sample) {
+ /* our last move backwards wasn't big enough */
+ pos -= (last_pos - pos);
+ needs_seek = true;
+ }
+ else {
+ if(target_sample < this_frame_sample) {
+ last_pos = pos;
+ approx_bytes_per_frame = decoder->guts->last_frame_header.blocksize * decoder->guts->last_frame_header.channels * decoder->guts->last_frame_header.bits_per_sample/8 + 64;
+ pos -= approx_bytes_per_frame;
+ needs_seek = true;
+ }
+ else {
+ last_pos = pos;
+ if(-1 == (pos = ftell(decoder->guts->file))) {
+ decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
+ return false;
+ }
+ pos -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream);
+ needs_seek = false;
+ }
+ }
+ if(pos < l)
+ pos = l;
+ last_frame_sample = this_frame_sample;
+ }
+ }
+
+ return true;
+}
diff --git a/src/libFLAC/fixed.c b/src/libFLAC/fixed.c
new file mode 100644
index 0000000..1b762bc
--- /dev/null
+++ b/src/libFLAC/fixed.c
@@ -0,0 +1,159 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <math.h>
+#include "private/fixed.h"
+
+#ifndef M_LN2
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_LN2 0.69314718055994530942
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x) < (y)? (x) : (y))
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((x)<0? -(x) : (x))
+
+unsigned FLAC__fixed_compute_best_predictor(const int32 data[], unsigned data_len, real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+{
+ int32 last_error_0 = data[-1];
+ int32 last_error_1 = data[-1] - data[-2];
+ int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+ int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+ int32 error_0, error_1, error_2, error_3, error_4;
+ int32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+ unsigned i, order;
+
+ for(i = 0; i < data_len; i++) {
+ error_0 = data[i] ; total_error_0 += local_abs(error_0);
+ error_1 = error_0 - last_error_0; total_error_1 += local_abs(error_1);
+ error_2 = error_1 - last_error_1; total_error_2 += local_abs(error_2);
+ error_3 = error_2 - last_error_2; total_error_3 += local_abs(error_3);
+ error_4 = error_3 - last_error_3; total_error_4 += local_abs(error_4);
+
+ last_error_0 = error_0;
+ last_error_1 = error_1;
+ last_error_2 = error_2;
+ last_error_3 = error_3;
+ }
+
+ if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 < min(total_error_3, total_error_4))
+ order = 2;
+ else if(total_error_3 < total_error_4)
+ order = 3;
+ else
+ order = 4;
+
+ /* Estimate the expected number of bits per residual signal sample. */
+ /* 'total_error*' is linearly related to the variance of the residual */
+ /* signal, so we use it directly to compute E(|x|) */
+ residual_bits_per_sample[0] = (real)((total_error_0 > 0 && data_len > 0) ? log(M_LN2 * total_error_0 / (real) data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (real)((total_error_1 > 0 && data_len > 0) ? log(M_LN2 * total_error_1 / (real) data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (real)((total_error_2 > 0 && data_len > 0) ? log(M_LN2 * total_error_2 / (real) data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (real)((total_error_3 > 0 && data_len > 0) ? log(M_LN2 * total_error_3 / (real) data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (real)((total_error_4 > 0 && data_len > 0) ? log(M_LN2 * total_error_4 / (real) data_len) / M_LN2 : 0.0);
+
+ return order;
+}
+
+void FLAC__fixed_compute_residual(const int32 data[], unsigned data_len, unsigned order, int32 residual[])
+{
+ unsigned i;
+
+ switch(order) {
+ case 0:
+ for(i = 0; i < data_len; i++) {
+ residual[i] = data[i];
+ }
+ break;
+ case 1:
+ for(i = 0; i < data_len; i++) {
+ residual[i] = data[i] - data[i-1];
+ }
+ break;
+ case 2:
+ for(i = 0; i < data_len; i++) {
+ /* == data[i] - 2*data[i-1] + data[i-2] */
+ residual[i] = data[i] - (data[i-1] << 1) + data[i-2];
+ }
+ break;
+ case 3:
+ for(i = 0; i < data_len; i++) {
+ /* == data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3] */
+ residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3];
+ }
+ break;
+ case 4:
+ for(i = 0; i < data_len; i++) {
+ /* == data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4] */
+ residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4];
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
+void FLAC__fixed_restore_signal(const int32 residual[], unsigned data_len, unsigned order, int32 data[])
+{
+ unsigned i;
+
+ switch(order) {
+ case 0:
+ for(i = 0; i < data_len; i++) {
+ data[i] = residual[i];
+ }
+ break;
+ case 1:
+ for(i = 0; i < data_len; i++) {
+ data[i] = residual[i] + data[i-1];
+ }
+ break;
+ case 2:
+ for(i = 0; i < data_len; i++) {
+ /* == residual[i] + 2*data[i-1] - data[i-2] */
+ data[i] = residual[i] + (data[i-1]<<1) - data[i-2];
+ }
+ break;
+ case 3:
+ for(i = 0; i < data_len; i++) {
+ /* residual[i] + 3*data[i-1] - 3*data[i-2]) + data[i-3] */
+ data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3];
+ }
+ break;
+ case 4:
+ for(i = 0; i < data_len; i++) {
+ /* == residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4] */
+ data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4];
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
diff --git a/src/libFLAC/format.c b/src/libFLAC/format.c
new file mode 100644
index 0000000..ed20941
--- /dev/null
+++ b/src/libFLAC/format.c
@@ -0,0 +1,66 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include "FLAC/format.h"
+
+const unsigned FLAC__MAJOR_VERSION = 0;
+const unsigned FLAC__MINOR_VERSION = 2;
+
+const byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+const unsigned FLAC__STREAM_SYNC = 0x664C6143;
+const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */;
+
+const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN = 24; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN = 24; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN = 20; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN = 3; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN = 5; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN = 36; /* bits */
+const unsigned FLAC__STREAM_METADATA_ENCODING_LENGTH = 18; /* bytes */
+
+const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+const unsigned FLAC__FRAME_HEADER_SYNC = 0x1fe;
+const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 9; /* bits */
+const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 3; /* bits */
+const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+const unsigned FLAC__FRAME_HEADER_CRC8_LEN = 8; /* bits */
+
+const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+
+const unsigned FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+const unsigned FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN = 5; /* bits */
+const unsigned FLAC__SUBFRAME_HEADER_LPC_RICE_PARAMETER_LEN = 4; /* bits */
+
+const unsigned FLAC__SUBFRAME_HEADER_TYPE_CONSTANT = 0x00;
+const unsigned FLAC__SUBFRAME_HEADER_TYPE_VERBATIM = 0x02;
+const unsigned FLAC__SUBFRAME_HEADER_TYPE_FIXED = 0x10;
+const unsigned FLAC__SUBFRAME_HEADER_TYPE_LPC = 0x40;
+const unsigned FLAC__SUBFRAME_HEADER_TYPE_LEN = 8; /* bits */
diff --git a/src/libFLAC/include/private/all.h b/src/libFLAC/include/private/all.h
new file mode 100644
index 0000000..b05a4b1
--- /dev/null
+++ b/src/libFLAC/include/private/all.h
@@ -0,0 +1,29 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PRIVATE__ALL_H
+#define FLAC__PRIVATE__ALL_H
+
+#include "bitbuffer.h"
+#include "crc.h"
+#include "encoder_framing.h"
+#include "fixed.h"
+#include "lpc.h"
+
+#endif
diff --git a/src/libFLAC/include/private/bitbuffer.h b/src/libFLAC/include/private/bitbuffer.h
new file mode 100644
index 0000000..192b6c9
--- /dev/null
+++ b/src/libFLAC/include/private/bitbuffer.h
@@ -0,0 +1,64 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PRIVATE__BITBUFFER_H
+#define FLAC__PRIVATE__BITBUFFER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+typedef struct {
+ byte *buffer;
+ unsigned capacity; /* in bytes */
+ unsigned bytes, bits;
+ unsigned total_bits; /* must always == 8*bytes+bits */
+ unsigned consumed_bytes, consumed_bits;
+ unsigned total_consumed_bits; /* must always == 8*consumed_bytes+consumed_bits */
+} FLAC__BitBuffer;
+
+void FLAC__bitbuffer_init(FLAC__BitBuffer *bb);
+bool FLAC__bitbuffer_init_from(FLAC__BitBuffer *bb, const byte buffer[], unsigned bytes);
+bool FLAC__bitbuffer_concatenate_aligned(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src);
+void FLAC__bitbuffer_free(FLAC__BitBuffer *bb); /* does not 'free(buffer)' */
+bool FLAC__bitbuffer_clear(FLAC__BitBuffer *bb);
+bool FLAC__bitbuffer_clone(FLAC__BitBuffer *dest, const FLAC__BitBuffer *src);
+bool FLAC__bitbuffer_write_zeroes(FLAC__BitBuffer *bb, unsigned bits);
+bool FLAC__bitbuffer_write_raw_uint32(FLAC__BitBuffer *bb, uint32 val, unsigned bits);
+bool FLAC__bitbuffer_write_raw_int32(FLAC__BitBuffer *bb, int32 val, unsigned bits);
+bool FLAC__bitbuffer_write_raw_uint64(FLAC__BitBuffer *bb, uint64 val, unsigned bits);
+bool FLAC__bitbuffer_write_raw_int64(FLAC__BitBuffer *bb, int64 val, unsigned bits);
+bool FLAC__bitbuffer_write_rice_signed(FLAC__BitBuffer *bb, int val, unsigned parameter);
+bool FLAC__bitbuffer_write_rice_signed_guarded(FLAC__BitBuffer *bb, int val, unsigned parameter, unsigned max_bits, bool *overflow);
+bool FLAC__bitbuffer_write_utf8_uint32(FLAC__BitBuffer *bb, uint32 val);
+bool FLAC__bitbuffer_write_utf8_uint64(FLAC__BitBuffer *bb, uint64 val);
+bool FLAC__bitbuffer_zero_pad_to_byte_boundary(FLAC__BitBuffer *bb);
+bool FLAC__bitbuffer_peek_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_bit(FLAC__BitBuffer *bb, unsigned *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_bit_to_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_bit_to_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_raw_uint32(FLAC__BitBuffer *bb, uint32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_raw_int32(FLAC__BitBuffer *bb, int32 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_raw_uint64(FLAC__BitBuffer *bb, uint64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_raw_int64(FLAC__BitBuffer *bb, int64 *val, unsigned bits, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_rice_signed(FLAC__BitBuffer *bb, int *val, unsigned parameter, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data);
+bool FLAC__bitbuffer_read_utf8_uint32(FLAC__BitBuffer *bb, uint32 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen);
+bool FLAC__bitbuffer_read_utf8_uint64(FLAC__BitBuffer *bb, uint64 *val, bool (*read_callback)(byte buffer[], unsigned *bytes, void *client_data), void *client_data, byte *raw, unsigned *rawlen);
+void FLAC__bitbuffer_dump(const FLAC__BitBuffer *bb, FILE *out);
+
+#endif
diff --git a/src/libFLAC/include/private/crc.h b/src/libFLAC/include/private/crc.h
new file mode 100644
index 0000000..742d9bc
--- /dev/null
+++ b/src/libFLAC/include/private/crc.h
@@ -0,0 +1,30 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PRIVATE__CRC_H
+#define FLAC__PRIVATE__CRC_H
+
+#include "FLAC/ordinals.h"
+
+/* 8 bit CRC generator, MSB shifted first
+** polynomial = x^8 + x^2 + x^1 + 1
+*/
+byte FLAC__crc8(const byte *data, const unsigned len);
+
+#endif
diff --git a/src/libFLAC/include/private/encoder_framing.h b/src/libFLAC/include/private/encoder_framing.h
new file mode 100644
index 0000000..bf26649
--- /dev/null
+++ b/src/libFLAC/include/private/encoder_framing.h
@@ -0,0 +1,33 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PRIVATE__ENCODER_FRAMING_H
+#define FLAC__PRIVATE__ENCODER_FRAMING_H
+
+#include "FLAC/format.h"
+#include "bitbuffer.h"
+
+bool FLAC__add_metadata_block(const FLAC__StreamMetaData *metadata, FLAC__BitBuffer *bb);
+bool FLAC__frame_add_header(const FLAC__FrameHeader *header, bool streamable_subset, bool is_last_block, FLAC__BitBuffer *bb);
+bool FLAC__subframe_add_constant(unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb);
+bool FLAC__subframe_add_fixed(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb);
+bool FLAC__subframe_add_lpc(const int32 residual[], unsigned residual_samples, unsigned bits_per_sample, const FLAC__SubframeHeader *subframe, FLAC__BitBuffer *bb);
+bool FLAC__subframe_add_verbatim(const int32 signal[], unsigned samples, unsigned bits_per_sample, FLAC__BitBuffer *bb);
+
+#endif
diff --git a/src/libFLAC/include/private/fixed.h b/src/libFLAC/include/private/fixed.h
new file mode 100644
index 0000000..e018da6
--- /dev/null
+++ b/src/libFLAC/include/private/fixed.h
@@ -0,0 +1,65 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PRIVATE__FIXED_H
+#define FLAC__PRIVATE__FIXED_H
+
+#include "FLAC/format.h"
+
+/*
+ * FLAC__fixed_compute_best_predictor()
+ * --------------------------------------------------------------------
+ * Compute the best fixed predictor and the expected bits-per-sample
+ * of the residual signal for each order.
+ *
+ * IN data[0,data_len-1]
+ * IN data_len
+ * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
+ */
+unsigned FLAC__fixed_compute_best_predictor(const int32 data[], unsigned data_len, real residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+
+/*
+ * FLAC__fixed_compute_residual()
+ * --------------------------------------------------------------------
+ * Compute the residual signal obtained from sutracting the predicted
+ * signal from the original.
+ *
+ * IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ * IN data_len length of original signal
+ * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ * OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__fixed_compute_residual(const int32 data[], unsigned data_len, unsigned order, int32 residual[]);
+
+/*
+ * FLAC__fixed_restore_signal()
+ * --------------------------------------------------------------------
+ * Restore the original signal by summing the residual and the
+ * predictor.
+ *
+ * IN residual[0,data_len-1] residual signal
+ * IN data_len length of original signal
+ * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ * *** IMPORTANT: the caller must pass in the historical samples:
+ * IN data[-order,-1] previously-reconstructed historical samples
+ * OUT data[0,data_len-1] original signal
+ */
+void FLAC__fixed_restore_signal(const int32 residual[], unsigned data_len, unsigned order, int32 data[]);
+
+#endif
diff --git a/src/libFLAC/include/private/lpc.h b/src/libFLAC/include/private/lpc.h
new file mode 100644
index 0000000..c30871b
--- /dev/null
+++ b/src/libFLAC/include/private/lpc.h
@@ -0,0 +1,142 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PRIVATE__LPC_H
+#define FLAC__PRIVATE__LPC_H
+
+#include "FLAC/ordinals.h"
+
+#define FLAC__MAX_LPC_ORDER (32u)
+
+/*
+ * FLAC__lpc_compute_autocorrelation()
+ * --------------------------------------------------------------------
+ * Compute the autocorrelation for lags between 0 and lag-1.
+ * Assumes data[] outside of [0,data_len-1] == 0.
+ * Asserts that lag > 0.
+ *
+ * IN data[0,data_len-1]
+ * IN data_len
+ * IN 0 < lag <= data_len
+ * OUT autoc[0,lag-1]
+ */
+void FLAC__lpc_compute_autocorrelation(const real data[], unsigned data_len, unsigned lag, real autoc[]);
+
+/*
+ * FLAC__lpc_compute_lp_coefficients()
+ * --------------------------------------------------------------------
+ * Computes LP coefficients for orders 1..max_order.
+ * Do not call if autoc[0] == 0.0. This means the signal is zero
+ * and there is no point in calculating a predictor.
+ *
+ * IN autoc[0,max_order] autocorrelation values
+ * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute
+ * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
+ * *** IMPORTANT:
+ * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
+ * OUT error[0,max_order-1] error for each order
+ *
+ * Example: if max_order is 9, the LP coefficients for order 9 will be
+ * in lp_coeff[8][0,8], the LP coefficients for order 8 will be
+ * in lp_coeff[7][0,7], etc.
+ */
+void FLAC__lpc_compute_lp_coefficients(const real autoc[], unsigned max_order, real lp_coeff[][FLAC__MAX_LPC_ORDER], real error[]);
+
+/*
+ * FLAC__lpc_quantize_coefficients()
+ * --------------------------------------------------------------------
+ * Quantizes the LP coefficients. NOTE: precision + bits_per_sample
+ * must be less than 32 (sizeof(int32)*8).
+ *
+ * IN lp_coeff[0,order-1] LP coefficients
+ * IN order LP order
+ * IN FLAC__MIN_QLP_COEFF_PRECISION < precision
+ * desired precision (in bits, including sign
+ * bit) of largest coefficient
+ * IN bits_per_sample > 0 bits per sample of the originial signal
+ * OUT qlp_coeff[0,order-1] quantized coefficients
+ * OUT bits # of bits to shift right to get approximated
+ * LP coefficients. NOTE: could be negative,
+ * but |*bits| will always be <= precision
+ * RETURN 0 => quantization OK
+ * 1 => coefficients vary too much to quantize to the desired
+ * precision. 'bits' is unset
+ * 2 => coefficients are all zero, which is bad. 'bits' is unset
+ */
+int FLAC__lpc_quantize_coefficients(const real lp_coeff[], unsigned order, unsigned precision, unsigned bits_per_sample, int32 qlp_coeff[], int *bits);
+
+/*
+ * FLAC__lpc_compute_residual_from_qlp_coefficients()
+ * --------------------------------------------------------------------
+ * Compute the residual signal obtained from sutracting the predicted
+ * signal from the original.
+ *
+ * IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ * IN data_len length of original signal
+ * IN qlp_coeff[0,order-1] quantized LP coefficients
+ * IN order > 0 LP order
+ * IN lp_quantization quantization of LP coefficients in bits
+ * OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const int32 data[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 residual[]);
+
+/*
+ * FLAC__lpc_restore_signal()
+ * --------------------------------------------------------------------
+ * Restore the original signal by summing the residual and the
+ * predictor.
+ *
+ * IN residual[0,data_len-1] residual signal
+ * IN data_len length of original signal
+ * IN qlp_coeff[0,order-1] quantized LP coefficients
+ * IN order > 0 LP order
+ * IN lp_quantization quantization of LP coefficients in bits
+ * *** IMPORTANT: the caller must pass in the historical samples:
+ * IN data[-order,-1] previously-reconstructed historical samples
+ * OUT data[0,data_len-1] original signal
+ */
+void FLAC__lpc_restore_signal(const int32 residual[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 data[]);
+
+/*
+ * FLAC__lpc_compute_expected_bits_per_residual_sample()
+ * --------------------------------------------------------------------
+ * Compute the expected number of bits per residual signal sample
+ * based on the LP error (which is related to the residual variance).
+ *
+ * IN lpc_error >= 0.0 error returned from calculating LP coefficients
+ * IN total_samples > 0 # of samples in residual signal
+ * RETURN expected bits per sample
+ */
+real FLAC__lpc_compute_expected_bits_per_residual_sample(real lpc_error, unsigned total_samples);
+
+/*
+ * FLAC__lpc_compute_best_order()
+ * --------------------------------------------------------------------
+ * Compute the best order from the array of signal errors returned
+ * during coefficient computation.
+ *
+ * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients
+ * IN max_order > 0 max LP order
+ * IN total_samples > 0 # of samples in residual signal
+ * IN bits_per_signal_sample # of bits per sample in the original signal
+ * RETURN [1,max_order] best order
+ */
+unsigned FLAC__lpc_compute_best_order(const real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample);
+
+#endif
diff --git a/src/libFLAC/include/protected/stream_decoder.h b/src/libFLAC/include/protected/stream_decoder.h
new file mode 100644
index 0000000..be6e541
--- /dev/null
+++ b/src/libFLAC/include/protected/stream_decoder.h
@@ -0,0 +1,28 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_DECODER_H
+#define FLAC__PROTECTED__STREAM_DECODER_H
+
+#include "FLAC/stream_decoder.h"
+
+/* only useful to the file_decoder */
+unsigned FLAC__stream_decoder_input_bytes_unconsumed(FLAC__StreamDecoder *decoder);
+
+#endif
diff --git a/src/libFLAC/lpc.c b/src/libFLAC/lpc.c
new file mode 100644
index 0000000..615a734
--- /dev/null
+++ b/src/libFLAC/lpc.c
@@ -0,0 +1,238 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include "FLAC/format.h"
+#include "private/lpc.h"
+
+#ifndef M_LN2
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_LN2 0.69314718055994530942
+#endif
+
+void FLAC__lpc_compute_autocorrelation(const real data[], unsigned data_len, unsigned lag, real autoc[])
+{
+ real d;
+ unsigned i;
+
+ assert(lag > 0);
+ assert(lag <= data_len);
+
+ while(lag--) {
+ for(i = lag, d = 0.0; i < data_len; i++)
+ d += data[i] * data[i - lag];
+ autoc[lag] = d;
+ }
+}
+
+void FLAC__lpc_compute_lp_coefficients(const real autoc[], unsigned max_order, real lp_coeff[][FLAC__MAX_LPC_ORDER], real error[])
+{
+ unsigned i, j;
+ real r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
+
+ assert(0 < max_order);
+ assert(max_order <= FLAC__MAX_LPC_ORDER);
+ assert(autoc[0] != 0.0);
+
+ err = autoc[0];
+
+ for(i = 0; i < max_order; i++) {
+ /* Sum up this iteration's reflection coefficient. */
+ r =- autoc[i+1];
+ for(j = 0; j < i; j++)
+ r -= lpc[j] * autoc[i-j];
+ ref[i] = (r/=err);
+
+ /* Update LPC coefficients and total error. */
+ lpc[i]=r;
+ for(j = 0; j < (i>>1); j++) {
+ real tmp = lpc[j];
+ lpc[j] += r * lpc[i-1-j];
+ lpc[i-1-j] += r * tmp;
+ }
+ if(i & 1)
+ lpc[j] += lpc[j] * r;
+
+ err *= (1.0 - r * r);
+
+ /* save this order */
+ for(j = 0; j <= i; j++)
+ lp_coeff[i][j] = -lpc[j]; /* N.B. why do we have to negate here? */
+ error[i] = err;
+ }
+}
+
+int FLAC__lpc_quantize_coefficients(const real lp_coeff[], unsigned order, unsigned precision, unsigned bits_per_sample, int32 qlp_coeff[], int *bits)
+{
+ unsigned i;
+ real d, rprecision = (real)precision, maxlog = -1e99, minlog = 1e99;
+
+ assert(bits_per_sample > 0);
+ assert(bits_per_sample <= sizeof(int32)*8);
+ assert(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
+ assert(precision + bits_per_sample < sizeof(int32)*8);
+#ifdef NDEBUG
+ (void)bits_per_sample; /* silence compiler warning about unused parameter */
+#endif
+
+ for(i = 0; i < order; i++) {
+ if(lp_coeff[i] == 0.0)
+ continue;
+ d = log(fabs(lp_coeff[i])) / M_LN2;
+ if(d > maxlog)
+ maxlog = d;
+ if(d < minlog)
+ minlog = d;
+ }
+ if(maxlog < minlog)
+ return 2;
+ else if(maxlog - minlog >= (real)(precision+1))
+ return 1;
+ else if((rprecision-1.0) - maxlog >= (real)(precision+1))
+ rprecision = (real)precision + maxlog + 1.0;
+
+ *bits = (int)floor((rprecision-1.0) - maxlog); /* '-1' because bits can be negative and the sign bit costs 1 bit */
+ if(*bits > (int)precision || *bits <= -(int)precision) {
+ fprintf(stderr, "@@@ FLAC__lpc_quantize_coefficients(): ERROR: *bits=%d, maxlog=%f, minlog=%f, precision=%u, rprecision=%f\n", *bits, maxlog, minlog, precision, rprecision);
+ return 1;
+ }
+
+ if(*bits != 0) { /* just to avoid wasting time... */
+ for(i = 0; i < order; i++)
+ qlp_coeff[i] = (int32)floor(lp_coeff[i] * (real)(1 << *bits));
+ }
+ return 0;
+}
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const int32 data[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 residual[])
+{
+#ifdef FLAC_OVERFLOW_DETECT
+ int64 sumo;
+#endif
+ unsigned i, j;
+ int32 sum;
+ const int32 *history;
+
+#ifdef FLAC_OVERFLOW_DETECT_VERBOSE
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+ for(i=0;i<order;i++)
+ fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+ fprintf(stderr,"\n");
+#endif
+ assert(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+#ifdef FLAC_OVERFLOW_DETECT
+ sumo = 0;
+#endif
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++) {
+ sum += qlp_coeff[j] * (*(--history));
+#ifdef FLAC_OVERFLOW_DETECT
+ sumo += (int64)qlp_coeff[j] * (int64)(*history);
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, sumo=%lld\n",sumo);
+#endif
+ }
+ *(residual++) = *(data++) - (sum >> lp_quantization);
+ }
+
+ /* Here's a slightly slower but clearer version:
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ history = &(data[i]);
+ for(j = 0; j < order; j++)
+ sum += qlp_coeff[j] * (*(--history));
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ */
+}
+
+void FLAC__lpc_restore_signal(const int32 residual[], unsigned data_len, const int32 qlp_coeff[], unsigned order, int lp_quantization, int32 data[])
+{
+#ifdef FLAC_OVERFLOW_DETECT
+ int64 sumo;
+#endif
+ unsigned i, j;
+ int32 sum, *history;
+
+#ifdef FLAC_OVERFLOW_DETECT_VERBOSE
+ fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+ for(i=0;i<order;i++)
+ fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+ fprintf(stderr,"\n");
+#endif
+ assert(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+#ifdef FLAC_OVERFLOW_DETECT
+ sumo = 0;
+#endif
+ sum = 0;
+ history = data+i;
+ for(j = 0; j < order; j++) {
+ sum += qlp_coeff[j] * (*(--history));
+#ifdef FLAC_OVERFLOW_DETECT
+ sumo += (int64)qlp_coeff[j] * (int64)(*history);
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, sumo=%lld\n",sumo);
+#endif
+ }
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+}
+
+real FLAC__lpc_compute_expected_bits_per_residual_sample(real lpc_error, unsigned total_samples)
+{
+ real escale;
+
+ assert(lpc_error >= 0.0); /* the error can never be negative */
+ assert(total_samples > 0);
+
+ escale = 0.5 * M_LN2 * M_LN2 / (real)total_samples;
+
+ if(lpc_error > 0.0)
+ return 0.5 * log(escale * lpc_error) / M_LN2;
+ else
+ return 0.0;
+}
+
+unsigned FLAC__lpc_compute_best_order(const real lpc_error[], unsigned max_order, unsigned total_samples, unsigned bits_per_signal_sample)
+{
+ unsigned order, best_order;
+ real best_bits, tmp_bits;
+
+ assert(max_order > 0);
+
+ best_order = 0;
+ best_bits = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[0], total_samples) * (real)total_samples;
+
+ for(order = 1; order < max_order; order++) {
+ tmp_bits = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[order], total_samples) * (real)(total_samples - order) + (real)(order * bits_per_signal_sample);
+ if(tmp_bits < best_bits) {
+ best_order = order;
+ best_bits = tmp_bits;
+ }
+ }
+
+ return best_order+1; /* +1 since index of lpc_error[] is order-1 */
+}
diff --git a/src/libFLAC/stream_decoder.c b/src/libFLAC/stream_decoder.c
new file mode 100644
index 0000000..eaf35bf
--- /dev/null
+++ b/src/libFLAC/stream_decoder.c
@@ -0,0 +1,1114 @@
+/* libFLAC - Free Lossless Audio Coder library
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include "FLAC/stream_decoder.h"
+#include "private/bitbuffer.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/lpc.h"
+
+typedef struct FLAC__StreamDecoderPrivate {
+ FLAC__StreamDecoderReadStatus (*read_callback)(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data);
+ FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
+ void (*metadata_callback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+ void (*error_callback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+ void *client_data;
+ FLAC__BitBuffer input;
+ int32 *output[FLAC__MAX_CHANNELS];
+ int32 *residual;
+ unsigned output_capacity;
+ uint32 last_frame_number;
+ uint64 samples_decoded;
+ bool has_stream_header;
+ FLAC__StreamMetaData stream_header;
+ FLAC__FrameHeader frame_header;
+} FLAC__StreamDecoderPrivate;
+
+static byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+static bool stream_decoder_allocate_output(FLAC__StreamDecoder *decoder, unsigned size);
+static bool stream_decoder_find_metadata_(FLAC__StreamDecoder *decoder);
+static bool stream_decoder_read_metadata_(FLAC__StreamDecoder *decoder);
+static bool stream_decoder_skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
+static bool stream_decoder_frame_sync_(FLAC__StreamDecoder *decoder);
+static bool stream_decoder_read_frame_(FLAC__StreamDecoder *decoder, bool *got_a_frame);
+static bool stream_decoder_read_frame_header_(FLAC__StreamDecoder *decoder);
+static bool stream_decoder_read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel);
+static bool stream_decoder_read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel);
+static bool stream_decoder_read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order);
+static bool stream_decoder_read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order);
+static bool stream_decoder_read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel);
+static bool stream_decoder_read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order);
+static bool stream_decoder_read_zero_padding_(FLAC__StreamDecoder *decoder);
+static bool read_callback_(byte buffer[], unsigned *bytes, void *client_data);
+
+FLAC__StreamDecoder *FLAC__stream_decoder_get_new_instance()
+{
+ FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)malloc(sizeof(FLAC__StreamDecoder));
+ if(decoder != 0) {
+ decoder->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+ decoder->guts = 0;
+ }
+ return decoder;
+}
+
+void FLAC__stream_decoder_free_instance(FLAC__StreamDecoder *decoder)
+{
+ free(decoder);
+}
+
+FLAC__StreamDecoderState FLAC__stream_decoder_init(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadStatus (*read_callback)(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data),
+ FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__StreamDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data),
+ void (*metadata_callback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data),
+ void (*error_callback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data),
+ void *client_data
+)
+{
+ unsigned i;
+
+ assert(sizeof(int) >= 4); /* we want to die right away if this is not true */
+ assert(decoder != 0);
+ assert(read_callback != 0);
+ assert(write_callback != 0);
+ assert(metadata_callback != 0);
+ assert(error_callback != 0);
+ assert(decoder->state == FLAC__STREAM_DECODER_UNINITIALIZED);
+ assert(decoder->guts == 0);
+
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+ decoder->guts = (FLAC__StreamDecoderPrivate*)malloc(sizeof(FLAC__StreamDecoderPrivate));
+ if(decoder->guts == 0)
+ return decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+
+ decoder->guts->read_callback = read_callback;
+ decoder->guts->write_callback = write_callback;
+ decoder->guts->metadata_callback = metadata_callback;
+ decoder->guts->error_callback = error_callback;
+ decoder->guts->client_data = client_data;
+
+ FLAC__bitbuffer_init(&decoder->guts->input);
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+ decoder->guts->output[i] = 0;
+ decoder->guts->residual = 0;
+
+ decoder->guts->output_capacity = 0;
+ decoder->guts->last_frame_number = 0;
+ decoder->guts->samples_decoded = 0;
+ decoder->guts->has_stream_header = false;
+
+ return decoder->state;
+}
+
+void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+ unsigned i;
+ assert(decoder != 0);
+ if(decoder->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+ return;
+ if(decoder->guts != 0) {
+ FLAC__bitbuffer_free(&decoder->guts->input);
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ if(decoder->guts->output[i] != 0) {
+ free(decoder->guts->output[i]);
+ decoder->guts->output[i] = 0;
+ }
+ }
+ if(decoder->guts->residual != 0) {
+ free(decoder->guts->residual);
+ decoder->guts->residual = 0;
+ }
+ free(decoder->guts);
+ decoder->guts = 0;
+ }
+ decoder->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+}
+
+bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
+{
+ assert(decoder != 0);
+
+ if(!FLAC__bitbuffer_clear(&decoder->guts->input)) {
+ decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+ assert(decoder != 0);
+
+ if(!FLAC__stream_decoder_flush(decoder)) {
+ decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+ return true;
+}
+
+bool FLAC__stream_decoder_process_whole_stream(FLAC__StreamDecoder *decoder)
+{
+ bool dummy;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+ return true;
+
+ assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA);
+
+ if(!FLAC__stream_decoder_reset(decoder)) {
+ decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ while(1) {
+ switch(decoder->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!stream_decoder_find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!stream_decoder_read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!stream_decoder_frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!stream_decoder_read_frame_(decoder, &dummy))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ return true;
+ default:
+ assert(0);
+ }
+ }
+}
+
+bool FLAC__stream_decoder_process_metadata(FLAC__StreamDecoder *decoder)
+{
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+ return true;
+
+ assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA);
+
+ if(!FLAC__stream_decoder_reset(decoder)) {
+ decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ while(1) {
+ switch(decoder->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!stream_decoder_find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!stream_decoder_read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ return true;
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ return true;
+ default:
+ assert(0);
+ }
+ }
+}
+
+bool FLAC__stream_decoder_process_one_frame(FLAC__StreamDecoder *decoder)
+{
+ bool got_a_frame;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+ return true;
+
+ assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC);
+
+ while(1) {
+ switch(decoder->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!stream_decoder_frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!stream_decoder_read_frame_(decoder, &got_a_frame))
+ return false; /* above function sets the status for us */
+ if(got_a_frame)
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ return true;
+ default:
+ assert(0);
+ }
+ }
+}
+
+bool FLAC__stream_decoder_process_remaining_frames(FLAC__StreamDecoder *decoder)
+{
+ bool dummy;
+ assert(decoder != 0);
+
+ if(decoder->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+ return true;
+
+ assert(decoder->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC);
+
+ while(1) {
+ switch(decoder->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!stream_decoder_frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!stream_decoder_read_frame_(decoder, &dummy))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ return true;
+ default:
+ assert(0);
+ }
+ }
+}
+
+unsigned FLAC__stream_decoder_input_bytes_unconsumed(FLAC__StreamDecoder *decoder)
+{
+ assert(decoder != 0);
+ return decoder->guts->input.bytes - decoder->guts->input.consumed_bytes;
+}
+
+bool stream_decoder_allocate_output(FLAC__StreamDecoder *decoder, unsigned size)
+{
+ unsigned i;
+ int32 *tmp;
+
+ if(size <= decoder->guts->output_capacity)
+ return true;
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ if(decoder->guts->output[i] != 0) {
+ free(decoder->guts->output[i]);
+ decoder->guts->output[i] = 0;
+ }
+ }
+ if(decoder->guts->residual != 0) {
+ free(decoder->guts->residual);
+ decoder->guts->residual = 0;
+ }
+
+ for(i = 0; i < decoder->guts->frame_header.channels; i++) {
+ tmp = (int32*)malloc(sizeof(int32)*size);
+ if(tmp == 0) {
+ decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->guts->output[i] = tmp;
+ }
+ tmp = (int32*)malloc(sizeof(int32)*size);
+ if(tmp == 0) {
+ decoder->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->guts->residual = tmp;
+
+ decoder->guts->output_capacity = size;
+
+ return true;
+}
+
+bool stream_decoder_find_metadata_(FLAC__StreamDecoder *decoder)
+{
+ uint32 x;
+ unsigned i, id;
+ bool first = 1;
+
+ assert(decoder->guts->input.consumed_bits == 0); /* make sure we're byte aligned */
+
+ for(i = id = 0; i < 4; ) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(x == FLAC__STREAM_SYNC_STRING[i]) {
+ first = 1;
+ i++;
+ id = 0;
+ continue;
+ }
+ if(x == ID3V2_TAG_[id]) {
+ id++;
+ i = 0;
+ if(id == 3) {
+ if(!stream_decoder_skip_id3v2_tag_(decoder))
+ return false; /* the read_callback_ sets the state for us */
+ }
+ continue;
+ }
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ unsigned y;
+ if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!y) { /* MAGIC NUMBER for the last sync bit */
+ decoder->state = FLAC__STREAM_DECODER_READ_FRAME;
+ return true;
+ }
+ }
+ i = 0;
+ if(first) {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ first = 0;
+ }
+ }
+
+ decoder->state = FLAC__STREAM_DECODER_READ_METADATA;
+ return true;
+}
+
+bool stream_decoder_read_metadata_(FLAC__StreamDecoder *decoder)
+{
+ uint32 i, x, last_block, type, length;
+
+ assert(decoder->guts->input.consumed_bits == 0); /* make sure we're byte aligned */
+
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &last_block, FLAC__STREAM_METADATA_IS_LAST_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &type, FLAC__STREAM_METADATA_TYPE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(type == FLAC__METADATA_TYPE_ENCODING) {
+ decoder->guts->stream_header.type = type;
+ decoder->guts->stream_header.is_last = last_block;
+ decoder->guts->stream_header.length = length;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MIN_BLOCK_SIZE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.min_blocksize = x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MAX_BLOCK_SIZE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.max_blocksize = x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MIN_FRAME_SIZE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.min_framesize = x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_MAX_FRAME_SIZE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.max_framesize = x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_SAMPLE_RATE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.sample_rate = x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_CHANNELS_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.channels = x+1;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__STREAM_METADATA_ENCODING_BITS_PER_SAMPLE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->stream_header.data.encoding.bits_per_sample = x+1;
+ if(!FLAC__bitbuffer_read_raw_uint64(&decoder->guts->input, &decoder->guts->stream_header.data.encoding.total_samples, FLAC__STREAM_METADATA_ENCODING_TOTAL_SAMPLES_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->has_stream_header = true;
+ decoder->guts->metadata_callback(decoder, &decoder->guts->stream_header, decoder->guts->client_data);
+ }
+ else {
+ /* skip other metadata blocks */
+ for(i = 0; i < length; i++) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ }
+ }
+
+ if(last_block)
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+ return true;
+}
+
+bool stream_decoder_skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
+{
+ uint32 x;
+ unsigned i, skip;
+
+ /* skip the version and flags bytes */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 24, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ /* get the size (in bytes) to skip */
+ skip = 0;
+ for(i = 0; i < 4; i++) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ skip <<= 7;
+ skip |= (x & 0x7f);
+ }
+ /* skip the rest of the tag */
+ for(i = 0; i < skip; i++) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ }
+ return true;
+}
+
+bool stream_decoder_frame_sync_(FLAC__StreamDecoder *decoder)
+{
+ uint32 x;
+ bool first = 1;
+
+ /* If we know the total number of samples in the stream, stop if we've read that many. */
+ /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
+ if(decoder->guts->has_stream_header && decoder->guts->stream_header.data.encoding.total_samples) {
+ if(decoder->guts->samples_decoded >= decoder->guts->stream_header.data.encoding.total_samples) {
+ decoder->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return true;
+ }
+ }
+
+ /* make sure we're byte aligned */
+ if(decoder->guts->input.consumed_bits != 0) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8-decoder->guts->input.consumed_bits, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ }
+
+ while(1) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ unsigned y;
+ if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!y) { /* MAGIC NUMBER for the last sync bit */
+ decoder->state = FLAC__STREAM_DECODER_READ_FRAME;
+ return true;
+ }
+ }
+ if(first) {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ first = 0;
+ }
+ }
+
+ return true;
+}
+
+bool stream_decoder_read_frame_(FLAC__StreamDecoder *decoder, bool *got_a_frame)
+{
+ unsigned channel;
+ unsigned i;
+ int32 mid, side, left, right;
+
+ *got_a_frame = false;
+
+ if(!stream_decoder_read_frame_header_(decoder))
+ return false;
+ if(decoder->state != FLAC__STREAM_DECODER_READ_FRAME) {
+ if(decoder->state == FLAC__STREAM_DECODER_RESYNC_IN_HEADER)
+ decoder->state = FLAC__STREAM_DECODER_READ_FRAME;
+ else
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ if(!stream_decoder_allocate_output(decoder, decoder->guts->frame_header.blocksize))
+ return false;
+ for(channel = 0; channel < decoder->guts->frame_header.channels; channel++) {
+ if(!stream_decoder_read_subframe_(decoder, channel))
+ return false;
+ if(decoder->state != FLAC__STREAM_DECODER_READ_FRAME) {
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ if(!stream_decoder_read_zero_padding_(decoder))
+ return false;
+
+ /* Undo any special channel coding */
+ switch(decoder->guts->frame_header.channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ /* do nothing */
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ assert(decoder->guts->frame_header.channels == 2);
+ for(i = 0; i < decoder->guts->frame_header.blocksize; i++)
+ decoder->guts->output[1][i] = decoder->guts->output[0][i] - decoder->guts->output[1][i];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ assert(decoder->guts->frame_header.channels == 2);
+ for(i = 0; i < decoder->guts->frame_header.blocksize; i++)
+ decoder->guts->output[0][i] += decoder->guts->output[1][i];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ assert(decoder->guts->frame_header.channels == 2);
+ for(i = 0; i < decoder->guts->frame_header.blocksize; i++) {
+ mid = decoder->guts->output[0][i];
+ side = decoder->guts->output[1][i];
+ mid <<= 1;
+ if(side & 1) /* i.e. if 'side' is odd... */
+ mid++;
+ left = mid + side;
+ right = mid - side;
+ decoder->guts->output[0][i] = left >> 1;
+ decoder->guts->output[1][i] = right >> 1;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ *got_a_frame = true;
+
+ /* put the latest values into the public section of the decoder instance */
+ decoder->channels = decoder->guts->frame_header.channels;
+ decoder->channel_assignment = decoder->guts->frame_header.channel_assignment;
+ decoder->bits_per_sample = decoder->guts->frame_header.bits_per_sample;
+ decoder->sample_rate = decoder->guts->frame_header.sample_rate;
+ decoder->blocksize = decoder->guts->frame_header.blocksize;
+
+ decoder->guts->samples_decoded += decoder->guts->frame_header.blocksize;
+
+ /* write it */
+ if(decoder->guts->write_callback(decoder, &decoder->guts->frame_header, decoder->guts->output, decoder->guts->client_data) != FLAC__STREAM_DECODER_WRITE_CONTINUE)
+ return false;
+
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+}
+
+bool stream_decoder_read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+ uint32 x;
+ uint64 xx;
+ unsigned i, blocksize_hint = 0, sample_rate_hint = 0;
+ byte crc, raw_header[15]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+ unsigned raw_header_len;
+ bool is_unparseable = false;
+
+ assert(decoder->guts->input.consumed_bits == 0); /* make sure we're byte aligned */
+
+ /* init the raw header with the first 8 bits of the sync code */
+ raw_header[0] = 0xff; /* MAGIC NUMBER for the first 8 frame sync bits */
+ raw_header_len = 1;
+
+ /*
+ * read in the raw header as bytes so we can CRC it, and parse it on the way
+ */
+ for(i = 0; i < 2; i++) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ else if(x == 0xff) { /* MAGIC NUMBER for the first part of the sync code */
+ /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */
+ uint32 y;
+ if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!y) { /* MAGIC NUMBER for the last sync bit */
+ decoder->state = FLAC__STREAM_DECODER_RESYNC_IN_HEADER;
+ return true;
+ }
+ else {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ raw_header[raw_header_len++] = (byte)x;
+ }
+ assert(!(raw_header[1] & 0x80)); /* last sync bit should be confirmed zero before we get here */
+
+ switch(x = raw_header[1] >> 4) {
+ case 0:
+ if(decoder->guts->has_stream_header && decoder->guts->stream_header.data.encoding.min_blocksize == decoder->guts->stream_header.data.encoding.max_blocksize) /* i.e. it's a fixed-blocksize stream */
+ decoder->guts->frame_header.blocksize = decoder->guts->stream_header.data.encoding.min_blocksize;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->guts->frame_header.blocksize = 192;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ decoder->guts->frame_header.blocksize = 576 << (x-2);
+ break;
+ case 6:
+ case 7:
+ blocksize_hint = x;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ switch(x = raw_header[1] & 0x0f) {
+ case 0:
+ if(decoder->guts->has_stream_header)
+ decoder->guts->frame_header.sample_rate = decoder->guts->stream_header.data.encoding.sample_rate;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ is_unparseable = true;
+ break;
+ case 4:
+ decoder->guts->frame_header.sample_rate = 8000;
+ break;
+ case 5:
+ decoder->guts->frame_header.sample_rate = 16000;
+ break;
+ case 6:
+ decoder->guts->frame_header.sample_rate = 22050;
+ break;
+ case 7:
+ decoder->guts->frame_header.sample_rate = 24000;
+ break;
+ case 8:
+ decoder->guts->frame_header.sample_rate = 32000;
+ break;
+ case 9:
+ decoder->guts->frame_header.sample_rate = 44100;
+ break;
+ case 10:
+ decoder->guts->frame_header.sample_rate = 48000;
+ break;
+ case 11:
+ decoder->guts->frame_header.sample_rate = 96000;
+ break;
+ case 12:
+ case 13:
+ case 14:
+ sample_rate_hint = x;
+ break;
+ case 15:
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ default:
+ assert(0);
+ }
+
+ x = (unsigned)(raw_header[2] >> 4);
+ if(x & 8) {
+ decoder->guts->frame_header.channels = 2;
+ switch(x & 7) {
+ case 0:
+ decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+ break;
+ case 1:
+ decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+ break;
+ case 2:
+ decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+ break;
+ default:
+ is_unparseable = true;
+ break;
+ }
+ }
+ else {
+ decoder->guts->frame_header.channels = (unsigned)x + 1;
+ decoder->guts->frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+ }
+
+ switch(x = (unsigned)(raw_header[2] & 0x0e) >> 1) {
+ case 0:
+ if(decoder->guts->has_stream_header)
+ decoder->guts->frame_header.bits_per_sample = decoder->guts->stream_header.data.encoding.bits_per_sample;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->guts->frame_header.bits_per_sample = 8;
+ break;
+ case 2:
+ decoder->guts->frame_header.bits_per_sample = 12;
+ break;
+ case 4:
+ decoder->guts->frame_header.bits_per_sample = 16;
+ break;
+ case 5:
+ decoder->guts->frame_header.bits_per_sample = 20;
+ break;
+ case 6:
+ decoder->guts->frame_header.bits_per_sample = 24;
+ break;
+ case 3:
+ case 7:
+ is_unparseable = true;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ if(raw_header[2] & 0x01) { /* this should be a zero padding bit */
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ if(blocksize_hint) {
+ if(!FLAC__bitbuffer_read_utf8_uint64(&decoder->guts->input, &xx, read_callback_, decoder, raw_header, &raw_header_len))
+ return false; /* the read_callback_ sets the state for us */
+ if(xx == 0xffffffffffffffff) {
+ if(raw_header[raw_header_len-1] == 0xff) { /* MAGIC NUMBER for sync code */
+ uint32 y;
+ if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!y) { /* MAGIC NUMBER for the last sync bit */
+ decoder->state = FLAC__STREAM_DECODER_RESYNC_IN_HEADER;
+ return true;
+ }
+ else {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ else {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ if(decoder->guts->has_stream_header && decoder->guts->stream_header.data.encoding.min_blocksize == decoder->guts->stream_header.data.encoding.max_blocksize) /* i.e. it's a fixed-blocksize stream */
+ decoder->guts->frame_header.number.sample_number = (uint64)decoder->guts->last_frame_number * (int64)decoder->guts->stream_header.data.encoding.min_blocksize + xx;
+ else
+ decoder->guts->frame_header.number.sample_number = xx;
+ }
+ else {
+ if(!FLAC__bitbuffer_read_utf8_uint32(&decoder->guts->input, &x, read_callback_, decoder, raw_header, &raw_header_len))
+ return false; /* the read_callback_ sets the state for us */
+ if(x == 0xffffffff) {
+ if(raw_header[raw_header_len-1] == 0xff) { /* MAGIC NUMBER for sync code */
+ uint32 y;
+ if(!FLAC__bitbuffer_peek_bit(&decoder->guts->input, &y, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(!y) { /* MAGIC NUMBER for the last sync bit */
+ decoder->state = FLAC__STREAM_DECODER_RESYNC_IN_HEADER;
+ return true;
+ }
+ else {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ else {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ decoder->guts->last_frame_number = x;
+ if(decoder->guts->has_stream_header) {
+ decoder->guts->frame_header.number.sample_number = (int64)decoder->guts->stream_header.data.encoding.min_blocksize * (int64)x;
+ }
+ else {
+ is_unparseable = true;
+ }
+ }
+
+ if(blocksize_hint) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (byte)x;
+ if(blocksize_hint == 7) {
+ uint32 _x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &_x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (byte)_x;
+ x = (x << 8) | _x;
+ }
+ decoder->guts->frame_header.blocksize = x+1;
+ }
+
+ if(sample_rate_hint) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (byte)x;
+ if(sample_rate_hint != 12) {
+ uint32 _x;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &_x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (byte)_x;
+ x = (x << 8) | _x;
+ }
+ if(sample_rate_hint == 12)
+ decoder->guts->frame_header.sample_rate = x*1000;
+ else if(sample_rate_hint == 13)
+ decoder->guts->frame_header.sample_rate = x;
+ else
+ decoder->guts->frame_header.sample_rate = x*10;
+ }
+
+ /* read the crc byte */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, 8, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ crc = (byte)x;
+
+ if(FLAC__crc8(raw_header, raw_header_len) != crc) {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ if(is_unparseable) {
+ decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+ return false;
+ }
+
+ return true;
+}
+
+bool stream_decoder_read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel)
+{
+ uint32 x;
+
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &x, FLAC__SUBFRAME_HEADER_TYPE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(x & 0x01 || x & 0x80) {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else if(x == 0) {
+ return stream_decoder_read_subframe_constant_(decoder, channel);
+ }
+ else if(x == 2) {
+ return stream_decoder_read_subframe_verbatim_(decoder, channel);
+ }
+ else if(x < 16) {
+ decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+ return false;
+ }
+ else if(x <= 24) {
+ return stream_decoder_read_subframe_fixed_(decoder, channel, (x>>1)&7);
+ }
+ else if(x < 64) {
+ decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+ return false;
+ }
+ else {
+ return stream_decoder_read_subframe_lpc_(decoder, channel, ((x>>1)&31)+1);
+ }
+}
+
+bool stream_decoder_read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel)
+{
+ int32 x;
+ unsigned i;
+
+ if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &x, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+
+ for(i = 0; i < decoder->guts->frame_header.blocksize; i++)
+ decoder->guts->output[channel][i] = x;
+
+ return true;
+}
+
+bool stream_decoder_read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order)
+{
+ FLAC__SubframeHeader_Fixed subframe_header;
+ int32 i32;
+ uint32 u32;
+ unsigned u;
+
+ subframe_header.order = order;
+
+ /* read warm-up samples */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->output[channel][u] = i32;
+ }
+
+ /* read entropy coding method info */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ subframe_header.entropy_coding_method.type = u32;
+ switch(subframe_header.entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ subframe_header.entropy_coding_method.data.partitioned_rice.order = u32;
+ break;
+ default:
+ decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+ return false;
+ }
+
+ /* read residual */
+ switch(subframe_header.entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!stream_decoder_read_residual_partitioned_rice_(decoder, order, subframe_header.entropy_coding_method.data.partitioned_rice.order))
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+
+ /* decode the subframe */
+ FLAC__fixed_restore_signal(decoder->guts->residual, decoder->guts->frame_header.blocksize-order, order, decoder->guts->output[channel]+order);
+
+ return true;
+}
+
+bool stream_decoder_read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, const unsigned order)
+{
+ FLAC__SubframeHeader_LPC subframe_header;
+ int32 i32;
+ uint32 u32;
+ unsigned u;
+
+ subframe_header.order = order;
+
+ /* read warm-up samples */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->output[channel][u] = i32;
+ }
+
+ /* read qlp coeff precision */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__SUBFRAME_HEADER_LPC_QLP_COEFF_PRECISION_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(u32 == 15) {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ subframe_header.qlp_coeff_precision = u32+1;
+
+ /* read qlp shift */
+ if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, FLAC__SUBFRAME_HEADER_LPC_QLP_SHIFT_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ subframe_header.quantization_level = i32;
+
+ /* read quantized lp coefficiencts */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &i32, subframe_header.qlp_coeff_precision, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ subframe_header.qlp_coeff[u] = i32;
+ }
+
+ /* read entropy coding method info */
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ subframe_header.entropy_coding_method.type = u32;
+ switch(subframe_header.entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ subframe_header.entropy_coding_method.data.partitioned_rice.order = u32;
+ break;
+ default:
+ decoder->state = FLAC__STREAM_DECODER_UNPARSEABLE_STREAM;
+ return false;
+ }
+
+ /* read residual */
+ switch(subframe_header.entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!stream_decoder_read_residual_partitioned_rice_(decoder, order, subframe_header.entropy_coding_method.data.partitioned_rice.order))
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+
+ /* decode the subframe */
+ FLAC__lpc_restore_signal(decoder->guts->residual, decoder->guts->frame_header.blocksize-order, subframe_header.qlp_coeff, order, subframe_header.quantization_level, decoder->guts->output[channel]+order);
+
+ return true;
+}
+
+bool stream_decoder_read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel)
+{
+ int32 x;
+ unsigned i;
+
+ for(i = 0; i < decoder->guts->frame_header.blocksize; i++) {
+ if(!FLAC__bitbuffer_read_raw_int32(&decoder->guts->input, &x, decoder->guts->frame_header.bits_per_sample, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->output[channel][i] = x;
+ }
+
+ return true;
+}
+
+bool stream_decoder_read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order)
+{
+ uint32 rice_parameter;
+ int i;
+ unsigned partition, sample, u;
+ const unsigned partitions = 1u << partition_order;
+ const unsigned partition_samples = partition_order > 0? decoder->guts->frame_header.blocksize >> partition_order : decoder->guts->frame_header.blocksize - predictor_order;
+
+ sample = 0;
+ for(partition = 0; partition < partitions; partition++) {
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+ if(!FLAC__bitbuffer_read_rice_signed(&decoder->guts->input, &i, rice_parameter, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ decoder->guts->residual[sample] = i;
+ }
+ }
+
+ return true;
+}
+
+bool stream_decoder_read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+ if(decoder->guts->input.consumed_bits != 0) {
+ uint32 zero;
+ if(!FLAC__bitbuffer_read_raw_uint32(&decoder->guts->input, &zero, 8-decoder->guts->input.consumed_bits, read_callback_, decoder))
+ return false; /* the read_callback_ sets the state for us */
+ if(zero != 0) {
+ decoder->guts->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_LOST_SYNC, decoder->guts->client_data);
+ decoder->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ }
+ }
+ return true;
+}
+
+bool read_callback_(byte buffer[], unsigned *bytes, void *client_data)
+{
+ FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+ FLAC__StreamDecoderReadStatus status;
+ status = decoder->guts->read_callback(decoder, buffer, bytes, decoder->guts->client_data);
+ if(status == FLAC__STREAM_DECODER_READ_END_OF_STREAM)
+ decoder->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ else if(status == FLAC__STREAM_DECODER_READ_ABORT)
+ decoder->state = FLAC__STREAM_DECODER_ABORTED;
+ return status == FLAC__STREAM_DECODER_READ_CONTINUE;
+}
diff --git a/src/plugin_winamp2/Makefile.vc b/src/plugin_winamp2/Makefile.vc
new file mode 100644
index 0000000..38a99ee
--- /dev/null
+++ b/src/plugin_winamp2/Makefile.vc
@@ -0,0 +1,23 @@
+!include <win32.mak>
+
+!IFNDEF NODEBUG
+.c.obj:
+ $(cc) /GX $(cdebug) $(cflags) $(cvarsdll) /I "..\..\include" /I ".\include" -DSTRICT -YX /Od /D "_DEBUG" $<
+!else
+.c.obj:
+ $(cc) $(cdebug) $(cflags) $(cvarsdll) /I "..\..\include" /I ".\include" -DSTRICT -YX -DNODEBUG $<
+!endif
+
+C_FILES= \
+ in_flac.c
+
+OBJS= $(C_FILES:.c=.obj)
+
+all: in_flac.dll
+
+in_flac.dll: $(OBJS)
+ link.exe /dll /libpath:"..\..\obj\lib" -out:../../obj/bin/$*.dll $(OBJS) libFLAC.lib user32.lib kernel32.lib
+
+clean:
+ -del *.obj *.pch
+ -del ..\..\obj\bin\in_flac.*
diff --git a/src/plugin_winamp2/in2.h b/src/plugin_winamp2/in2.h
new file mode 100644
index 0000000..dcac5ba
--- /dev/null
+++ b/src/plugin_winamp2/in2.h
@@ -0,0 +1,104 @@
+/* Standard Winamp input-plugin header
+ */
+
+#include "out.h"
+
+// note: exported symbol is now winampGetInModule2.
+
+#define IN_VER 0x100
+
+typedef struct
+{
+ int version; // module type (IN_VER)
+ char *description; // description of module, with version string
+
+ HWND hMainWindow; // winamp's main window (filled in by winamp)
+ HINSTANCE hDllInstance; // DLL instance handle (Also filled in by winamp)
+
+ char *FileExtensions; // "mp3\0Layer 3 MPEG\0mp2\0Layer 2 MPEG\0mpg\0Layer 1 MPEG\0"
+ // May be altered from Config, so the user can select what they want
+
+ int is_seekable; // is this stream seekable?
+ int UsesOutputPlug; // does this plug-in use the output plug-ins? (musn't ever change, ever :)
+
+ void (*Config)(HWND hwndParent); // configuration dialog
+ void (*About)(HWND hwndParent); // about dialog
+
+ void (*Init)(); // called at program init
+ void (*Quit)(); // called at program quit
+
+ void (*GetFileInfo)(char *file, char *title, int *length_in_ms); // if file == NULL, current playing is used
+ int (*InfoBox)(char *file, HWND hwndParent);
+
+ int (*IsOurFile)(char *fn); // called before extension checks, to allow detection of mms://, etc
+ // playback stuff
+ int (*Play)(char *fn); // return zero on success, -1 on file-not-found, some other value on other (stopping winamp) error
+ void (*Pause)(); // pause stream
+ void (*UnPause)(); // unpause stream
+ int (*IsPaused)(); // ispaused? return 1 if paused, 0 if not
+ void (*Stop)(); // stop (unload) stream
+
+ // time stuff
+ int (*GetLength)(); // get length in ms
+ int (*GetOutputTime)(); // returns current output time in ms. (usually returns outMod->GetOutputTime()
+ void (*SetOutputTime)(int time_in_ms); // seeks to point in stream (in ms). Usually you signal yoru thread to seek, which seeks and calls outMod->Flush()..
+
+ // volume stuff
+ void (*SetVolume)(int volume); // from 0 to 255.. usually just call outMod->SetVolume
+ void (*SetPan)(int pan); // from -127 to 127.. usually just call outMod->SetPan
+
+ // in-window builtin vis stuff
+
+ void (*SAVSAInit)(int maxlatency_in_ms, int srate); // call once in Play(). maxlatency_in_ms should be the value returned from outMod->Open()
+ // call after opening audio device with max latency in ms and samplerate
+ void (*SAVSADeInit)(); // call in Stop()
+
+
+ // simple vis supplying mode
+ void (*SAAddPCMData)(void *PCMData, int nch, int bps, int timestamp);
+ // sets the spec data directly from PCM data
+ // quick and easy way to get vis working :)
+ // needs at least 576 samples :)
+
+ // advanced vis supplying mode, only use if you're cool. Use SAAddPCMData for most stuff.
+ int (*SAGetMode)(); // gets csa (the current type (4=ws,2=osc,1=spec))
+ // use when calling SAAdd()
+ void (*SAAdd)(void *data, int timestamp, int csa); // sets the spec data, filled in by winamp
+
+
+ // vis stuff (plug-in)
+ // simple vis supplying mode
+ void (*VSAAddPCMData)(void *PCMData, int nch, int bps, int timestamp); // sets the vis data directly from PCM data
+ // quick and easy way to get vis working :)
+ // needs at least 576 samples :)
+
+ // advanced vis supplying mode, only use if you're cool. Use VSAAddPCMData for most stuff.
+ int (*VSAGetMode)(int *specNch, int *waveNch); // use to figure out what to give to VSAAdd
+ void (*VSAAdd)(void *data, int timestamp); // filled in by winamp, called by plug-in
+
+
+ // call this in Play() to tell the vis plug-ins the current output params.
+ void (*VSASetInfo)(int nch, int srate);
+
+
+ // dsp plug-in processing:
+ // (filled in by winamp, called by input plug)
+
+ // returns 1 if active (which means that the number of samples returned by dsp_dosamples
+ // could be greater than went in.. Use it to estimate if you'll have enough room in the
+ // output buffer
+ int (*dsp_isactive)();
+
+ // returns number of samples to output. This can be as much as twice numsamples.
+ // be sure to allocate enough buffer for samples, then.
+ int (*dsp_dosamples)(short int *samples, int numsamples, int bps, int nch, int srate);
+
+
+ // eq stuff
+ void (*EQSet)(int on, char data[10], int preamp); // 0-64 each, 31 is +0, 0 is +12, 63 is -12. Do nothing to ignore.
+
+ // info setting (filled in by winamp)
+ void (*SetInfo)(int bitrate, int srate, int stereo, int synched); // if -1, changes ignored? :)
+
+ Out_Module *outMod; // filled in by winamp, optionally used :)
+} In_Module;
diff --git a/src/plugin_winamp2/in_flac.c b/src/plugin_winamp2/in_flac.c
new file mode 100644
index 0000000..fb021c8
--- /dev/null
+++ b/src/plugin_winamp2/in_flac.c
@@ -0,0 +1,425 @@
+/* in_flac - Winamp FLAC input plugin
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <windows.h>
+#include <mmreg.h>
+#include <msacm.h>
+#include <math.h>
+#include <assert.h>
+
+#include "in2.h"
+#include "FLAC/all.h"
+
+BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+{
+ return TRUE;
+}
+
+/* post this to the main window at end of file (after playback as stopped) */
+#define WM_WA_MPEG_EOF WM_USER+2
+
+typedef struct {
+ bool abort_flag;
+ unsigned total_samples;
+ unsigned bits_per_sample;
+ unsigned channels;
+ unsigned sample_rate;
+ unsigned length_in_ms;
+} stream_info_struct;
+
+static bool stream_init(const char *infile);
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
+static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+In_Module mod; /* the output module (declared near the bottom of this file) */
+char lastfn[MAX_PATH]; /* currently playing file (used for getting info on the current file) */
+int decode_pos_ms; /* current decoding position, in milliseconds */
+int paused; /* are we paused? */
+int seek_needed; /* if != -1, it is the point that the decode thread should seek to, in ms. */
+int16 reservoir[FLAC__MAX_BLOCK_SIZE * 2]; /* 2 for max channels */
+char sample_buffer[576 * 2 * (16/8) * 2]; /* 2 for max channels, (16/8) for max bytes per sample, and 2 for who knows what */
+unsigned samples_in_reservoir;
+static stream_info_struct stream_info;
+static FLAC__FileDecoder *decoder;
+
+int killDecodeThread=0; /* the kill switch for the decode thread */
+HANDLE thread_handle=INVALID_HANDLE_VALUE; /* the handle to the decode thread */
+
+DWORD WINAPI __stdcall DecodeThread(void *b); /* the decode thread procedure */
+
+void config(HWND hwndParent)
+{
+ MessageBox(hwndParent, "No configuration.", "Configuration", MB_OK);
+ /* if we had a configuration we'd want to write it here :) */
+}
+void about(HWND hwndParent)
+{
+ MessageBox(hwndParent,"Winamp FLAC Plugin v0.2, by Josh Coalson\nSee http://flac.sourceforge.net/","About FLAC Plugin",MB_OK);
+}
+
+void init()
+{
+ decoder = FLAC__file_decoder_get_new_instance();
+}
+
+void quit()
+{
+ if(decoder)
+ FLAC__file_decoder_free_instance(decoder);
+}
+
+int isourfile(char *fn) { return 0; }
+/* used for detecting URL streams.. unused here. strncmp(fn,"http://",7) to detect HTTP streams, etc */
+
+int play(char *fn)
+{
+ int maxlatency;
+ int thread_id;
+ HANDLE input_file=INVALID_HANDLE_VALUE;
+
+ if(0 == decoder) {
+ return 1;
+ }
+
+ input_file = CreateFile(fn,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
+ if (input_file == INVALID_HANDLE_VALUE) {
+ return 1;
+ }
+ CloseHandle(input_file);
+
+ if(!stream_init(fn)) {
+ return 1;
+ }
+
+ strcpy(lastfn,fn);
+ paused=0;
+ decode_pos_ms=0;
+ seek_needed=-1;
+ samples_in_reservoir = 0;
+
+ maxlatency = mod.outMod->Open(stream_info.sample_rate, stream_info.channels, stream_info.bits_per_sample, -1,-1);
+ if (maxlatency < 0) { /* error opening device */
+ return 1;
+ }
+
+ /* dividing by 1000 for the first parameter of setinfo makes it */
+ /* display 'H'... for hundred.. i.e. 14H Kbps. */
+ mod.SetInfo((stream_info.sample_rate*stream_info.bits_per_sample*stream_info.channels)/1000,stream_info.sample_rate/1000,stream_info.channels,1);
+
+ /* initialize vis stuff */
+ mod.SAVSAInit(maxlatency,stream_info.sample_rate);
+ mod.VSASetInfo(stream_info.sample_rate,stream_info.channels);
+
+ mod.outMod->SetVolume(-666); /* set the output plug-ins default volume */
+
+ killDecodeThread=0;
+ thread_handle = (HANDLE) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) DecodeThread,(void *) &killDecodeThread,0,&thread_id);
+
+ return 0;
+}
+
+void pause()
+{
+ paused=1;
+ mod.outMod->Pause(1);
+}
+
+void unpause()
+{
+ paused=0;
+ mod.outMod->Pause(0);
+}
+int ispaused()
+{
+ return paused;
+}
+
+void stop()
+{
+ if (thread_handle != INVALID_HANDLE_VALUE) {
+ killDecodeThread=1;
+ if (WaitForSingleObject(thread_handle,INFINITE) == WAIT_TIMEOUT) {
+ MessageBox(mod.hMainWindow,"error asking thread to die!\n","error killing decode thread",0);
+ TerminateThread(thread_handle,0);
+ }
+ CloseHandle(thread_handle);
+ thread_handle = INVALID_HANDLE_VALUE;
+ }
+ if(decoder) {
+ if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder);
+ }
+
+ mod.outMod->Close();
+
+ mod.SAVSADeInit();
+}
+
+int getlength()
+{
+ return (int)stream_info.length_in_ms;
+}
+
+int getoutputtime()
+{
+ return decode_pos_ms+(mod.outMod->GetOutputTime()-mod.outMod->GetWrittenTime());
+}
+
+void setoutputtime(int time_in_ms)
+{
+ seek_needed=time_in_ms;
+}
+
+void setvolume(int volume) { mod.outMod->SetVolume(volume); }
+void setpan(int pan) { mod.outMod->SetPan(pan); }
+
+int infoDlg(char *fn, HWND hwnd)
+{
+ /* TODO: implement info dialog. */
+ return 0;
+}
+
+void getfileinfo(char *filename, char *title, int *length_in_ms)
+{
+ if (!filename || !*filename) { /* currently playing file */
+ if (length_in_ms)
+ *length_in_ms=getlength();
+ if (title) {
+ char *p=lastfn+strlen(lastfn);
+ while (*p != '\\' && p >= lastfn) p--;
+ strcpy(title,++p);
+ }
+ }
+ else { /* some other file */
+ if (length_in_ms) {
+ FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_get_new_instance();
+ stream_info_struct tmp_stream_info;
+ tmp_stream_info.abort_flag = false;
+ if(FLAC__file_decoder_init(tmp_decoder, filename, write_callback, metadata_callback, error_callback, &tmp_stream_info) != FLAC__FILE_DECODER_OK)
+ return;
+ if(!FLAC__file_decoder_process_metadata(tmp_decoder))
+ return;
+
+ *length_in_ms = (int)tmp_stream_info.length_in_ms;
+
+ if(tmp_decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(tmp_decoder);
+ FLAC__file_decoder_free_instance(tmp_decoder);
+ }
+ if (title) {
+ char *p=filename+strlen(filename);
+ while (*p != '\\' && p >= filename) p--;
+ strcpy(title,++p);
+ }
+ }
+}
+
+void eq_set(int on, char data[10], int preamp)
+{
+}
+
+DWORD WINAPI __stdcall DecodeThread(void *b)
+{
+ int done=0;
+
+ while (! *((int *)b) ) {
+ unsigned channels = stream_info.channels;
+ unsigned bits_per_sample = stream_info.bits_per_sample;
+ unsigned bytes_per_sample = (bits_per_sample+7)/8;
+ unsigned sample_rate = stream_info.sample_rate;
+ if (seek_needed != -1) {
+ const double distance = (double)seek_needed / (double)getlength();
+ unsigned target_sample = (unsigned)(distance * (double)stream_info.total_samples);
+ if(FLAC__file_decoder_seek_absolute(decoder, (uint64)target_sample)) {
+ decode_pos_ms = (int)(distance * (double)getlength());
+ seek_needed=-1;
+ done=0;
+ mod.outMod->Flush(decode_pos_ms);
+ }
+ }
+ if (done) {
+ if (!mod.outMod->IsPlaying()) {
+ PostMessage(mod.hMainWindow,WM_WA_MPEG_EOF,0,0);
+ return 0;
+ }
+ Sleep(10);
+ }
+ else if (mod.outMod->CanWrite() >= ((int)(576*channels*bytes_per_sample) << (mod.dsp_isactive()?1:0))) {
+ while(samples_in_reservoir < 576) {
+ if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE) {
+ done = 1;
+ break;
+ }
+ else if(!FLAC__file_decoder_process_one_frame(decoder))
+ break;
+ }
+
+ if (samples_in_reservoir == 0) {
+ done=1;
+ }
+ else {
+ unsigned i, n = min(samples_in_reservoir, 576), delta;
+ int l;
+ signed short *ssbuffer = (signed short *)sample_buffer;
+
+ for(i = 0; i < n*channels; i++)
+ ssbuffer[i] = reservoir[i];
+ delta = i;
+ for( ; i < samples_in_reservoir*channels; i++)
+ reservoir[i-delta] = reservoir[i];
+ samples_in_reservoir -= n;
+ l = n * channels * bytes_per_sample;
+
+ mod.SAAddPCMData((char *)sample_buffer,channels,bits_per_sample,decode_pos_ms);
+ mod.VSAAddPCMData((char *)sample_buffer,channels,bits_per_sample,decode_pos_ms);
+ decode_pos_ms+=(576*1000)/sample_rate;
+ if (mod.dsp_isactive())
+ l=mod.dsp_dosamples((short *)sample_buffer,n/channels/bytes_per_sample,bits_per_sample,channels,sample_rate) * (channels*bytes_per_sample);
+ mod.outMod->Write(sample_buffer,l);
+ }
+ }
+ else Sleep(20);
+ }
+ return 0;
+}
+
+
+
+In_Module mod =
+{
+ IN_VER,
+ "Reference FLAC Player v0.0"
+#ifdef __alpha
+ "(AXP)"
+#else
+ "(x86)"
+#endif
+ ,
+ 0, /* hMainWindow */
+ 0, /* hDllInstance */
+ "FLAC\0FLAC Audio File (*.FLAC)\0"
+ ,
+ 1, /* is_seekable */
+ 1, /* uses output */
+ config,
+ about,
+ init,
+ quit,
+ getfileinfo,
+ infoDlg,
+ isourfile,
+ play,
+ pause,
+ unpause,
+ ispaused,
+ stop,
+
+ getlength,
+ getoutputtime,
+ setoutputtime,
+
+ setvolume,
+ setpan,
+
+ 0,0,0,0,0,0,0,0,0, /* vis stuff */
+
+
+ 0,0, /* dsp */
+
+ eq_set,
+
+ NULL, /* setinfo */
+
+ 0 /* out_mod */
+
+};
+
+__declspec( dllexport ) In_Module * winampGetInModule2()
+{
+ return &mod;
+}
+
+
+/***********************************************************************
+ * local routines
+ **********************************************************************/
+bool stream_init(const char *infile)
+{
+ if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, &stream_info) != FLAC__FILE_DECODER_OK) {
+ MessageBox(mod.hMainWindow,"ERROR initializing decoder, state = %d\n","ERROR initializing decoder",0);
+ return false;
+ }
+
+ stream_info.abort_flag = false;
+ if(!FLAC__file_decoder_process_metadata(decoder)) {
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
+{
+ stream_info_struct *stream_info = (stream_info_struct *)client_data;
+ unsigned bps = stream_info->bits_per_sample, channels = stream_info->channels;
+ unsigned wide_samples = header->blocksize, wide_sample, sample, channel, offset;
+
+ (void)decoder;
+
+ if(stream_info->abort_flag)
+ return FLAC__STREAM_DECODER_WRITE_ABORT;
+
+ offset = samples_in_reservoir * channels;
+
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ reservoir[offset+sample] = (int16)buffer[channel][wide_sample];
+
+ samples_in_reservoir += wide_samples;
+
+ return FLAC__STREAM_DECODER_WRITE_CONTINUE;
+}
+
+void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+ stream_info_struct *stream_info = (stream_info_struct *)client_data;
+ (void)decoder;
+ if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
+ assert(metadata->data.encoding.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
+ stream_info->total_samples = (unsigned)(metadata->data.encoding.total_samples&0xffffffff);
+ stream_info->bits_per_sample = metadata->data.encoding.bits_per_sample;
+ stream_info->channels = metadata->data.encoding.channels;
+ stream_info->sample_rate = metadata->data.encoding.sample_rate;
+
+ if(stream_info->bits_per_sample != 16) {
+ MessageBox(mod.hMainWindow,"ERROR: plugin can only handle 16-bit samples\n","ERROR: plugin can only handle 16-bit samples",0);
+ stream_info->abort_flag = true;
+ return;
+ }
+ stream_info->length_in_ms = stream_info->total_samples * 10 / (stream_info->sample_rate / 100);
+ }
+}
+
+void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ stream_info_struct *stream_info = (stream_info_struct *)client_data;
+ (void)decoder;
+ if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC)
+ stream_info->abort_flag = true;
+}
diff --git a/src/plugin_winamp2/out.h b/src/plugin_winamp2/out.h
new file mode 100644
index 0000000..f82708a
--- /dev/null
+++ b/src/plugin_winamp2/out.h
@@ -0,0 +1,55 @@
+/* Standard Winamp output-plugin header
+ */
+
+#define OUT_VER 0x10
+
+typedef struct
+{
+ int version; // module version (OUT_VER)
+ char *description; // description of module, with version string
+ int id; // module id. each input module gets its own. non-nullsoft modules should
+ // be >= 65536.
+
+ HWND hMainWindow; // winamp's main window (filled in by winamp)
+ HINSTANCE hDllInstance; // DLL instance handle (filled in by winamp)
+
+ void (*Config)(HWND hwndParent); // configuration dialog
+ void (*About)(HWND hwndParent); // about dialog
+
+ void (*Init)(); // called when loaded
+ void (*Quit)(); // called when unloaded
+
+ int (*Open)(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms);
+ // returns >=0 on success, <0 on failure
+ // NOTENOTENOTE: bufferlenms and prebufferms are ignored in most if not all output plug-ins.
+ // ... so don't expect the max latency returned to be what you asked for.
+ // returns max latency in ms (0 for diskwriters, etc)
+ // bufferlenms and prebufferms must be in ms. 0 to use defaults.
+ // prebufferms must be <= bufferlenms
+
+ void (*Close)(); // close the ol' output device.
+
+ int (*Write)(char *buf, int len);
+ // 0 on success. Len == bytes to write (<= 8192 always). buf is straight audio data.
+ // 1 returns not able to write (yet). Non-blocking, always.
+
+ int (*CanWrite)(); // returns number of bytes possible to write at a given time.
+ // Never will decrease unless you call Write (or Close, heh)
+
+ int (*IsPlaying)(); // non0 if output is still going or if data in buffers waiting to be
+ // written (i.e. closing while IsPlaying() returns 1 would truncate the song
+
+ int (*Pause)(int pause); // returns previous pause state
+
+ void (*SetVolume)(int volume); // volume is 0-255
+ void (*SetPan)(int pan); // pan is -128 to 128
+
+ void (*Flush)(int t); // flushes buffers and restarts output at time t (in ms)
+ // (used for seeking)
+
+ int (*GetOutputTime)(); // returns played time in MS
+ int (*GetWrittenTime)(); // returns time written in MS (used for synching up vis stuff)
+
+} Out_Module;
+
+
diff --git a/src/plugin_xmms/Makefile b/src/plugin_xmms/Makefile
new file mode 100644
index 0000000..a50821c
--- /dev/null
+++ b/src/plugin_xmms/Makefile
@@ -0,0 +1,14 @@
+#
+# GNU makefile
+#
+
+LIB_NAME = libxmms-flac
+INCLUDES = $(shell xmms-config --cflags) -I./include -I../../include
+LIBS = ../../obj/lib/libFLAC.a
+
+OBJS = \
+ plugin.o
+
+include ../../build/lib.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/plugin_xmms/plugin.c b/src/plugin_xmms/plugin.c
new file mode 100644
index 0000000..43b4ac5
--- /dev/null
+++ b/src/plugin_xmms/plugin.c
@@ -0,0 +1,393 @@
+/* libxmms-flac - XMMS FLAC input plugin
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <glib.h>
+
+#include "xmms/plugin.h"
+#include "xmms/util.h"
+#include "FLAC/all.h"
+
+typedef struct {
+ byte raw[128];
+ char title[31];
+ char artist[31];
+ char album[31];
+ char comment[31];
+ unsigned year;
+ unsigned track; /* may be 0 if v1 (not v1.1) tag */
+ unsigned genre;
+ char description[1024]; /* the formatted description passed to xmms */
+} id3v1_struct;
+
+typedef struct {
+ bool abort_flag;
+ bool is_playing;
+ bool eof;
+ unsigned total_samples;
+ unsigned bits_per_sample;
+ unsigned channels;
+ unsigned sample_rate;
+ unsigned length_in_msec;
+ int seek_to_in_sec;
+} file_info_struct;
+
+static void FLAC_XMMS__init();
+static int FLAC_XMMS__is_our_file(char *filename);
+static void FLAC_XMMS__play_file(char *filename);
+static void FLAC_XMMS__stop();
+static void FLAC_XMMS__pause(short p);
+static void FLAC_XMMS__seek(int time);
+static int FLAC_XMMS__get_time();
+static void FLAC_XMMS__cleanup();
+static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length);
+
+static void *play_loop_(void *arg);
+static bool decoder_init_(const char *filename);
+static bool get_id3v1_tag_(const char *filename, id3v1_struct *tag);
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
+static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+InputPlugin flac_ip =
+{
+ NULL,
+ NULL,
+ "FLAC Player v" FLAC__VERSION_STRING,
+ FLAC_XMMS__init,
+ NULL,
+ NULL,
+ FLAC_XMMS__is_our_file,
+ NULL,
+ FLAC_XMMS__play_file,
+ FLAC_XMMS__stop,
+ FLAC_XMMS__pause,
+ FLAC_XMMS__seek,
+ NULL,
+ FLAC_XMMS__get_time,
+ NULL,
+ NULL,
+ FLAC_XMMS__cleanup,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ FLAC_XMMS__get_song_info,
+ NULL, /* file_info_box */
+ NULL
+};
+
+static int16 reservoir_[FLAC__MAX_BLOCK_SIZE * 2]; /* 2 for max channels */
+static unsigned reservoir_samples_;
+static FLAC__FileDecoder *decoder_;
+static file_info_struct file_info_;
+static pthread_t decode_thread_;
+static bool audio_error_ = false;
+
+InputPlugin *get_iplugin_info()
+{
+ flac_ip.description = g_strdup_printf("FLAC Player v%u.%u", FLAC__MAJOR_VERSION, FLAC__MINOR_VERSION);
+ return &flac_ip;
+}
+
+void FLAC_XMMS__init()
+{
+ decoder_ = FLAC__file_decoder_get_new_instance();
+}
+
+int FLAC_XMMS__is_our_file(char *filename)
+{
+ char *ext;
+
+ ext = strrchr(filename, '.');
+ if (ext)
+ if (!strcasecmp(ext, ".flac") || !strcasecmp(ext, ".fla"))
+ return 1;
+ return 0;
+}
+
+void FLAC_XMMS__play_file(char *filename)
+{
+ FILE *f;
+ id3v1_struct tag;
+
+ if(0 == (f = fopen(filename, "r")))
+ return;
+ fclose(f);
+
+ if(!decoder_init_(filename))
+ return;
+
+ reservoir_samples_ = 0;
+ audio_error_ = false;
+ file_info_.is_playing = true;
+ file_info_.eof = false;
+
+ if (flac_ip.output->open_audio(FMT_S16_NE, file_info_.sample_rate, file_info_.channels) == 0) {
+ audio_error_ = true;
+ if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder_);
+ return;
+ }
+
+ (void)get_id3v1_tag_(filename, &tag);
+ flac_ip.set_info(tag.description, file_info_.length_in_msec, file_info_.sample_rate * file_info_.channels * file_info_.bits_per_sample, file_info_.sample_rate, file_info_.channels);
+
+ file_info_.seek_to_in_sec = -1;
+ pthread_create(&decode_thread_, NULL, play_loop_, NULL);
+}
+
+void FLAC_XMMS__stop()
+{
+ if(file_info_.is_playing) {
+ file_info_.is_playing = false;
+ pthread_join(decode_thread_, NULL);
+ flac_ip.output->close_audio();
+ if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder_);
+ }
+}
+
+void FLAC_XMMS__pause(short p)
+{
+ flac_ip.output->pause(p);
+}
+
+void FLAC_XMMS__seek(int time)
+{
+ file_info_.seek_to_in_sec = time;
+ file_info_.eof = false;
+
+ while(file_info_.seek_to_in_sec != -1)
+ xmms_usleep(10000);
+}
+
+int FLAC_XMMS__get_time()
+{
+ if(audio_error_)
+ return -2;
+ if(!file_info_.is_playing || (file_info_.eof && !flac_ip.output->buffer_playing()))
+ return -1;
+ else
+ return flac_ip.output->output_time();
+}
+
+void FLAC_XMMS__cleanup()
+{
+ if(decoder_)
+ FLAC__file_decoder_free_instance(decoder_);
+}
+
+void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec)
+{
+ id3v1_struct tag;
+
+ if(title) {
+ (void)get_id3v1_tag_(filename, &tag);
+ *title = g_malloc(strlen(tag.description)+1);
+ strcpy(*title, tag.description);
+ }
+ if(length_in_msec) {
+ FLAC__FileDecoder *tmp_decoder = FLAC__file_decoder_get_new_instance();
+ file_info_struct tmp_file_info;
+ if(0 == tmp_decoder) {
+ *length_in_msec = -1;
+ return;
+ }
+ tmp_file_info.abort_flag = false;
+ if(FLAC__file_decoder_init(tmp_decoder, filename, write_callback_, metadata_callback_, error_callback_, &tmp_file_info) != FLAC__FILE_DECODER_OK) {
+ *length_in_msec = -1;
+ return;
+ }
+ if(!FLAC__file_decoder_process_metadata(tmp_decoder)) {
+ *length_in_msec = -1;
+ return;
+ }
+
+ *length_in_msec = (int)tmp_file_info.length_in_msec;
+
+ if(tmp_decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(tmp_decoder);
+ FLAC__file_decoder_free_instance(tmp_decoder);
+ }
+}
+
+/***********************************************************************
+ * local routines
+ **********************************************************************/
+
+void *play_loop_(void *arg)
+{
+
+ (void)arg;
+
+ while(file_info_.is_playing) {
+ if(!file_info_.eof) {
+ (void)FLAC__file_decoder_process_one_frame(decoder_);
+ if(reservoir_samples_ > 0) {
+ unsigned bytes = reservoir_samples_ * ((file_info_.bits_per_sample+7)/8) * file_info_.channels;
+ flac_ip.add_vis_pcm(flac_ip.output->written_time(), FMT_S16_NE, file_info_.channels, bytes, (char*)reservoir_);
+ while(flac_ip.output->buffer_free() < (int)bytes && file_info_.is_playing && file_info_.seek_to_in_sec == -1)
+ xmms_usleep(10000);
+ if(file_info_.is_playing && file_info_.seek_to_in_sec == -1)
+ flac_ip.output->write_audio((char*)reservoir_, bytes);
+ reservoir_samples_ = 0;
+ }
+ else {
+ file_info_.eof = true;
+ xmms_usleep(10000);
+ }
+ }
+ else
+ xmms_usleep(10000);
+ if (file_info_.seek_to_in_sec != -1) {
+ const double distance = (double)file_info_.seek_to_in_sec * 1000.0 / (double)file_info_.length_in_msec;
+ unsigned target_sample = (unsigned)(distance * (double)file_info_.total_samples);
+ if(FLAC__file_decoder_seek_absolute(decoder_, (uint64)target_sample)) {
+ flac_ip.output->flush(file_info_.seek_to_in_sec * 1000);
+ file_info_.seek_to_in_sec = -1;
+ file_info_.eof = false;
+ }
+ }
+
+ }
+ if(decoder_ && decoder_->state != FLAC__FILE_DECODER_UNINITIALIZED)
+ FLAC__file_decoder_finish(decoder_);
+
+ /* are these two calls necessary? */
+ flac_ip.output->buffer_free();
+ flac_ip.output->buffer_free();
+
+ pthread_exit(NULL);
+ return 0; /* to silence the compiler warning about not returning a value */
+}
+
+bool decoder_init_(const char *filename)
+{
+ if(decoder_ == 0)
+ return false;
+
+ if(FLAC__file_decoder_init(decoder_, filename, write_callback_, metadata_callback_, error_callback_, &file_info_) != FLAC__FILE_DECODER_OK)
+ return false;
+
+ file_info_.abort_flag = false;
+
+ if(!FLAC__file_decoder_process_metadata(decoder_))
+ return false;
+
+ return true;
+}
+
+bool get_id3v1_tag_(const char *filename, id3v1_struct *tag)
+{
+ const char *temp;
+ FILE *f = fopen(filename, "rb");
+ memset(tag, 0, sizeof(id3v1_struct));
+
+ /* set the description to the filename by default */
+ temp = strrchr(filename, '/');
+ if(!temp)
+ temp = filename;
+ else
+ temp++;
+ strcpy(tag->description, temp);
+ *strrchr(tag->description, '.') = '\0';
+
+ if(0 == f)
+ return false;
+ if(-1 == fseek(f, -128, SEEK_END)) {
+ fclose(f);
+ return false;
+ }
+ if(fread(tag->raw, 1, 128, f) < 128) {
+ fclose(f);
+ return false;
+ }
+ fclose(f);
+ if(strncmp(tag->raw, "TAG", 3))
+ return false;
+ else {
+ char year_str[5];
+
+ memcpy(tag->title, tag->raw+3, 30);
+ memcpy(tag->artist, tag->raw+33, 30);
+ memcpy(tag->album, tag->raw+63, 30);
+ memcpy(year_str, tag->raw+93, 4); year_str[4] = '\0'; tag->year = atoi(year_str);
+ memcpy(tag->comment, tag->raw+97, 30);
+ tag->genre = (unsigned)((byte)tag->raw[127]);
+ tag->track = (unsigned)((byte)tag->raw[126]);
+
+ sprintf(tag->description, "%s - %s", tag->artist, tag->title);
+
+ return true;
+ }
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
+{
+ file_info_struct *file_info = (file_info_struct *)client_data;
+ unsigned bps = file_info->bits_per_sample, channels = file_info->channels;
+ unsigned wide_samples = header->blocksize, wide_sample, sample, channel;
+
+ (void)decoder;
+
+ if(file_info->abort_flag)
+ return FLAC__STREAM_DECODER_WRITE_ABORT;
+
+ assert(bps == 16);
+
+ for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
+ for(channel = 0; channel < channels; channel++, sample++)
+ reservoir_[sample] = (int16)buffer[channel][wide_sample];
+
+ reservoir_samples_ = wide_samples;
+
+ return FLAC__STREAM_DECODER_WRITE_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+{
+ file_info_struct *file_info = (file_info_struct *)client_data;
+ (void)decoder;
+ if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
+ assert(metadata->data.encoding.total_samples < 0x100000000); /* this plugin can only handle < 4 gigasamples */
+ file_info->total_samples = (unsigned)(metadata->data.encoding.total_samples&0xffffffff);
+ file_info->bits_per_sample = metadata->data.encoding.bits_per_sample;
+ file_info->channels = metadata->data.encoding.channels;
+ file_info->sample_rate = metadata->data.encoding.sample_rate;
+
+ if(file_info->bits_per_sample != 16) {
+ file_info->abort_flag = true;
+ return;
+ }
+ file_info->length_in_msec = file_info->total_samples * 10 / (file_info->sample_rate / 100);
+ }
+}
+
+void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ file_info_struct *file_info = (file_info_struct *)client_data;
+ (void)decoder;
+ if(status != FLAC__STREAM_DECODER_ERROR_LOST_SYNC)
+ file_info->abort_flag = true;
+}
diff --git a/src/test_streams/Makefile b/src/test_streams/Makefile
new file mode 100644
index 0000000..e64e3d1
--- /dev/null
+++ b/src/test_streams/Makefile
@@ -0,0 +1,13 @@
+#
+# GNU makefile
+#
+
+PROGRAM_NAME = test_streams
+INCLUDES = -I./include -I../../include
+LIBS = -lm
+OBJS = \
+ main.o
+
+include ../../build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_streams/main.c b/src/test_streams/main.c
new file mode 100644
index 0000000..4216520
--- /dev/null
+++ b/src/test_streams/main.c
@@ -0,0 +1,258 @@
+/* test_streams - Simple test pattern generator
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "FLAC/ordinals.h"
+
+#ifdef _WIN32
+ static const char *mode = "wb";
+#else
+ static const char *mode = "w";
+#endif
+
+static bool is_big_endian_host;
+
+static void swap16(int16 *i)
+{
+ unsigned char *x = (unsigned char *)i, b;
+ if(!is_big_endian_host) {
+ b = x[0];
+ x[0] = x[1];
+ x[1] = b;
+ }
+}
+
+/* a mono one-sample 16bps stream */
+static bool generate_01()
+{
+ FILE *f;
+ int16 x = -32768;
+
+ if(0 == (f = fopen("test01.raw", mode)))
+ return false;
+
+ swap16(&x);
+ if(fwrite(&x, sizeof(x), 1, f) < 1)
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo one-sample 16bps stream */
+static bool generate_02()
+{
+ FILE *f;
+ int16 xl = -32768, xr = 32767;
+
+ if(0 == (f = fopen("test02.raw", mode)))
+ return false;
+
+ swap16(&xl);
+ swap16(&xr);
+
+ if(fwrite(&xl, sizeof(xl), 1, f) < 1)
+ goto foo;
+ if(fwrite(&xr, sizeof(xr), 1, f) < 1)
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono five-sample 16bps stream */
+static bool generate_03()
+{
+ FILE *f;
+ int16 x[] = { -25, 0, 25, 50, 100 };
+ unsigned i;
+
+ if(0 == (f = fopen("test03.raw", mode)))
+ return false;
+
+ for(i = 0; i < 5; i++)
+ swap16(x+i);
+
+ if(fwrite(&x, sizeof(int16), 5, f) < 5)
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo five-sample 16bps stream */
+static bool generate_04()
+{
+ FILE *f;
+ int16 x[] = { -25, 500, 0, 400, 25, 300, 50, 200, 100, 100 };
+ unsigned i;
+
+ if(0 == (f = fopen("test04.raw", mode)))
+ return false;
+
+ for(i = 0; i < 10; i++)
+ swap16(x+i);
+
+ if(fwrite(&x, sizeof(int16), 10, f) < 10)
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono full-scale deflection 8bps stream */
+static bool generate_fsd8(const char *fn, const int pattern[], unsigned reps)
+{
+ FILE *f;
+ unsigned rep, p;
+
+ assert(pattern != 0);
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(rep = 0; rep < reps; rep++) {
+ for(p = 0; pattern[p]; p++) {
+ signed char x = pattern[p] > 0? 127 : -128;
+ if(fwrite(&x, sizeof(x), 1, f) < 1)
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono full-scale deflection 16bps stream */
+static bool generate_fsd16(const char *fn, const int pattern[], unsigned reps)
+{
+ FILE *f;
+ unsigned rep, p;
+
+ assert(pattern != 0);
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(rep = 0; rep < reps; rep++) {
+ for(p = 0; pattern[p]; p++) {
+ int16 x = pattern[p] > 0? 32767 : -32768;
+ swap16(&x);
+ if(fwrite(&x, sizeof(x), 1, f) < 1)
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono sine-wave 16bps stream */
+static bool generate_sine16(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+ const signed short full_scale = 32767;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ int16 v = (int16)(val + 0.5);
+ swap16(&v);
+ if(fwrite(&v, sizeof(v), 1, f) < 1)
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+int main(int argc, char *argv[])
+{
+ uint32 test = 1;
+
+ int pattern01[] = { 1, -1, 0 };
+ int pattern02[] = { 1, 1, -1, 0 };
+ int pattern03[] = { 1, -1, -1, 0 };
+ int pattern04[] = { 1, -1, 1, -1, 0 };
+ int pattern05[] = { 1, -1, -1, 1, 0 };
+ int pattern06[] = { 1, -1, 1, 1, -1, 0 };
+ int pattern07[] = { 1, -1, -1, 1, -1, 0 };
+
+ (void)argc;
+ (void)argv;
+ is_big_endian_host = (*((byte*)(&test)))? false : true;
+
+ if(!generate_01()) return 1;
+ if(!generate_02()) return 1;
+ if(!generate_03()) return 1;
+ if(!generate_04()) return 1;
+
+ if(!generate_fsd8("fsd8-01.raw", pattern01, 100)) return 1;
+ if(!generate_fsd8("fsd8-02.raw", pattern02, 100)) return 1;
+ if(!generate_fsd8("fsd8-03.raw", pattern03, 100)) return 1;
+ if(!generate_fsd8("fsd8-04.raw", pattern04, 100)) return 1;
+ if(!generate_fsd8("fsd8-05.raw", pattern05, 100)) return 1;
+ if(!generate_fsd8("fsd8-06.raw", pattern06, 100)) return 1;
+ if(!generate_fsd8("fsd8-07.raw", pattern07, 100)) return 1;
+
+ if(!generate_fsd16("fsd16-01.raw", pattern01, 100)) return 1;
+ if(!generate_fsd16("fsd16-02.raw", pattern02, 100)) return 1;
+ if(!generate_fsd16("fsd16-03.raw", pattern03, 100)) return 1;
+ if(!generate_fsd16("fsd16-04.raw", pattern04, 100)) return 1;
+ if(!generate_fsd16("fsd16-05.raw", pattern05, 100)) return 1;
+ if(!generate_fsd16("fsd16-06.raw", pattern06, 100)) return 1;
+ if(!generate_fsd16("fsd16-07.raw", pattern07, 100)) return 1;
+
+ if(!generate_sine16("sine-01.raw", 44100.0, 80000, 441.0, 0.50, 441.0, 0.49)) return 1;
+ if(!generate_sine16("sine-02.raw", 44100.0, 80000, 441.0, 0.61, 661.5, 0.37)) return 1;
+ if(!generate_sine16("sine-03.raw", 44100.0, 80000, 441.0, 0.50, 882.0, 0.49)) return 1;
+ if(!generate_sine16("sine-04.raw", 44100.0, 80000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+ if(!generate_sine16("sine-05.raw", 44100.0, 50000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+ return 0;
+}
diff --git a/src/test_unit/Makefile b/src/test_unit/Makefile
new file mode 100644
index 0000000..b1892ea
--- /dev/null
+++ b/src/test_unit/Makefile
@@ -0,0 +1,14 @@
+#
+# GNU makefile
+#
+
+PROGRAM_NAME = test_unit
+INCLUDES = -I../libFLAC/include -I../../include
+LIBS = -lFLAC -lm
+OBJS = \
+ bitbuffer.o \
+ main.o
+
+include ../../build/exe.mk
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/test_unit/bitbuffer.c b/src/test_unit/bitbuffer.c
new file mode 100644
index 0000000..c5279ae
--- /dev/null
+++ b/src/test_unit/bitbuffer.c
@@ -0,0 +1,629 @@
+/* test_unit - Simple FLAC unit tester
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "private/bitbuffer.h" /* from the libFLAC private include area */
+
+static bool dummy_read_callback(byte buffer[], unsigned *bytes, void *client_data)
+{
+ (void)buffer, (void)bytes, (void)client_data;
+ return true;
+}
+
+int test_bitbuffer()
+{
+ FLAC__BitBuffer bb, bb_zero, bb_one, bbcopy;
+ bool ok;
+ unsigned i, j;
+ static byte test_pattern1[19] = { 0xaa, 0xf0, 0xaa, 0xbe, 0xaa, 0xaa, 0xaa, 0xa8, 0x30, 0x0a, 0xaa, 0xaa, 0xaa, 0xad, 0xea, 0xdb, 0xee, 0xfa, 0xce };
+
+ printf("testing init... OK\n");
+ FLAC__bitbuffer_init(&bb);
+ FLAC__bitbuffer_init(&bb_zero);
+ FLAC__bitbuffer_init(&bb_one);
+ FLAC__bitbuffer_init(&bbcopy);
+
+ printf("testing clear... ");
+ ok = FLAC__bitbuffer_clear(&bb) && FLAC__bitbuffer_clear(&bb_zero) && FLAC__bitbuffer_clear(&bb_one) && FLAC__bitbuffer_clear(&bbcopy);
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok)
+ return 1;
+
+ printf("setting up bb_one... ");
+ ok = FLAC__bitbuffer_write_raw_uint32(&bb_one, 1, 7) && FLAC__bitbuffer_read_raw_uint32(&bb_one, &i, 6, dummy_read_callback, 0);
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok)
+ return 1;
+ FLAC__bitbuffer_dump(&bb_one, stdout);
+
+ printf("capacity = %u\n", bb.capacity);
+
+ printf("testing zeroes, raw_uint32*... ");
+ ok =
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0x1, 1) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0x1, 2) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xa, 5) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xf0, 8) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0x2aa, 10) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xf, 4) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xaaaaaaaa, 32) &&
+ FLAC__bitbuffer_write_zeroes(&bb, 4) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0x3, 2) &&
+ FLAC__bitbuffer_write_zeroes(&bb, 8) &&
+ FLAC__bitbuffer_write_raw_uint64(&bb, 0xaaaaaaaadeadbeef, 64) &&
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xace, 12)
+ ;
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1));
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 0) {
+ printf("FAILED bit count %u != 0\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing raw_uint32 some more... ");
+ ok = FLAC__bitbuffer_write_raw_uint32(&bb, 0x3d, 6);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1));
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 6) {
+ printf("FAILED bit count %u != 6\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x3d) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing concatenate_aligned (bb_zero)... ");
+ ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_zero);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1));
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 6) {
+ printf("FAILED bit count %u != 6\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x3d) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing concatenate_aligned (bb_one)... ");
+ ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1));
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 7) {
+ printf("FAILED bit count %u != 7\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x7b) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing concatenate_aligned (bb_one again)... ");
+ (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 1, 1);
+ (void)FLAC__bitbuffer_read_raw_uint32(&bb_one, &i, 1, dummy_read_callback, 0);
+ ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)+1) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+1);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 0) {
+ printf("FAILED bit count %u != 0\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes-1] != 0xf7) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing concatenate_aligned (bb_four)... ");
+ (void)FLAC__bitbuffer_clear(&bb_one);
+ (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 8, 4);
+ ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)+1) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+1);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 4) {
+ printf("FAILED bit count %u != 4\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes] != 0x08) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing concatenate_aligned (bb_eight)... ");
+ (void)FLAC__bitbuffer_read_raw_uint32(&bb_one, &i, 4, dummy_read_callback, 0);
+ (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 0xaa, 8);
+ ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)+2) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+2);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 4) {
+ printf("FAILED bit count %u != 4\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes-1] != 0x8a || bb.buffer[bb.bytes] != 0x0a) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing concatenate_aligned (bb_seventeen)... ");
+ (void)FLAC__bitbuffer_write_raw_uint32(&bb_one, 0x155, 9);
+ ok = FLAC__bitbuffer_concatenate_aligned(&bb, &bb_one);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bytes != sizeof(test_pattern1)+4) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, sizeof(test_pattern1)+4);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.bits != 5) {
+ printf("FAILED bit count %u != 5\n", bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(bb.total_bits != 8*bb.bytes+bb.bits) {
+ printf("FAILED total_bits count %u != %u (%u:%u)\n", bb.total_bits, 8*bb.bytes+bb.bits, bb.bytes, bb.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, test_pattern1, sizeof(byte)*sizeof(test_pattern1)) != 0 || bb.buffer[bb.bytes-3] != 0x8a || bb.buffer[bb.bytes-2] != 0xaa || bb.buffer[bb.bytes-1] != 0xaa || bb.buffer[bb.bytes] != 0x15) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("OK\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+
+ printf("testing utf8_uint32(0x00000000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00000000);
+ ok = bb.total_bits == 8 && bb.buffer[0] == 0;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x0000007F)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x0000007F);
+ ok = bb.total_bits == 8 && bb.buffer[0] == 0x7F;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x00000080)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00000080);
+ ok = bb.total_bits == 16 && bb.buffer[0] == 0xC2 && bb.buffer[1] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x000007FF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x000007FF);
+ ok = bb.total_bits == 16 && bb.buffer[0] == 0xDF && bb.buffer[1] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x00000800)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00000800);
+ ok = bb.total_bits == 24 && bb.buffer[0] == 0xE0 && bb.buffer[1] == 0xA0 && bb.buffer[2] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x0000FFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x0000FFFF);
+ ok = bb.total_bits == 24 && bb.buffer[0] == 0xEF && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x00010000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00010000);
+ ok = bb.total_bits == 32 && bb.buffer[0] == 0xF0 && bb.buffer[1] == 0x90 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x001FFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x001FFFFF);
+ ok = bb.total_bits == 32 && bb.buffer[0] == 0xF7 && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x00200000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x00200000);
+ ok = bb.total_bits == 40 && bb.buffer[0] == 0xF8 && bb.buffer[1] == 0x88 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x03FFFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x03FFFFFF);
+ ok = bb.total_bits == 40 && bb.buffer[0] == 0xFB && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x04000000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x04000000);
+ ok = bb.total_bits == 48 && bb.buffer[0] == 0xFC && bb.buffer[1] == 0x84 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80 && bb.buffer[5] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint32(0x7FFFFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint32(&bb, 0x7FFFFFFF);
+ ok = bb.total_bits == 48 && bb.buffer[0] == 0xFD && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF && bb.buffer[5] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000000000000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000000000);
+ ok = bb.total_bits == 8 && bb.buffer[0] == 0;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x000000000000007F)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x000000000000007F);
+ ok = bb.total_bits == 8 && bb.buffer[0] == 0x7F;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000000000080)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000000080);
+ ok = bb.total_bits == 16 && bb.buffer[0] == 0xC2 && bb.buffer[1] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x00000000000007FF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x00000000000007FF);
+ ok = bb.total_bits == 16 && bb.buffer[0] == 0xDF && bb.buffer[1] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000000000800)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000000800);
+ ok = bb.total_bits == 24 && bb.buffer[0] == 0xE0 && bb.buffer[1] == 0xA0 && bb.buffer[2] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x000000000000FFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x000000000000FFFF);
+ ok = bb.total_bits == 24 && bb.buffer[0] == 0xEF && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000000010000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000010000);
+ ok = bb.total_bits == 32 && bb.buffer[0] == 0xF0 && bb.buffer[1] == 0x90 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x00000000001FFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x00000000001FFFFF);
+ ok = bb.total_bits == 32 && bb.buffer[0] == 0xF7 && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000000200000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000000200000);
+ ok = bb.total_bits == 40 && bb.buffer[0] == 0xF8 && bb.buffer[1] == 0x88 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000003FFFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000003FFFFFF);
+ ok = bb.total_bits == 40 && bb.buffer[0] == 0xFB && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000004000000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000004000000);
+ ok = bb.total_bits == 48 && bb.buffer[0] == 0xFC && bb.buffer[1] == 0x84 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80 && bb.buffer[5] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x000000007FFFFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x000000007FFFFFFF);
+ ok = bb.total_bits == 48 && bb.buffer[0] == 0xFD && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF && bb.buffer[5] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000080000000)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000080000000);
+ ok = bb.total_bits == 56 && bb.buffer[0] == 0xFE && bb.buffer[1] == 0x82 && bb.buffer[2] == 0x80 && bb.buffer[3] == 0x80 && bb.buffer[4] == 0x80 && bb.buffer[5] == 0x80 && bb.buffer[6] == 0x80;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing utf8_uint64(0x0000000FFFFFFFFF)... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_utf8_uint64(&bb, 0x0000000FFFFFFFFF);
+ ok = bb.total_bits == 56 && bb.buffer[0] == 0xFE && bb.buffer[1] == 0xBF && bb.buffer[2] == 0xBF && bb.buffer[3] == 0xBF && bb.buffer[4] == 0xBF && bb.buffer[5] == 0xBF && bb.buffer[6] == 0xBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+
+ printf("testing grow... ");
+ FLAC__bitbuffer_clear(&bb);
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xa, 4);
+ j = bb.capacity;
+ for(i = 0; i < j; i++)
+ FLAC__bitbuffer_write_raw_uint32(&bb, 0xaa, 8);
+ ok = bb.total_bits = i*8+4 && bb.buffer[0] == 0xaa && bb.buffer[i] == 0xa;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitbuffer_dump(&bb, stdout);
+ return 1;
+ }
+ printf("capacity = %u\n", bb.capacity);
+
+ printf("testing clone... ");
+ ok = FLAC__bitbuffer_clone(&bbcopy, &bb);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ FLAC__bitbuffer_dump(&bbcopy, stdout);
+ return 1;
+ }
+ if(bb.bytes != bbcopy.bytes) {
+ printf("FAILED byte count %u != %u\n", bb.bytes, bbcopy.bytes);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ FLAC__bitbuffer_dump(&bbcopy, stdout);
+ return 1;
+ }
+ if(bb.bits != bbcopy.bits) {
+ printf("FAILED bit count %u != %u\n", bb.bits, bbcopy.bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ FLAC__bitbuffer_dump(&bbcopy, stdout);
+ return 1;
+ }
+ if(bb.total_bits != bbcopy.total_bits) {
+ printf("FAILED total_bits count %u != %u\n", bb.total_bits, bbcopy.total_bits);
+ FLAC__bitbuffer_dump(&bb, stdout);
+ FLAC__bitbuffer_dump(&bbcopy, stdout);
+ return 1;
+ }
+ if(memcmp(bb.buffer, bbcopy.buffer, sizeof(byte)*bb.capacity) != 0) {
+ printf("FAILED pattern match\n");
+ FLAC__bitbuffer_dump(&bb, stdout);
+ FLAC__bitbuffer_dump(&bbcopy, stdout);
+ return 1;
+ }
+ printf("OK\n");
+
+ printf("testing free... OK\n");
+ FLAC__bitbuffer_free(&bb);
+ FLAC__bitbuffer_free(&bbcopy);
+
+ printf("\nPASSED!\n");
+ return 0;
+}
diff --git a/src/test_unit/bitbuffer.h b/src/test_unit/bitbuffer.h
new file mode 100644
index 0000000..5a6de2b
--- /dev/null
+++ b/src/test_unit/bitbuffer.h
@@ -0,0 +1,24 @@
+/* test_unit - Simple FLAC unit tester
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef FLAC__TEST_UNIT_BITBUFFER_H
+#define FLAC__TEST_UNIT_BITBUFFER_H
+
+int test_bitbuffer();
+
+#endif
diff --git a/src/test_unit/main.c b/src/test_unit/main.c
new file mode 100644
index 0000000..8d172bc
--- /dev/null
+++ b/src/test_unit/main.c
@@ -0,0 +1,26 @@
+/* test_unit - Simple FLAC unit tester
+ * Copyright (C) 2000 Josh Coalson
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "bitbuffer.h"
+
+int main(int argc, char *argv[])
+{
+ if(0 != test_bitbuffer())
+ return 1;
+ return 0;
+}