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;
+}